diff --git a/packages/hoppscotch-cli/package.json b/packages/hoppscotch-cli/package.json index 07d62a0d..fbc9bb1a 100644 --- a/packages/hoppscotch-cli/package.json +++ b/packages/hoppscotch-cli/package.json @@ -1,6 +1,6 @@ { "name": "@hoppscotch/cli", - "version": "0.23.0", + "version": "0.23.1", "description": "A CLI to run Hoppscotch test scripts in CI environments.", "homepage": "https://hoppscotch.io", "type": "module", @@ -50,7 +50,7 @@ "lodash-es": "4.17.21", "papaparse": "5.4.1", "qs": "6.13.0", - "verzod": "0.2.4", + "verzod": "0.3.0", "xmlbuilder2": "3.1.1", "zod": "3.25.32" }, diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts b/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts index c37efa48..050285d3 100644 --- a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts +++ b/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts @@ -89,6 +89,24 @@ describe("hopp test [options] ", { timeout: 100000 }, () => { expect(error).toBeNull(); }); }); + + describe("Mixed versions", () => { + test("Successfully processes children based on valid version ranges", async () => { + const args = `test ${getTestJsonFilePath("valid-mixed-versions-coll.json", "collection")}`; + const { error } = await runCLI(args); + + expect(error).toBeNull(); + }); + + test("Errors with the code `MALFORMED_COLLECTION` if the children fall out of valid version ranges", async () => { + const args = `test ${getTestJsonFilePath("invalid-mixed-versions-coll.json", "collection")}`; + + const { stderr } = await runCLI(args); + const out = getErrorCode(stderr); + + expect(out).toBe("MALFORMED_COLLECTION"); + }); + }); }); describe("Environments", () => { diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json new file mode 100644 index 00000000..6b53a4f0 --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json @@ -0,0 +1,48 @@ +{ + "v": 5, + "id": "cmbgcmyly10yhdjet63hiorps", + "name": "Invalid mixed versions collection", + "folders": [ + { + "v": 8, + "id": "cmbgnb4h100v613phgrz6vku9", + "name": "fold1", + "folders": [], + "requests": [ + { + "v": "13", + "name": "req", + "method": "GET", + "endpoint": "https://echo.hoppscotch.io", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { + "authType": "inherit", + "authActive": true + }, + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [], + "responses": {} + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbgnb8zy_eab190e2-6770-428c-8645-f49e88a3fe90" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbgnb8zy_7c3f6eca-bd94-44a5-90e3-3f7c2126d63e" +} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json new file mode 100644 index 00000000..cfe97d5c --- /dev/null +++ b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json @@ -0,0 +1,90 @@ +{ + "v": 8, + "id": "cmbgcmyly10yhdjet63hiorps", + "name": "Valid mixed versions collection", + "folders": [ + { + "v": 7, + "id": "cmbgnb4h100v613phgrz6vku9", + "name": "fold1", + "folders": [ + { + "v": 6, + "id": "cmbhux44609zs2triccmql79r", + "name": "fold2", + "folders": [ + { + "v": 5, + "id": "cmbhux6es09zv2triton3kzv4", + "name": "fold3", + "folders": [ + { + "v": 4, + "id": "cmbhux9vo0b2t13ph6dwapwh3", + "name": "fold4", + "folders": [], + "requests": [ + { + "v": "13", + "name": "req", + "method": "GET", + "endpoint": "https://echo.hoppscotch.io", + "params": [], + "headers": [], + "preRequestScript": "", + "testScript": "", + "auth": { + "authType": "inherit", + "authActive": true + }, + "body": { + "contentType": null, + "body": null + }, + "requestVariables": [], + "responses": {} + } + ], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbhuxoci_023b77eb-ed0c-4ec7-97ca-f46cf327cc54" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbhuxoci_d22767f4-fd0a-4264-a86a-ba4a87c009cb" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbhuxoci_0effd54f-8e08-441f-9b44-95d02ff1861e" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbhuxoci_d7eee2ab-a921-447f-931d-bdce8c715770" + } + ], + "requests": [], + "auth": { + "authType": "inherit", + "authActive": true + }, + "headers": [], + "_ref_id": "coll_mbhuxoci_a8fc710e-04c1-489c-a183-7f16946a7225" +} diff --git a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts b/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts index 95613178..acb7fd61 100644 --- a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts +++ b/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts @@ -1365,7 +1365,81 @@ export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK }, ]; -export const WORKSPACE_ENVIRONMENT_MOCK: WorkspaceEnvironment = { +export const WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK = { + id: "clwudd68q00079rufju8uo3om", + teamID: "clws3hg58000011o8h07glsb1", + name: "Workspace environment v0 format", + variables: [ + { + key: "firstName", + value: "John", + }, + { + key: "lastName", + value: "Doe", + }, + ], +}; + +export const TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK: Environment = { + v: EnvironmentSchemaVersion, + id: "clwudd68q00079rufju8uo3om", + name: "Workspace environment v0 format", + variables: [ + { + key: "firstName", + initialValue: "John", + currentValue: "John", + secret: false, + }, + { + key: "lastName", + initialValue: "Doe", + currentValue: "Doe", + secret: false, + }, + ], +}; + +export const WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK = { + id: "clwudd68q00079rufju8uo3om", + teamID: "clws3hg58000011o8h07glsb1", + name: "Workspace environment v1 format", + variables: [ + { + key: "firstName", + value: "John", + secret: false, + }, + { + key: "lastName", + value: "Doe", + secret: false, + }, + ], +}; + +export const TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK: Environment = { + v: EnvironmentSchemaVersion, + id: "clwudd68q00079rufju8uo3om", + name: "Workspace environment v1 format", + variables: [ + { + key: "firstName", + initialValue: "John", + currentValue: "John", + secret: false, + }, + { + key: "lastName", + initialValue: "Doe", + currentValue: "Doe", + secret: false, + }, + ], +}; + +export const WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK: WorkspaceEnvironment = { id: "clwudd68q00079rufju8uo3on", teamID: "clws3hg58000011o8h07glsb1", name: "Response body sample", @@ -1421,7 +1495,7 @@ export const WORKSPACE_ENVIRONMENT_MOCK: WorkspaceEnvironment = { ], }; -export const TRANSFORMED_ENVIRONMENT_MOCK: Environment = { +export const TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK: Environment = { v: EnvironmentSchemaVersion, id: "clwudd68q00079rufju8uo3on", name: "Response body sample", diff --git a/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts index 51e5dbf2..eb7ef180 100644 --- a/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts +++ b/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts @@ -7,11 +7,15 @@ import { import { TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK, TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK, - TRANSFORMED_ENVIRONMENT_MOCK, + TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK, + TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK, + TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK, TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK, WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_AT_CERTAIN_LEVELS_MOCK, WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_MOCK, - WORKSPACE_ENVIRONMENT_MOCK, + WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK, + WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK, + WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK, WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK, } from "./fixtures/workspace-access.mock"; @@ -45,10 +49,24 @@ describe("workspace-access", () => { }); describe("transformWorkspaceEnvironment", () => { - test("Successfully transforms environment data conforming to the format received from the network call to the `HoppEnvironment` format", () => { - expect(transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_MOCK)).toEqual( - TRANSFORMED_ENVIRONMENT_MOCK - ); + test("Successfully transforms environment data conforming to the `v0` format received from the network call to the `HoppEnvironment` format", () => { + expect( + // @ts-expect-error: Testing legacy format transformation + transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK) + ).toEqual(TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK); + }); + + test("Successfully transforms environment data conforming to the `v1` format received from the network call to the `HoppEnvironment` format", () => { + expect( + // @ts-expect-error: Testing legacy format transformation + transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK) + ).toEqual(TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK); + }); + + test("Successfully transforms environment data conforming to the `v2` format received from the network call to the `HoppEnvironment` format", () => { + expect( + transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK) + ).toEqual(TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK); }); }); }); diff --git a/packages/hoppscotch-cli/src/utils/workspace-access.ts b/packages/hoppscotch-cli/src/utils/workspace-access.ts index 901021c9..2ab6c7ac 100644 --- a/packages/hoppscotch-cli/src/utils/workspace-access.ts +++ b/packages/hoppscotch-cli/src/utils/workspace-access.ts @@ -45,6 +45,37 @@ const transformWorkspaceRequests = ( requests: WorkspaceRequest[] ): HoppRESTRequest[] => requests.map(({ request }) => JSON.parse(request)); +/** + * Apply relevant migrations for data conforming to older formats + * + * @param {HoppEnvPair} variable - The environment variable to normalize. + * @returns {HoppEnvPair} The normalized environment variable conforming to the `HoppEnvPair` type. + */ +const normalizeEnvironmentVariable = (variable: HoppEnvPair): HoppEnvPair => { + if ( + "secret" in variable && + "initialValue" in variable && + "currentValue" in variable + ) { + return variable; + } + + const envPair = variable as Partial & { + key: string; + value?: string; + }; + + const isSecret = !!envPair.secret; + const value = envPair.value ?? ""; + + return { + key: envPair.key, + secret: isSecret, + initialValue: isSecret ? "" : (envPair.initialValue ?? value), + currentValue: isSecret ? "" : (envPair.currentValue ?? value), + }; +}; + /** * Transforms workspace environment data to the `HoppEnvironment` format. * @@ -56,23 +87,11 @@ export const transformWorkspaceEnvironment = ( ): Environment => { const { teamID, variables, ...rest } = workspaceEnvironment; - // Add `secret` field if the data conforms to an older schema - const transformedEnvVars = variables.map((variable) => { - if (!("secret" in variable)) { - return { - ...(variable as HoppEnvPair), - secret: false, - } as HoppEnvPair; - } - - return variable; - }); - // The response doesn't include a way to infer the schema version, so it's set to the latest version // Any relevant migrations have to be accounted here return { v: EnvironmentSchemaVersion, - variables: transformedEnvVars, + variables: variables.map(normalizeEnvironmentVariable), ...rest, }; }; @@ -96,19 +115,34 @@ export const transformWorkspaceCollections = ( const { auth = { authType: "inherit", authActive: true }, headers = [] } = parsedData; + const migratedAuth: HoppRESTAuth = + auth.authType === "oauth-2" + ? { + ...auth, + grantTypeInfo: + auth.grantTypeInfo.grantType === "CLIENT_CREDENTIALS" + ? { + ...auth.grantTypeInfo, + clientAuthentication: "IN_BODY", + } + : auth.grantTypeInfo, + } + : auth; + const migratedHeaders = headers.map((header) => header.description ? header : { ...header, description: "" } ); // The response doesn't include a way to infer the schema version, so it's set to the latest version // Any relevant migrations have to be accounted here + // `ref_id` field isn't necessary being applicable only to personal workspace and asociates with syncing return { v: CollectionSchemaVersion, id, name: title, folders: transformWorkspaceCollections(folders), requests: transformWorkspaceRequests(requests), - auth, + auth: migratedAuth, headers: migratedHeaders, }; }); diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json index e155ea3e..4683368f 100644 --- a/packages/hoppscotch-common/package.json +++ b/packages/hoppscotch-common/package.json @@ -102,7 +102,7 @@ "url": "0.11.4", "util": "0.12.5", "uuid": "10.0.0", - "verzod": "0.2.4", + "verzod": "0.3.0", "vue": "3.5.12", "vue-i18n": "10.0.4", "vue-json-pretty": "2.4.0", diff --git a/packages/hoppscotch-data/package.json b/packages/hoppscotch-data/package.json index 4c1cbce2..b82c9481 100644 --- a/packages/hoppscotch-data/package.json +++ b/packages/hoppscotch-data/package.json @@ -43,11 +43,11 @@ "dependencies": { "fp-ts": "2.16.9", "io-ts": "2.2.21", + "jose": "6.0.11", "lodash": "4.17.21", "parser-ts": "0.7.0", - "jose": "6.0.11", "uuid": "10.0.0", - "verzod": "0.2.4", + "verzod": "0.3.0", "zod": "3.25.32" } } diff --git a/packages/hoppscotch-data/src/collection/v/1.ts b/packages/hoppscotch-data/src/collection/v/1.ts index 73b30e28..f2a923b1 100644 --- a/packages/hoppscotch-data/src/collection/v/1.ts +++ b/packages/hoppscotch-data/src/collection/v/1.ts @@ -1,7 +1,8 @@ -import { defineVersion, entityReference } from "verzod" +import { defineVersion, entityReference, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppRESTRequest } from "../../rest" import { HoppGQLRequest } from "../../graphql" +import { HoppCollection } from ".." const baseCollectionSchema = z.object({ v: z.literal(1), @@ -26,10 +27,9 @@ type Output = z.output & { folders: Output[] } -export const V1_SCHEMA: z.ZodType = - baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V1_SCHEMA)), - }) +export const V1_SCHEMA = baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 1))), +}) as z.ZodType export default defineVersion({ initial: true, diff --git a/packages/hoppscotch-data/src/collection/v/2.ts b/packages/hoppscotch-data/src/collection/v/2.ts index f91554fe..cef5a721 100644 --- a/packages/hoppscotch-data/src/collection/v/2.ts +++ b/packages/hoppscotch-data/src/collection/v/2.ts @@ -1,4 +1,4 @@ -import { defineVersion, entityReference } from "verzod" +import { defineVersion, entityReference, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppGQLRequest } from "../../graphql" @@ -8,6 +8,7 @@ import { HoppRESTRequest } from "../../rest" import { HoppRESTHeaders } from "../../rest/v/1" import { HoppRESTAuth } from "../../rest/v/5" import { V1_SCHEMA } from "./1" +import { HoppCollection } from ".." export const v2_baseCollectionSchema = z.object({ v: z.literal(2), @@ -35,16 +36,14 @@ type Output = z.output & { folders: Output[] } -export const V2_SCHEMA: z.ZodType = - v2_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V2_SCHEMA)), - }) +export const V2_SCHEMA = v2_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 2))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V2_SCHEMA, up(old: z.infer) { - // @ts-expect-error const result: z.infer = { ...old, v: 2, @@ -53,6 +52,15 @@ export default defineVersion({ authType: "inherit", }, headers: [], + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 2) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } if (old.id) result.id = old.id diff --git a/packages/hoppscotch-data/src/collection/v/3.ts b/packages/hoppscotch-data/src/collection/v/3.ts index 776abc10..15e0c704 100644 --- a/packages/hoppscotch-data/src/collection/v/3.ts +++ b/packages/hoppscotch-data/src/collection/v/3.ts @@ -1,4 +1,4 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { GQLHeader as V1_GQLHeader } from "../../graphql/v/1" @@ -11,6 +11,7 @@ import { } from "../../rest/v/7" import { v2_baseCollectionSchema, V2_SCHEMA } from "./2" +import { HoppCollection } from ".." export const v3_baseCollectionSchema = v2_baseCollectionSchema.extend({ v: z.literal(3), @@ -30,10 +31,9 @@ type Output = z.output & { folders: Output[] } -export const V3_SCHEMA: z.ZodType = - v3_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V3_SCHEMA)), - }) +export const V3_SCHEMA = v3_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 3))), +}) as z.ZodType export default defineVersion({ initial: false, @@ -46,11 +46,19 @@ export default defineVersion({ }) ) - // @ts-expect-error const result: z.infer = { ...old, v: 3, headers, + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 3) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } return result diff --git a/packages/hoppscotch-data/src/collection/v/4.ts b/packages/hoppscotch-data/src/collection/v/4.ts index a8996ff4..7af4ab38 100644 --- a/packages/hoppscotch-data/src/collection/v/4.ts +++ b/packages/hoppscotch-data/src/collection/v/4.ts @@ -1,10 +1,11 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppGQLAuth } from "../../graphql/v/7" import { HoppRESTAuth } from "../../rest/v/8" import { V3_SCHEMA, v3_baseCollectionSchema } from "./3" +import { HoppCollection } from ".." export const v4_baseCollectionSchema = v3_baseCollectionSchema.extend({ v: z.literal(4), @@ -19,19 +20,28 @@ type Output = z.output & { folders: Output[] } -export const V4_SCHEMA: z.ZodType = - v4_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V4_SCHEMA)), - }) +export const V4_SCHEMA = v4_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 4))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V4_SCHEMA, - // @ts-expect-error up(old: z.infer) { - return { + const result: z.infer = { ...old, v: 4 as const, + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 4) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } + + return result }, }) diff --git a/packages/hoppscotch-data/src/collection/v/5.ts b/packages/hoppscotch-data/src/collection/v/5.ts index 551a3a1c..8f372635 100644 --- a/packages/hoppscotch-data/src/collection/v/5.ts +++ b/packages/hoppscotch-data/src/collection/v/5.ts @@ -1,8 +1,9 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { V4_SCHEMA, v4_baseCollectionSchema } from "./4" import { generateUniqueRefId } from "../../utils/collection" +import { HoppCollection } from ".." export const v5_baseCollectionSchema = v4_baseCollectionSchema.extend({ v: z.literal(5), @@ -17,20 +18,29 @@ type Output = z.output & { folders: Output[] } -export const V5_SCHEMA: z.ZodType = - v5_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V5_SCHEMA)), - }) +export const V5_SCHEMA = v5_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 5))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V5_SCHEMA, - // @ts-expect-error up(old: z.infer) { - return { + const result: z.infer = { ...old, v: 5 as const, _ref_id: generateUniqueRefId("coll"), + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 5) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } + + return result }, }) diff --git a/packages/hoppscotch-data/src/collection/v/6.ts b/packages/hoppscotch-data/src/collection/v/6.ts index 39b02469..ca65d7a5 100644 --- a/packages/hoppscotch-data/src/collection/v/6.ts +++ b/packages/hoppscotch-data/src/collection/v/6.ts @@ -1,10 +1,11 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppGQLAuth } from "../../graphql/v/8" import { HoppRESTAuth } from "../../rest/v/11" import { V5_SCHEMA, v5_baseCollectionSchema } from "./5" +import { HoppCollection } from ".." export const v6_baseCollectionSchema = v5_baseCollectionSchema.extend({ v: z.literal(6), @@ -19,15 +20,13 @@ type Output = z.output & { folders: Output[] } -export const V6_SCHEMA: z.ZodType = - v6_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V6_SCHEMA)), - }) +export const V6_SCHEMA = v6_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 6))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V6_SCHEMA, - // @ts-expect-error up(old: z.infer) { const auth = old.auth @@ -45,10 +44,21 @@ export default defineVersion({ } : auth - return { + const result: z.infer = { ...old, auth: migratedAuth, v: 6 as const, + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 6) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } + + return result }, }) diff --git a/packages/hoppscotch-data/src/collection/v/7.ts b/packages/hoppscotch-data/src/collection/v/7.ts index 55afb1ac..ce6fb29f 100644 --- a/packages/hoppscotch-data/src/collection/v/7.ts +++ b/packages/hoppscotch-data/src/collection/v/7.ts @@ -1,10 +1,11 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppGQLAuth } from "../../graphql/v/8" import { HoppRESTAuth } from "../../rest/v/12" import { V6_SCHEMA, v6_baseCollectionSchema } from "./6" +import { HoppCollection } from ".." export const v7_baseCollectionSchema = v6_baseCollectionSchema.extend({ v: z.literal(7), @@ -19,19 +20,28 @@ type Output = z.output & { folders: Output[] } -export const V7_SCHEMA: z.ZodType = - v7_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V7_SCHEMA)), - }) +export const V7_SCHEMA = v7_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 7))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V7_SCHEMA, - // @ts-expect-error up(old: z.infer) { - return { + const result: z.infer = { ...old, v: 7 as const, + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 7) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } + + return result }, }) diff --git a/packages/hoppscotch-data/src/collection/v/8.ts b/packages/hoppscotch-data/src/collection/v/8.ts index e91103f0..d11ed776 100644 --- a/packages/hoppscotch-data/src/collection/v/8.ts +++ b/packages/hoppscotch-data/src/collection/v/8.ts @@ -1,10 +1,11 @@ -import { defineVersion } from "verzod" +import { defineVersion, entityRefUptoVersion } from "verzod" import { z } from "zod" import { HoppGQLAuth } from "../../graphql/v/8" import { HoppRESTAuth } from "../../rest/v/13" -import { V7_SCHEMA, v7_baseCollectionSchema } from "./7" +import { HoppCollection } from ".." +import { v7_baseCollectionSchema, V7_SCHEMA } from "./7" export const v8_baseCollectionSchema = v7_baseCollectionSchema.extend({ v: z.literal(8), @@ -19,19 +20,28 @@ type Output = z.output & { folders: Output[] } -export const V8_SCHEMA: z.ZodType = - v8_baseCollectionSchema.extend({ - folders: z.lazy(() => z.array(V8_SCHEMA)), - }) +export const V8_SCHEMA = v8_baseCollectionSchema.extend({ + folders: z.lazy(() => z.array(entityRefUptoVersion(HoppCollection, 8))), +}) as z.ZodType export default defineVersion({ initial: false, schema: V8_SCHEMA, - // @ts-expect-error up(old: z.infer) { - return { + const result: z.infer = { ...old, v: 8 as const, + folders: old.folders.map((folder) => { + const result = HoppCollection.safeParseUpToVersion(folder, 8) + + if (result.type !== "ok") { + throw new Error("Failed to migrate child collections") + } + + return result.value + }), } + + return result }, }) diff --git a/packages/hoppscotch-selfhost-desktop/package.json b/packages/hoppscotch-selfhost-desktop/package.json index eaa1c5a6..600908d3 100644 --- a/packages/hoppscotch-selfhost-desktop/package.json +++ b/packages/hoppscotch-selfhost-desktop/package.json @@ -36,10 +36,10 @@ "tauri": "link:@tauri-apps/api/tauri", "tauri-plugin-store-api": "0.0.0", "util": "0.12.5", - "verzod": "0.2.4", + "verzod": "0.3.0", "vue": "3.3.9", "workbox-window": "6.6.0", - "zod": "3.22.4" + "zod": "3.25.32" }, "devDependencies": { "@graphql-codegen/add": "5.0.0", diff --git a/packages/hoppscotch-selfhost-web/package.json b/packages/hoppscotch-selfhost-web/package.json index 3b827896..0d65c591 100644 --- a/packages/hoppscotch-selfhost-web/package.json +++ b/packages/hoppscotch-selfhost-web/package.json @@ -44,7 +44,7 @@ "rxjs": "7.8.1", "stream-browserify": "3.0.0", "util": "0.12.5", - "verzod": "0.2.4", + "verzod": "0.3.0", "vue": "3.5.12", "workbox-window": "7.1.0", "zod": "3.25.32" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89f41261..365ddd4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -422,8 +422,8 @@ importers: specifier: 6.13.0 version: 6.13.0 verzod: - specifier: 0.2.4 - version: 0.2.4(zod@3.25.32) + specifier: 0.3.0 + version: 0.3.0(zod@3.25.32) xmlbuilder2: specifier: 3.1.1 version: 3.1.1 @@ -714,8 +714,8 @@ importers: specifier: 10.0.0 version: 10.0.0 verzod: - specifier: 0.2.4 - version: 0.2.4(zod@3.25.32) + specifier: 0.3.0 + version: 0.3.0(zod@3.25.32) vue: specifier: 3.5.12 version: 3.5.12(typescript@5.8.3) @@ -961,8 +961,8 @@ importers: specifier: 10.0.0 version: 10.0.0 verzod: - specifier: 0.2.4 - version: 0.2.4(zod@3.25.32) + specifier: 0.3.0 + version: 0.3.0(zod@3.25.32) zod: specifier: 3.25.32 version: 3.25.32 @@ -1316,8 +1316,8 @@ importers: specifier: 0.12.5 version: 0.12.5 verzod: - specifier: 0.2.4 - version: 0.2.4(zod@3.22.4) + specifier: 0.3.0 + version: 0.3.0(zod@3.25.32) vue: specifier: 3.5.12 version: 3.5.12(typescript@4.9.5) @@ -1325,8 +1325,8 @@ importers: specifier: 6.6.0 version: 6.6.0 zod: - specifier: 3.22.4 - version: 3.22.4 + specifier: 3.25.32 + version: 3.25.32 devDependencies: '@graphql-codegen/add': specifier: 5.0.0 @@ -1512,8 +1512,8 @@ importers: specifier: 0.12.5 version: 0.12.5 verzod: - specifier: 0.2.4 - version: 0.2.4(zod@3.25.32) + specifier: 0.3.0 + version: 0.3.0(zod@3.25.32) vue: specifier: 3.5.12 version: 3.5.12(typescript@5.8.3) @@ -13609,8 +13609,8 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - verzod@0.2.4: - resolution: {integrity: sha512-xli0iwB1nxtWiJTjekTuPm9DuHXU8zdu6vKG2QXT0ZYKn9HanS/azJDSvbvT5IQ5HHltoV9h2Jf4Y+dwk8Fa5Q==} + verzod@0.3.0: + resolution: {integrity: sha512-h3L33u54/U/KWQh5z2sEaB0esQt3K3BhCCiriACW9t+83fLD7ebQnzcdckhIwZeZWfgQHNI7PTEDITlCqHTtZw==} engines: {node: '>=16'} peerDependencies: zod: ^3.22.0 @@ -30416,11 +30416,7 @@ snapshots: vary@1.1.2: {} - verzod@0.2.4(zod@3.22.4): - dependencies: - zod: 3.22.4 - - verzod@0.2.4(zod@3.25.32): + verzod@0.3.0(zod@3.25.32): dependencies: zod: 3.25.32