@scalar/oas-utils 0.6.42 → 0.6.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +11 -1
- package/dist/migrations/index.js.map +2 -2
- package/dist/migrations/migrate-to-indexdb.d.ts +60 -0
- package/dist/migrations/migrate-to-indexdb.d.ts.map +1 -0
- package/dist/migrations/migrate-to-indexdb.js +540 -0
- package/dist/migrations/migrate-to-indexdb.js.map +7 -0
- package/dist/migrations/migrator.d.ts +4 -1
- package/dist/migrations/migrator.d.ts.map +1 -1
- package/dist/migrations/migrator.js +13 -11
- package/dist/migrations/migrator.js.map +2 -2
- package/package.json +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,88 @@
|
|
|
1
1
|
# @scalar/oas-utils
|
|
2
2
|
|
|
3
|
+
## 0.6.46
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
#### Updated Dependencies
|
|
8
|
+
|
|
9
|
+
- **@scalar/workspace-store@0.34.2**
|
|
10
|
+
- [#8219](https://github.com/scalar/scalar/pull/8219): chore: default to proxy for web layout
|
|
11
|
+
|
|
12
|
+
## 0.6.45
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [#8212](https://github.com/scalar/scalar/pull/8212): chore: version bump
|
|
17
|
+
|
|
18
|
+
#### Updated Dependencies
|
|
19
|
+
|
|
20
|
+
- **@scalar/helpers@0.2.15**
|
|
21
|
+
- [#8212](https://github.com/scalar/scalar/pull/8212): chore: version bump
|
|
22
|
+
|
|
23
|
+
- **@scalar/json-magic@0.11.4**
|
|
24
|
+
- [#8212](https://github.com/scalar/scalar/pull/8212): chore: version bump
|
|
25
|
+
|
|
26
|
+
- **@scalar/types@0.6.6**
|
|
27
|
+
- [#8212](https://github.com/scalar/scalar/pull/8212): chore: version bump
|
|
28
|
+
|
|
29
|
+
- **@scalar/workspace-store@0.34.1**
|
|
30
|
+
- [#8212](https://github.com/scalar/scalar/pull/8212): chore: version bump
|
|
31
|
+
|
|
32
|
+
- **@scalar/object-utils@1.2.29**
|
|
33
|
+
|
|
34
|
+
## 0.6.44
|
|
35
|
+
|
|
36
|
+
### Patch Changes
|
|
37
|
+
|
|
38
|
+
- [#8207](https://github.com/scalar/scalar/pull/8207): chore: version bump
|
|
39
|
+
|
|
40
|
+
#### Updated Dependencies
|
|
41
|
+
|
|
42
|
+
- **@scalar/workspace-store@0.34.0**
|
|
43
|
+
- [#8198](https://github.com/scalar/scalar/pull/8198): feat: handle workspace rename
|
|
44
|
+
- [#8208](https://github.com/scalar/scalar/pull/8208): fix: unpack proxy before assigning
|
|
45
|
+
- [#8207](https://github.com/scalar/scalar/pull/8207): chore: version bump
|
|
46
|
+
|
|
47
|
+
- **@scalar/helpers@0.2.14**
|
|
48
|
+
- [#8207](https://github.com/scalar/scalar/pull/8207): chore: version bump
|
|
49
|
+
|
|
50
|
+
- **@scalar/json-magic@0.11.3**
|
|
51
|
+
- [#8207](https://github.com/scalar/scalar/pull/8207): chore: version bump
|
|
52
|
+
|
|
53
|
+
- **@scalar/types@0.6.5**
|
|
54
|
+
- [#8207](https://github.com/scalar/scalar/pull/8207): chore: version bump
|
|
55
|
+
|
|
56
|
+
- **@scalar/object-utils@1.2.28**
|
|
57
|
+
|
|
58
|
+
## 0.6.43
|
|
59
|
+
|
|
60
|
+
### Patch Changes
|
|
61
|
+
|
|
62
|
+
- [#7826](https://github.com/scalar/scalar/pull/7826): feat: added migrator for v1 local storage to v2 indexdb
|
|
63
|
+
|
|
64
|
+
#### Updated Dependencies
|
|
65
|
+
|
|
66
|
+
- **@scalar/workspace-store@0.33.0**
|
|
67
|
+
- [#8162](https://github.com/scalar/scalar/pull/8162): feat: allow editing tags
|
|
68
|
+
- [#8151](https://github.com/scalar/scalar/pull/8151): fix: resolve external references on windows
|
|
69
|
+
- [#8191](https://github.com/scalar/scalar/pull/8191): chore: rename create document command
|
|
70
|
+
- [#8199](https://github.com/scalar/scalar/pull/8199): feat: create draft example
|
|
71
|
+
- [#7826](https://github.com/scalar/scalar/pull/7826): feat: added migrator for v1 local storage to v2 indexdb
|
|
72
|
+
- [#8160](https://github.com/scalar/scalar/pull/8160): fix: update sidebar entry when the operation summary changes
|
|
73
|
+
- [#8133](https://github.com/scalar/scalar/pull/8133): fix: allow editing content-type query parameters in the API client
|
|
74
|
+
|
|
75
|
+
- **@scalar/json-magic@0.11.2**
|
|
76
|
+
- [#8151](https://github.com/scalar/scalar/pull/8151): fix: resolve external references on windows
|
|
77
|
+
|
|
78
|
+
- **@scalar/helpers@0.2.13**
|
|
79
|
+
- [#7826](https://github.com/scalar/scalar/pull/7826): feat: added migrator for v1 local storage to v2 indexdb
|
|
80
|
+
|
|
81
|
+
- **@scalar/types@0.6.4**
|
|
82
|
+
- [#8174](https://github.com/scalar/scalar/pull/8174): feat: add `createAnySecurityScheme` config option to control generic auth scheme creation
|
|
83
|
+
|
|
84
|
+
- **@scalar/object-utils@1.2.27**
|
|
85
|
+
|
|
3
86
|
## 0.6.42
|
|
4
87
|
|
|
5
88
|
### Patch Changes
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { DATA_VERSION, DATA_VERSION_LS_LEY } from './data-version.js';
|
|
2
|
+
export { clearLegacyLocalStorage, migrateLocalStorageToIndexDb, shouldMigrateToIndexDb, transformLegacyDataToWorkspace, } from './migrate-to-indexdb.js';
|
|
2
3
|
export { migrator } from './migrator.js';
|
|
3
4
|
export { semverLessThan } from './semver.js';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,sBAAsB,EACtB,8BAA8B,GAC/B,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
|
package/dist/migrations/index.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { DATA_VERSION, DATA_VERSION_LS_LEY } from "./data-version.js";
|
|
2
|
+
import {
|
|
3
|
+
clearLegacyLocalStorage,
|
|
4
|
+
migrateLocalStorageToIndexDb,
|
|
5
|
+
shouldMigrateToIndexDb,
|
|
6
|
+
transformLegacyDataToWorkspace
|
|
7
|
+
} from "./migrate-to-indexdb.js";
|
|
2
8
|
import { migrator } from "./migrator.js";
|
|
3
9
|
import { semverLessThan } from "./semver.js";
|
|
4
10
|
export {
|
|
5
11
|
DATA_VERSION,
|
|
6
12
|
DATA_VERSION_LS_LEY,
|
|
13
|
+
clearLegacyLocalStorage,
|
|
14
|
+
migrateLocalStorageToIndexDb,
|
|
7
15
|
migrator,
|
|
8
|
-
semverLessThan
|
|
16
|
+
semverLessThan,
|
|
17
|
+
shouldMigrateToIndexDb,
|
|
18
|
+
transformLegacyDataToWorkspace
|
|
9
19
|
};
|
|
10
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/migrations/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { DATA_VERSION, DATA_VERSION_LS_LEY } from './data-version'\nexport { migrator } from './migrator'\nexport { semverLessThan } from './semver'\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,cAAc,2BAA2B;AAClD,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;",
|
|
4
|
+
"sourcesContent": ["export { DATA_VERSION, DATA_VERSION_LS_LEY } from './data-version'\nexport {\n clearLegacyLocalStorage,\n migrateLocalStorageToIndexDb,\n shouldMigrateToIndexDb,\n transformLegacyDataToWorkspace,\n} from './migrate-to-indexdb'\nexport { migrator } from './migrator'\nexport { semverLessThan } from './semver'\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,cAAc,2BAA2B;AAClD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createWorkspaceStorePersistence } from '@scalar/workspace-store/persistence';
|
|
2
|
+
import type { InMemoryWorkspace } from '@scalar/workspace-store/schemas/inmemory-workspace';
|
|
3
|
+
import type { v_2_5_0 } from '../migrations/v-2.5.0/types.generated.js';
|
|
4
|
+
/**
|
|
5
|
+
* Migrates localStorage data to IndexedDB workspace structure.
|
|
6
|
+
*
|
|
7
|
+
* Called early in app initialization (app-state.ts) before workspace data loads.
|
|
8
|
+
* Idempotent and non-destructive - runs when legacy data exists but IndexedDB is empty.
|
|
9
|
+
*
|
|
10
|
+
* Flow:
|
|
11
|
+
* 1. Check if migration needed (has legacy data + IndexedDB is empty)
|
|
12
|
+
* 2. Run existing migrations to get latest data structure
|
|
13
|
+
* 3. Transform to new workspace format
|
|
14
|
+
* 4. Save to IndexedDB
|
|
15
|
+
*
|
|
16
|
+
* Old data is preserved for rollback. Typically completes in < 1 second.
|
|
17
|
+
*/
|
|
18
|
+
export declare const migrateLocalStorageToIndexDb: () => Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Checks if migration is needed by verifying IndexedDB state and presence of legacy data.
|
|
21
|
+
*
|
|
22
|
+
* Migration is needed when:
|
|
23
|
+
* 1. Legacy data exists in localStorage (workspace, collection, or request keys)
|
|
24
|
+
* 2. AND IndexedDB has no workspaces yet
|
|
25
|
+
*
|
|
26
|
+
* This approach is more reliable than using a flag because:
|
|
27
|
+
* - If IndexedDB is cleared, migration will run again automatically
|
|
28
|
+
* - No risk of flag getting out of sync with actual data state
|
|
29
|
+
* - Handles edge cases like partial migrations or database corruption
|
|
30
|
+
*/
|
|
31
|
+
export declare const shouldMigrateToIndexDb: (workspacePersistence: Awaited<ReturnType<typeof createWorkspaceStorePersistence>>["workspace"]) => Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* Transforms legacy localStorage data into IndexedDB workspace structure.
|
|
34
|
+
*
|
|
35
|
+
* Transformations:
|
|
36
|
+
* - Collections → Documents (collections were OpenAPI specs)
|
|
37
|
+
* - Environments → x-scalar-environments in meta
|
|
38
|
+
* - Cookies → x-scalar-cookies in meta
|
|
39
|
+
* - Workspace properties → meta extensions (activeEnvironmentId, proxyUrl, themeId)
|
|
40
|
+
*
|
|
41
|
+
* Creates a default workspace if none exist. Falls back to collection uid if info.title is missing.
|
|
42
|
+
*/
|
|
43
|
+
export declare const transformLegacyDataToWorkspace: (legacyData: {
|
|
44
|
+
arrays: v_2_5_0["DataArray"];
|
|
45
|
+
records: v_2_5_0["DataRecord"];
|
|
46
|
+
}) => Promise<{
|
|
47
|
+
slug: string;
|
|
48
|
+
name: string;
|
|
49
|
+
workspace: InMemoryWorkspace;
|
|
50
|
+
}[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Clears legacy localStorage data after successful migration.
|
|
53
|
+
*
|
|
54
|
+
* NOT called automatically - old data is preserved as a safety net for rollback.
|
|
55
|
+
* Call only after migration succeeds and a grace period passes (e.g., 30 days).
|
|
56
|
+
*
|
|
57
|
+
* To rollback: clear IndexedDB and reload - migration will run again automatically.
|
|
58
|
+
*/
|
|
59
|
+
export declare const clearLegacyLocalStorage: () => void;
|
|
60
|
+
//# sourceMappingURL=migrate-to-indexdb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-to-indexdb.d.ts","sourceRoot":"","sources":["../../src/migrations/migrate-to-indexdb.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,+BAA+B,EAAE,MAAM,qCAAqC,CAAA;AAOrF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oDAAoD,CAAA;AAmB3F,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAEnE;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,qBA2CxC,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GACjC,sBAAsB,OAAO,CAAC,UAAU,CAAC,OAAO,+BAA+B,CAAC,CAAC,CAAC,WAAW,CAAC,KAC7F,OAAO,CAAC,OAAO,CAiBjB,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,GAAU,YAAY;IAC/D,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAC/B;;;;IAyFE,CAAA;AA2nBH;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,QAAO,IAmB1C,CAAA"}
|
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { CONTENT_TYPES } from "@scalar/helpers/consts/content-types";
|
|
2
|
+
import { extractConfigSecrets, removeSecretFields } from "@scalar/helpers/general/extract-config-secrets";
|
|
3
|
+
import { circularToRefs } from "@scalar/helpers/object/circular-to-refs";
|
|
4
|
+
import { objectEntries } from "@scalar/helpers/object/object-entries";
|
|
5
|
+
import { createWorkspaceStore } from "@scalar/workspace-store/client";
|
|
6
|
+
import { AuthSchema } from "@scalar/workspace-store/entities/auth";
|
|
7
|
+
import { createWorkspaceStorePersistence } from "@scalar/workspace-store/persistence";
|
|
8
|
+
import {
|
|
9
|
+
xScalarEnvironmentSchema
|
|
10
|
+
} from "@scalar/workspace-store/schemas/extensions/document/x-scalar-environments";
|
|
11
|
+
import { xScalarCookieSchema } from "@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies";
|
|
12
|
+
import { coerceValue } from "@scalar/workspace-store/schemas/typebox-coerce";
|
|
13
|
+
import {
|
|
14
|
+
OpenAPIDocumentSchema
|
|
15
|
+
} from "@scalar/workspace-store/schemas/v3.1/strict/openapi-document";
|
|
16
|
+
import { ColorModeSchema } from "@scalar/workspace-store/schemas/workspace";
|
|
17
|
+
import { DATA_VERSION_LS_LEY } from "../migrations/data-version.js";
|
|
18
|
+
import { migrator } from "../migrations/migrator.js";
|
|
19
|
+
const migrateLocalStorageToIndexDb = async () => {
|
|
20
|
+
const { close, workspace: workspacePersistence } = await createWorkspaceStorePersistence();
|
|
21
|
+
try {
|
|
22
|
+
const shouldMigrate = await shouldMigrateToIndexDb(workspacePersistence);
|
|
23
|
+
if (!shouldMigrate) {
|
|
24
|
+
console.info("\u2139\uFE0F No migration needed - IndexedDB already has workspaces or no legacy data exists");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.info("\u{1F680} Starting migration from localStorage to IndexedDB...");
|
|
28
|
+
const legacyData = migrator();
|
|
29
|
+
console.info(
|
|
30
|
+
`\u{1F4E6} Found legacy data: ${legacyData.arrays.workspaces.length} workspace(s), ${legacyData.arrays.collections.length} collection(s)`
|
|
31
|
+
);
|
|
32
|
+
const workspaces = await transformLegacyDataToWorkspace(legacyData);
|
|
33
|
+
await Promise.all(
|
|
34
|
+
workspaces.map(
|
|
35
|
+
(workspace) => workspacePersistence.setItem(
|
|
36
|
+
{ namespace: "local", slug: workspace.slug },
|
|
37
|
+
{
|
|
38
|
+
name: workspace.name,
|
|
39
|
+
workspace: workspace.workspace,
|
|
40
|
+
teamUid: "local"
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
console.info(`\u2705 Successfully migrated ${workspaces.length} workspace(s) to IndexedDB`);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.error("\u274C Migration failed:", error);
|
|
48
|
+
} finally {
|
|
49
|
+
close();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const shouldMigrateToIndexDb = async (workspacePersistence) => {
|
|
53
|
+
const hasLegacyData = localStorage.getItem("workspace") !== null || localStorage.getItem("collection") !== null || localStorage.getItem("request") !== null;
|
|
54
|
+
if (!hasLegacyData) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const existingWorkspaces = await workspacePersistence.getAll();
|
|
58
|
+
const hasIndexDbData = existingWorkspaces.length > 0;
|
|
59
|
+
return !hasIndexDbData;
|
|
60
|
+
};
|
|
61
|
+
const transformLegacyDataToWorkspace = async (legacyData) => await Promise.all(
|
|
62
|
+
legacyData.arrays.workspaces.map(async (workspace) => {
|
|
63
|
+
const workspaceAuth = {};
|
|
64
|
+
const documents = workspace.collections.flatMap((uid) => {
|
|
65
|
+
const collection = legacyData.records.collections[uid];
|
|
66
|
+
if (!collection) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
const documentName = collection.info?.title || collection.uid;
|
|
70
|
+
const { document, auth } = transformCollectionToDocument(documentName, collection, legacyData.records);
|
|
71
|
+
const normalizedName = documentName === "Drafts" ? "drafts" : documentName;
|
|
72
|
+
workspaceAuth[normalizedName] = auth;
|
|
73
|
+
return { name: normalizedName, document };
|
|
74
|
+
});
|
|
75
|
+
const meta = {};
|
|
76
|
+
const extensions = {};
|
|
77
|
+
const environmentEntries = Object.entries(workspace.environments);
|
|
78
|
+
if (environmentEntries.length > 0) {
|
|
79
|
+
extensions["x-scalar-environments"] = {
|
|
80
|
+
default: coerceValue(xScalarEnvironmentSchema, {
|
|
81
|
+
variables: environmentEntries.map(([name, value]) => ({
|
|
82
|
+
name,
|
|
83
|
+
value
|
|
84
|
+
}))
|
|
85
|
+
})
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
if (workspace.cookies.length > 0) {
|
|
89
|
+
extensions["x-scalar-cookies"] = workspace.cookies.flatMap((uid) => {
|
|
90
|
+
const cookie = legacyData.records.cookies[uid];
|
|
91
|
+
return cookie ? coerceValue(xScalarCookieSchema, cookie) : [];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (workspace.proxyUrl) {
|
|
95
|
+
meta["x-scalar-active-proxy"] = workspace.proxyUrl;
|
|
96
|
+
}
|
|
97
|
+
if (workspace.themeId) {
|
|
98
|
+
meta["x-scalar-theme"] = workspace.themeId;
|
|
99
|
+
}
|
|
100
|
+
if (localStorage.getItem("colorMode")) {
|
|
101
|
+
meta["x-scalar-color-mode"] = coerceValue(ColorModeSchema, localStorage.getItem("colorMode"));
|
|
102
|
+
}
|
|
103
|
+
const store = createWorkspaceStore({
|
|
104
|
+
meta
|
|
105
|
+
});
|
|
106
|
+
await Promise.all(
|
|
107
|
+
documents.map(async ({ name, document }) => {
|
|
108
|
+
await store.addDocument({
|
|
109
|
+
name,
|
|
110
|
+
document
|
|
111
|
+
});
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
store.auth.load(workspaceAuth);
|
|
115
|
+
objectEntries(extensions).forEach(([key, value]) => {
|
|
116
|
+
store.update(key, value);
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
slug: workspace.uid.toString(),
|
|
120
|
+
// Convert to string to convert it to a simple string type
|
|
121
|
+
name: workspace.name || "Untitled Workspace",
|
|
122
|
+
workspace: store.exportWorkspace()
|
|
123
|
+
};
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
const transformLegacyEnvironments = (environments) => {
|
|
127
|
+
const entries = Object.entries(environments || {});
|
|
128
|
+
if (entries.length === 0) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
return Object.fromEntries(
|
|
132
|
+
entries.map(([envName, env]) => [
|
|
133
|
+
envName,
|
|
134
|
+
coerceValue(xScalarEnvironmentSchema, {
|
|
135
|
+
color: env.color,
|
|
136
|
+
variables: Object.entries(env.variables || {}).map(([name, value]) => ({
|
|
137
|
+
name,
|
|
138
|
+
value: typeof value === "string" ? value : value.default || ""
|
|
139
|
+
}))
|
|
140
|
+
})
|
|
141
|
+
])
|
|
142
|
+
);
|
|
143
|
+
};
|
|
144
|
+
const transformRequestsToPaths = (collection, dataRecords) => {
|
|
145
|
+
const paths = /* @__PURE__ */ Object.create(null);
|
|
146
|
+
for (const requestUid of collection.requests || []) {
|
|
147
|
+
const request = dataRecords.requests[requestUid];
|
|
148
|
+
if (!request) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const {
|
|
152
|
+
path,
|
|
153
|
+
method,
|
|
154
|
+
uid: _uid,
|
|
155
|
+
type: _type,
|
|
156
|
+
selectedServerUid: _selectedServerUid,
|
|
157
|
+
examples,
|
|
158
|
+
servers,
|
|
159
|
+
selectedSecuritySchemeUids: _selectedSecuritySchemeUids,
|
|
160
|
+
parameters = [],
|
|
161
|
+
requestBody,
|
|
162
|
+
...rest
|
|
163
|
+
} = request;
|
|
164
|
+
if (!paths[path]) {
|
|
165
|
+
paths[path] = {};
|
|
166
|
+
}
|
|
167
|
+
const partialOperation = {
|
|
168
|
+
...rest
|
|
169
|
+
};
|
|
170
|
+
const requestExamples = (examples || []).flatMap((exampleUid) => {
|
|
171
|
+
const example = dataRecords.requestExamples[exampleUid];
|
|
172
|
+
return example ? [example] : [];
|
|
173
|
+
});
|
|
174
|
+
const mergedParameters = mergeExamplesIntoParameters(parameters, requestExamples);
|
|
175
|
+
if (mergedParameters.length > 0) {
|
|
176
|
+
partialOperation.parameters = mergedParameters;
|
|
177
|
+
}
|
|
178
|
+
const mergedRequestBody = mergeExamplesIntoRequestBody(requestBody, requestExamples);
|
|
179
|
+
if (mergedRequestBody) {
|
|
180
|
+
partialOperation.requestBody = mergedRequestBody;
|
|
181
|
+
}
|
|
182
|
+
if (servers && servers.length > 0) {
|
|
183
|
+
partialOperation.servers = servers.flatMap((serverUid) => {
|
|
184
|
+
const server = dataRecords.servers[serverUid];
|
|
185
|
+
if (!server) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const { uid: _, ...rest2 } = server;
|
|
189
|
+
return [rest2];
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
paths[path][method] = partialOperation;
|
|
193
|
+
}
|
|
194
|
+
return paths;
|
|
195
|
+
};
|
|
196
|
+
const PARAM_TYPE_TO_IN = {
|
|
197
|
+
path: "path",
|
|
198
|
+
query: "query",
|
|
199
|
+
headers: "header",
|
|
200
|
+
cookies: "cookie"
|
|
201
|
+
};
|
|
202
|
+
const mergeExamplesIntoParameters = (parameters, requestExamples) => {
|
|
203
|
+
const paramEntries = /* @__PURE__ */ new Map();
|
|
204
|
+
for (const param of parameters) {
|
|
205
|
+
let paramObject;
|
|
206
|
+
if (param.content && typeof param.content === "object") {
|
|
207
|
+
paramObject = {
|
|
208
|
+
name: param.name,
|
|
209
|
+
in: param.in,
|
|
210
|
+
required: param.required ?? param.in === "path",
|
|
211
|
+
deprecated: param.deprecated ?? false,
|
|
212
|
+
content: param.content,
|
|
213
|
+
...param.description && { description: param.description }
|
|
214
|
+
};
|
|
215
|
+
} else {
|
|
216
|
+
paramObject = {
|
|
217
|
+
name: param.name,
|
|
218
|
+
in: param.in,
|
|
219
|
+
required: param.required ?? param.in === "path",
|
|
220
|
+
deprecated: param.deprecated ?? false,
|
|
221
|
+
...param.description && { description: param.description },
|
|
222
|
+
...param.schema ? { schema: param.schema } : {},
|
|
223
|
+
...param.style && { style: param.style },
|
|
224
|
+
...param.explode !== void 0 && { explode: param.explode },
|
|
225
|
+
...param.example !== void 0 && { example: param.example },
|
|
226
|
+
...param.examples && typeof param.examples === "object" && {
|
|
227
|
+
examples: param.examples
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
paramEntries.set(`${param.in}:${param.name}`, {
|
|
232
|
+
param: paramObject,
|
|
233
|
+
examples: {}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const paramTypes = Object.keys(PARAM_TYPE_TO_IN);
|
|
237
|
+
for (const requestExample of requestExamples) {
|
|
238
|
+
const exampleName = requestExample.name || "Example";
|
|
239
|
+
for (const paramType of paramTypes) {
|
|
240
|
+
const inValue = PARAM_TYPE_TO_IN[paramType];
|
|
241
|
+
const items = requestExample.parameters?.[paramType] || [];
|
|
242
|
+
for (const item of items) {
|
|
243
|
+
const key = `${inValue}:${item.key}`;
|
|
244
|
+
if (!item.key) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const lowerKey = item.key.toLowerCase();
|
|
248
|
+
if (!paramEntries.has(key) && (lowerKey !== "content-type" || !CONTENT_TYPES[item.value]) && (lowerKey !== "accept" || item.value !== "*/*")) {
|
|
249
|
+
paramEntries.set(key, {
|
|
250
|
+
param: {
|
|
251
|
+
name: item.key,
|
|
252
|
+
in: inValue ?? "query",
|
|
253
|
+
required: inValue === "path",
|
|
254
|
+
deprecated: false,
|
|
255
|
+
schema: { type: "string" }
|
|
256
|
+
},
|
|
257
|
+
examples: {}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const param = paramEntries.get(key);
|
|
261
|
+
if (!param) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
param.examples[exampleName] = {
|
|
265
|
+
value: item.value,
|
|
266
|
+
"x-disabled": !item.enabled
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return Array.from(paramEntries.values()).map(({ param, examples }) => {
|
|
272
|
+
if (Object.keys(examples).length > 0) {
|
|
273
|
+
;
|
|
274
|
+
param.examples = examples;
|
|
275
|
+
}
|
|
276
|
+
return param;
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
const RAW_ENCODING_TO_CONTENT_TYPE = {
|
|
280
|
+
json: "application/json",
|
|
281
|
+
xml: "application/xml",
|
|
282
|
+
yaml: "application/yaml",
|
|
283
|
+
edn: "application/edn",
|
|
284
|
+
text: "text/plain",
|
|
285
|
+
html: "text/html",
|
|
286
|
+
javascript: "application/javascript"
|
|
287
|
+
};
|
|
288
|
+
const extractBodyExample = (body) => {
|
|
289
|
+
if (!body?.activeBody) {
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
if (body.activeBody === "raw" && body.raw) {
|
|
293
|
+
return {
|
|
294
|
+
contentType: RAW_ENCODING_TO_CONTENT_TYPE[body.raw.encoding] || "text/plain",
|
|
295
|
+
value: body.raw.value
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
if (body.activeBody === "formData" && body.formData) {
|
|
299
|
+
return {
|
|
300
|
+
contentType: body.formData.encoding === "form-data" ? "multipart/form-data" : "application/x-www-form-urlencoded",
|
|
301
|
+
value: body.formData.value.flatMap(
|
|
302
|
+
(param) => param.key ? {
|
|
303
|
+
name: param.key,
|
|
304
|
+
value: param.value,
|
|
305
|
+
isDisabled: !param.enabled
|
|
306
|
+
} : []
|
|
307
|
+
)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
if (body.activeBody === "binary") {
|
|
311
|
+
return { contentType: "binary", value: {} };
|
|
312
|
+
}
|
|
313
|
+
return void 0;
|
|
314
|
+
};
|
|
315
|
+
const mergeExamplesIntoRequestBody = (requestBody, requestExamples) => {
|
|
316
|
+
const groupedByContentType = /* @__PURE__ */ new Map();
|
|
317
|
+
const selectedContentTypes = {};
|
|
318
|
+
for (const example of requestExamples) {
|
|
319
|
+
const extracted = extractBodyExample(example.body);
|
|
320
|
+
if (!extracted) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const name = example.name || "Example";
|
|
324
|
+
const group = groupedByContentType.get(extracted.contentType);
|
|
325
|
+
if (group) {
|
|
326
|
+
group[name] = { value: extracted.value };
|
|
327
|
+
} else {
|
|
328
|
+
groupedByContentType.set(extracted.contentType, { [name]: { value: extracted.value } });
|
|
329
|
+
}
|
|
330
|
+
selectedContentTypes[name] = extracted.contentType;
|
|
331
|
+
}
|
|
332
|
+
if (groupedByContentType.size === 0) {
|
|
333
|
+
return requestBody;
|
|
334
|
+
}
|
|
335
|
+
const result = requestBody ?? {};
|
|
336
|
+
result.content ??= {};
|
|
337
|
+
for (const [contentType, examples] of groupedByContentType) {
|
|
338
|
+
result.content[contentType] ??= {};
|
|
339
|
+
result.content[contentType].examples = examples;
|
|
340
|
+
}
|
|
341
|
+
if (Object.keys(selectedContentTypes).length > 0) {
|
|
342
|
+
result["x-scalar-selected-content-type"] = selectedContentTypes;
|
|
343
|
+
}
|
|
344
|
+
return result;
|
|
345
|
+
};
|
|
346
|
+
const transformLegacyTags = (collection, dataRecords) => {
|
|
347
|
+
const tags = [];
|
|
348
|
+
const tagGroups = [];
|
|
349
|
+
const topLevelTagUids = new Set(collection.children.filter((uid) => dataRecords.tags[uid] !== void 0));
|
|
350
|
+
const parentTagUids = new Set(
|
|
351
|
+
collection.tags.filter((uid) => {
|
|
352
|
+
const tag = dataRecords.tags[uid];
|
|
353
|
+
return tag?.children && tag.children.length > 0;
|
|
354
|
+
})
|
|
355
|
+
);
|
|
356
|
+
for (const tagUid of collection.tags) {
|
|
357
|
+
const tag = dataRecords.tags[tagUid];
|
|
358
|
+
if (!tag) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
const isTopLevelParent = topLevelTagUids.has(tagUid) && parentTagUids.has(tagUid);
|
|
362
|
+
if (isTopLevelParent) {
|
|
363
|
+
const childTagNames = tag.children.map((childUid) => dataRecords.tags[childUid]?.name).filter((name) => name !== void 0);
|
|
364
|
+
if (childTagNames.length > 0) {
|
|
365
|
+
tagGroups.push({
|
|
366
|
+
name: tag.name,
|
|
367
|
+
tags: childTagNames
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
} else {
|
|
371
|
+
const tagObject = { name: tag.name };
|
|
372
|
+
if (tag.description) {
|
|
373
|
+
tagObject.description = tag.description;
|
|
374
|
+
}
|
|
375
|
+
if (tag.externalDocs) {
|
|
376
|
+
tagObject.externalDocs = tag.externalDocs;
|
|
377
|
+
}
|
|
378
|
+
tags.push(tagObject);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return { tags, tagGroups };
|
|
382
|
+
};
|
|
383
|
+
const transformCollectionToDocument = (documentName, collection, dataRecords) => {
|
|
384
|
+
const selectedServerUrl = collection.selectedServerUid && dataRecords.servers[collection.selectedServerUid] ? dataRecords.servers[collection.selectedServerUid]?.url : void 0;
|
|
385
|
+
const { tags, tagGroups } = transformLegacyTags(collection, dataRecords);
|
|
386
|
+
const paths = transformRequestsToPaths(collection, dataRecords);
|
|
387
|
+
const document = {
|
|
388
|
+
openapi: collection.openapi || "3.1.0",
|
|
389
|
+
info: collection.info || {
|
|
390
|
+
title: documentName,
|
|
391
|
+
version: "1.0"
|
|
392
|
+
},
|
|
393
|
+
servers: collection.servers.flatMap((uid) => {
|
|
394
|
+
const server = dataRecords.servers[uid];
|
|
395
|
+
if (!server) {
|
|
396
|
+
return [];
|
|
397
|
+
}
|
|
398
|
+
const { uid: _, ...rest } = server;
|
|
399
|
+
return [rest];
|
|
400
|
+
}),
|
|
401
|
+
paths,
|
|
402
|
+
/**
|
|
403
|
+
* Preserve all component types from the collection and merge with transformed security schemes.
|
|
404
|
+
* OpenAPI components object supports: schemas, responses, parameters, examples,
|
|
405
|
+
* requestBodies, headers, securitySchemes, links, callbacks, pathItems
|
|
406
|
+
*/
|
|
407
|
+
components: {
|
|
408
|
+
// Preserve existing components from the collection (schemas, responses, parameters, etc.)
|
|
409
|
+
...collection.components || {},
|
|
410
|
+
// Merge security schemes (transformed from UIDs) with any existing security schemes
|
|
411
|
+
securitySchemes: {
|
|
412
|
+
...collection.components?.securitySchemes || {},
|
|
413
|
+
...collection.securitySchemes.reduce((acc, uid) => {
|
|
414
|
+
const securityScheme = dataRecords.securitySchemes[uid];
|
|
415
|
+
if (!securityScheme) {
|
|
416
|
+
return acc;
|
|
417
|
+
}
|
|
418
|
+
const { uid: _uid, nameKey: _nameKey, ...publicSecurityScheme } = removeSecretFields(securityScheme);
|
|
419
|
+
if (securityScheme.type === "oauth2") {
|
|
420
|
+
const selectedScopes = /* @__PURE__ */ new Set();
|
|
421
|
+
return {
|
|
422
|
+
...acc,
|
|
423
|
+
[securityScheme.nameKey]: {
|
|
424
|
+
...publicSecurityScheme,
|
|
425
|
+
flows: objectEntries(securityScheme.flows).reduce(
|
|
426
|
+
(acc2, [key, flow]) => {
|
|
427
|
+
if (!flow) {
|
|
428
|
+
return acc2;
|
|
429
|
+
}
|
|
430
|
+
if ("selectedScopes" in flow && Array.isArray(flow.selectedScopes)) {
|
|
431
|
+
flow.selectedScopes?.forEach((scope) => selectedScopes.add(scope));
|
|
432
|
+
}
|
|
433
|
+
acc2[key] = removeSecretFields(flow);
|
|
434
|
+
return acc2;
|
|
435
|
+
},
|
|
436
|
+
{}
|
|
437
|
+
),
|
|
438
|
+
"x-default-scopes": Array.from(selectedScopes)
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
return {
|
|
443
|
+
...acc,
|
|
444
|
+
[securityScheme.nameKey]: publicSecurityScheme
|
|
445
|
+
};
|
|
446
|
+
}, {})
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
security: collection.security || [],
|
|
450
|
+
tags,
|
|
451
|
+
webhooks: collection.webhooks,
|
|
452
|
+
externalDocs: collection.externalDocs,
|
|
453
|
+
"x-scalar-original-document-hash": "",
|
|
454
|
+
// Preserve scalar extensions
|
|
455
|
+
"x-scalar-icon": collection["x-scalar-icon"],
|
|
456
|
+
// Convert legacy record-based environment variables to the new array format
|
|
457
|
+
"x-scalar-environments": transformLegacyEnvironments(collection["x-scalar-environments"]),
|
|
458
|
+
// useCollectionSecurity → x-scalar-set-operation-security
|
|
459
|
+
"x-scalar-set-operation-security": collection.useCollectionSecurity ?? false
|
|
460
|
+
};
|
|
461
|
+
if (tagGroups.length > 0) {
|
|
462
|
+
document["x-tagGroups"] = tagGroups;
|
|
463
|
+
}
|
|
464
|
+
if (collection["x-scalar-active-environment"]) {
|
|
465
|
+
document["x-scalar-client-config-active-environment"] = collection["x-scalar-active-environment"];
|
|
466
|
+
}
|
|
467
|
+
if (selectedServerUrl) {
|
|
468
|
+
document["x-scalar-selected-server"] = selectedServerUrl;
|
|
469
|
+
}
|
|
470
|
+
if (collection.documentUrl) {
|
|
471
|
+
document["x-scalar-original-source-url"] = collection.documentUrl;
|
|
472
|
+
}
|
|
473
|
+
const safeDocument = circularToRefs(document, {
|
|
474
|
+
"$ref-value": "",
|
|
475
|
+
"$global": false,
|
|
476
|
+
"summary": "This ref was re-created from a circular schema reference"
|
|
477
|
+
});
|
|
478
|
+
return {
|
|
479
|
+
document: coerceValue(OpenAPIDocumentSchema, safeDocument),
|
|
480
|
+
auth: coerceValue(AuthSchema, {
|
|
481
|
+
secrets: collection.securitySchemes.reduce((acc, uid) => {
|
|
482
|
+
const securityScheme = dataRecords.securitySchemes[uid];
|
|
483
|
+
if (!securityScheme) {
|
|
484
|
+
return acc;
|
|
485
|
+
}
|
|
486
|
+
if (securityScheme.type === "oauth2") {
|
|
487
|
+
return {
|
|
488
|
+
...acc,
|
|
489
|
+
[securityScheme.nameKey]: {
|
|
490
|
+
type: securityScheme.type,
|
|
491
|
+
...objectEntries(securityScheme.flows).reduce(
|
|
492
|
+
(acc2, [key, flow]) => {
|
|
493
|
+
if (!flow) {
|
|
494
|
+
return acc2;
|
|
495
|
+
}
|
|
496
|
+
acc2[key] = extractConfigSecrets(flow);
|
|
497
|
+
return acc2;
|
|
498
|
+
},
|
|
499
|
+
{}
|
|
500
|
+
)
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
return {
|
|
505
|
+
...acc,
|
|
506
|
+
[securityScheme.nameKey]: {
|
|
507
|
+
type: securityScheme.type,
|
|
508
|
+
...extractConfigSecrets(securityScheme)
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
}, {}),
|
|
512
|
+
selected: {}
|
|
513
|
+
})
|
|
514
|
+
};
|
|
515
|
+
};
|
|
516
|
+
const clearLegacyLocalStorage = () => {
|
|
517
|
+
const keysToRemove = [
|
|
518
|
+
"collection",
|
|
519
|
+
"cookie",
|
|
520
|
+
"environment",
|
|
521
|
+
"requestExample",
|
|
522
|
+
"request",
|
|
523
|
+
"securityScheme",
|
|
524
|
+
"server",
|
|
525
|
+
"tag",
|
|
526
|
+
"workspace",
|
|
527
|
+
DATA_VERSION_LS_LEY
|
|
528
|
+
];
|
|
529
|
+
keysToRemove.forEach((key) => {
|
|
530
|
+
localStorage.removeItem(key);
|
|
531
|
+
});
|
|
532
|
+
console.info("\u{1F9F9} Cleared legacy localStorage data");
|
|
533
|
+
};
|
|
534
|
+
export {
|
|
535
|
+
clearLegacyLocalStorage,
|
|
536
|
+
migrateLocalStorageToIndexDb,
|
|
537
|
+
shouldMigrateToIndexDb,
|
|
538
|
+
transformLegacyDataToWorkspace
|
|
539
|
+
};
|
|
540
|
+
//# sourceMappingURL=migrate-to-indexdb.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/migrations/migrate-to-indexdb.ts"],
|
|
4
|
+
"sourcesContent": ["import { CONTENT_TYPES } from '@scalar/helpers/consts/content-types'\nimport { extractConfigSecrets, removeSecretFields } from '@scalar/helpers/general/extract-config-secrets'\nimport { circularToRefs } from '@scalar/helpers/object/circular-to-refs'\nimport { objectEntries } from '@scalar/helpers/object/object-entries'\nimport type { Oauth2Flow } from '@scalar/types/entities'\nimport { createWorkspaceStore } from '@scalar/workspace-store/client'\nimport { type Auth, AuthSchema } from '@scalar/workspace-store/entities/auth'\nimport { createWorkspaceStorePersistence } from '@scalar/workspace-store/persistence'\nimport {\n type XScalarEnvironments,\n xScalarEnvironmentSchema,\n} from '@scalar/workspace-store/schemas/extensions/document/x-scalar-environments'\nimport { xScalarCookieSchema } from '@scalar/workspace-store/schemas/extensions/general/x-scalar-cookies'\nimport type { XTagGroup } from '@scalar/workspace-store/schemas/extensions/tag'\nimport type { InMemoryWorkspace } from '@scalar/workspace-store/schemas/inmemory-workspace'\nimport { coerceValue } from '@scalar/workspace-store/schemas/typebox-coerce'\nimport {\n OpenAPIDocumentSchema,\n type OpenApiDocument,\n type OperationObject,\n type ParameterObject,\n type ParameterWithContentObject,\n type ParameterWithSchemaObject,\n type PathItemObject,\n type RequestBodyObject,\n type TagObject,\n} from '@scalar/workspace-store/schemas/v3.1/strict/openapi-document'\nimport type { WorkspaceDocument, WorkspaceExtensions, WorkspaceMeta } from '@scalar/workspace-store/schemas/workspace'\nimport { ColorModeSchema } from '@scalar/workspace-store/schemas/workspace'\n\nimport type { RequestParameter } from '@/entities/spec/parameters'\nimport { DATA_VERSION_LS_LEY } from '@/migrations/data-version'\nimport { migrator } from '@/migrations/migrator'\nimport type { v_2_5_0 } from '@/migrations/v-2.5.0/types.generated'\n\n/**\n * Migrates localStorage data to IndexedDB workspace structure.\n *\n * Called early in app initialization (app-state.ts) before workspace data loads.\n * Idempotent and non-destructive - runs when legacy data exists but IndexedDB is empty.\n *\n * Flow:\n * 1. Check if migration needed (has legacy data + IndexedDB is empty)\n * 2. Run existing migrations to get latest data structure\n * 3. Transform to new workspace format\n * 4. Save to IndexedDB\n *\n * Old data is preserved for rollback. Typically completes in < 1 second.\n */\nexport const migrateLocalStorageToIndexDb = async () => {\n const { close, workspace: workspacePersistence } = await createWorkspaceStorePersistence()\n\n try {\n const shouldMigrate = await shouldMigrateToIndexDb(workspacePersistence)\n\n if (!shouldMigrate) {\n console.info('\u2139\uFE0F No migration needed - IndexedDB already has workspaces or no legacy data exists')\n return\n }\n\n console.info('\uD83D\uDE80 Starting migration from localStorage to IndexedDB...')\n\n // Step 1: Run existing migrations to get latest data structure\n const legacyData = migrator()\n\n console.info(\n `\uD83D\uDCE6 Found legacy data: ${legacyData.arrays.workspaces.length} workspace(s), ${legacyData.arrays.collections.length} collection(s)`,\n )\n\n // Step 2: Transform to new workspace structure\n const workspaces = await transformLegacyDataToWorkspace(legacyData)\n\n // Step 3: Save to IndexedDB\n await Promise.all(\n workspaces.map((workspace) =>\n workspacePersistence.setItem(\n { namespace: 'local', slug: workspace.slug },\n {\n name: workspace.name,\n workspace: workspace.workspace,\n teamUid: 'local',\n },\n ),\n ),\n )\n\n console.info(`\u2705 Successfully migrated ${workspaces.length} workspace(s) to IndexedDB`)\n } catch (error) {\n console.error('\u274C Migration failed:', error)\n } finally {\n close()\n }\n}\n\n/**\n * Checks if migration is needed by verifying IndexedDB state and presence of legacy data.\n *\n * Migration is needed when:\n * 1. Legacy data exists in localStorage (workspace, collection, or request keys)\n * 2. AND IndexedDB has no workspaces yet\n *\n * This approach is more reliable than using a flag because:\n * - If IndexedDB is cleared, migration will run again automatically\n * - No risk of flag getting out of sync with actual data state\n * - Handles edge cases like partial migrations or database corruption\n */\nexport const shouldMigrateToIndexDb = async (\n workspacePersistence: Awaited<ReturnType<typeof createWorkspaceStorePersistence>>['workspace'],\n): Promise<boolean> => {\n // Check if there is any old data in localStorage\n const hasLegacyData =\n localStorage.getItem('workspace') !== null ||\n localStorage.getItem('collection') !== null ||\n localStorage.getItem('request') !== null\n\n if (!hasLegacyData) {\n return false\n }\n\n // Check if IndexedDB already has workspaces\n const existingWorkspaces = await workspacePersistence.getAll()\n const hasIndexDbData = existingWorkspaces.length > 0\n\n // Only migrate if we have legacy data but no IndexedDB data\n return !hasIndexDbData\n}\n\n/**\n * Transforms legacy localStorage data into IndexedDB workspace structure.\n *\n * Transformations:\n * - Collections \u2192 Documents (collections were OpenAPI specs)\n * - Environments \u2192 x-scalar-environments in meta\n * - Cookies \u2192 x-scalar-cookies in meta\n * - Workspace properties \u2192 meta extensions (activeEnvironmentId, proxyUrl, themeId)\n *\n * Creates a default workspace if none exist. Falls back to collection uid if info.title is missing.\n */\nexport const transformLegacyDataToWorkspace = async (legacyData: {\n arrays: v_2_5_0['DataArray']\n records: v_2_5_0['DataRecord']\n}) =>\n await Promise.all(\n legacyData.arrays.workspaces.map(async (workspace) => {\n /** Grab auth from the collections */\n const workspaceAuth: InMemoryWorkspace['auth'] = {}\n\n /** Each collection becomes a document in the new system and grab the auth as well */\n const documents: { name: string; document: OpenApiDocument }[] = workspace.collections.flatMap((uid) => {\n const collection = legacyData.records.collections[uid]\n if (!collection) {\n return []\n }\n\n const documentName = collection.info?.title || collection.uid\n const { document, auth } = transformCollectionToDocument(documentName, collection, legacyData.records)\n\n // Normalize document name to match the store (lowercase \"Drafts\" \u2192 \"drafts\")\n const normalizedName = documentName === 'Drafts' ? 'drafts' : documentName\n workspaceAuth[normalizedName] = auth\n\n return { name: normalizedName, document }\n })\n\n const meta: WorkspaceMeta = {}\n const extensions: WorkspaceExtensions = {}\n\n // Add environment\n const environmentEntries = Object.entries(workspace.environments)\n if (environmentEntries.length > 0) {\n extensions['x-scalar-environments'] = {\n default: coerceValue(xScalarEnvironmentSchema, {\n variables: environmentEntries.map(([name, value]) => ({\n name,\n value,\n })),\n }),\n }\n }\n\n // Add cookies to meta\n if (workspace.cookies.length > 0) {\n extensions['x-scalar-cookies'] = workspace.cookies.flatMap((uid) => {\n const cookie = legacyData.records.cookies[uid]\n return cookie ? coerceValue(xScalarCookieSchema, cookie) : []\n })\n }\n\n // Add proxy URL if present\n if (workspace.proxyUrl) {\n meta['x-scalar-active-proxy'] = workspace.proxyUrl\n }\n\n // Add theme if present\n if (workspace.themeId) {\n meta['x-scalar-theme'] = workspace.themeId\n }\n\n // Set color mode\n if (localStorage.getItem('colorMode')) {\n meta['x-scalar-color-mode'] = coerceValue(ColorModeSchema, localStorage.getItem('colorMode'))\n }\n\n const store = createWorkspaceStore({\n meta,\n })\n\n await Promise.all(\n documents.map(async ({ name, document }) => {\n await store.addDocument({\n name,\n document,\n })\n }),\n )\n\n // Load the auth into the store\n store.auth.load(workspaceAuth)\n\n // Load the extensions into the store\n objectEntries(extensions).forEach(([key, value]) => {\n store.update(key, value)\n })\n\n return {\n slug: workspace.uid.toString(), // Convert to string to convert it to a simple string type\n name: workspace.name || 'Untitled Workspace',\n workspace: store.exportWorkspace(),\n }\n }),\n )\n\n/**\n * Converts legacy environment variables from record format to the new array format.\n *\n * Legacy format: { variables: { API_URL: 'https://...', API_KEY: 'secret' } }\n * New format: { variables: [{ name: 'API_URL', value: 'https://...' }, { name: 'API_KEY', value: 'secret' }] }\n */\nconst transformLegacyEnvironments = (\n environments: v_2_5_0['Collection']['x-scalar-environments'],\n): XScalarEnvironments | undefined => {\n const entries = Object.entries(environments || {})\n if (entries.length === 0) {\n return undefined\n }\n\n return Object.fromEntries(\n entries.map(([envName, env]) => [\n envName,\n coerceValue(xScalarEnvironmentSchema, {\n color: env.color,\n variables: Object.entries(env.variables || {}).map(([name, value]) => ({\n name,\n value: typeof value === 'string' ? value : value.default || '',\n })),\n }),\n ]),\n )\n}\n\n/**\n * Transforms legacy requests and request examples into OpenAPI paths.\n *\n * Each request becomes an operation in the paths object.\n * Request examples are merged into parameter examples and request body examples.\n */\nconst transformRequestsToPaths = (\n collection: v_2_5_0['Collection'],\n dataRecords: v_2_5_0['DataRecord'],\n): Record<string, PathItemObject> => {\n const paths = Object.create(null) as Record<string, PathItemObject>\n\n for (const requestUid of collection.requests || []) {\n const request = dataRecords.requests[requestUid]\n if (!request) {\n continue\n }\n\n const {\n path,\n method,\n uid: _uid,\n type: _type,\n selectedServerUid: _selectedServerUid,\n examples,\n servers,\n selectedSecuritySchemeUids: _selectedSecuritySchemeUids,\n parameters = [],\n requestBody,\n ...rest\n } = request\n\n // Initialize path object if it doesn't exist\n if (!paths[path]) {\n paths[path] = {}\n }\n\n /** Start building the OAS operation object */\n const partialOperation: OperationObject = {\n ...rest,\n }\n\n // Get request examples for this request\n const requestExamples = (examples || []).flatMap((exampleUid) => {\n const example = dataRecords.requestExamples[exampleUid]\n return example ? [example] : []\n })\n\n // Merge examples into parameters\n const mergedParameters = mergeExamplesIntoParameters(parameters, requestExamples)\n if (mergedParameters.length > 0) {\n partialOperation.parameters = mergedParameters\n }\n\n // Merge examples into request body\n const mergedRequestBody = mergeExamplesIntoRequestBody(requestBody, requestExamples)\n if (mergedRequestBody) {\n partialOperation.requestBody = mergedRequestBody\n }\n\n // Add server overrides if present\n if (servers && servers.length > 0) {\n partialOperation.servers = servers.flatMap((serverUid) => {\n const server = dataRecords.servers[serverUid]\n if (!server) {\n return []\n }\n const { uid: _, ...rest } = server\n return [rest]\n })\n }\n\n paths[path][method] = partialOperation\n }\n\n return paths\n}\n\n/**\n * The legacy data model uses plural \"headers\"/\"cookies\" for parameter categories,\n * but OpenAPI uses singular \"header\"/\"cookie\" for the `in` field. This mapping\n * normalizes the legacy names to their OpenAPI equivalents.\n */\nconst PARAM_TYPE_TO_IN: Record<string, string> = {\n path: 'path',\n query: 'query',\n headers: 'header',\n cookies: 'cookie',\n}\n\n/**\n * Merges request example values into OpenAPI parameter objects.\n *\n * In the legacy data model, parameter values live on individual RequestExample\n * objects (one per \"example\" tab in the UI). OpenAPI instead stores examples\n * directly on each Parameter object via the `examples` map.\n */\nconst mergeExamplesIntoParameters = (\n parameters: RequestParameter[],\n requestExamples: v_2_5_0['RequestExample'][],\n): ParameterObject[] => {\n /**\n * We track parameters and their collected examples together in a single map\n * keyed by `{in}:{name}` (e.g. \"query:page\") to avoid a second lookup pass.\n */\n const paramEntries = new Map<\n string,\n { param: ParameterObject; examples: Record<string, { value: string; 'x-disabled': boolean }> }\n >()\n\n // Seed with the operation's existing parameters so they are preserved even if\n // no request example references them.\n for (const param of parameters) {\n // Build a type-safe ParameterObject by explicitly mapping properties\n // The old RequestParameter type uses z.unknown() for schema/content/examples,\n // but these values come from validated OpenAPI documents and are already in the correct format.\n // We use type assertions (via unknown) to bridge from the old loose types to the new strict types.\n // This is safe because the data has already been validated by the Zod schema.\n\n // Build either ParameterWithSchemaObject or ParameterWithContentObject\n let paramObject: ParameterObject\n\n // Param with Content Type\n if (param.content && typeof param.content === 'object') {\n paramObject = {\n name: param.name,\n in: param.in,\n required: param.required ?? param.in === 'path',\n deprecated: param.deprecated ?? false,\n content: param.content as ParameterWithContentObject['content'],\n ...(param.description && { description: param.description }),\n } satisfies ParameterWithContentObject\n }\n\n // Param with Schema Type\n else {\n paramObject = {\n name: param.name,\n in: param.in,\n required: param.required ?? param.in === 'path',\n deprecated: param.deprecated ?? false,\n ...(param.description && { description: param.description }),\n ...(param.schema ? { schema: param.schema as ParameterWithSchemaObject['schema'] } : {}),\n ...(param.style && { style: param.style }),\n ...(param.explode !== undefined && { explode: param.explode }),\n ...(param.example !== undefined && { example: param.example }),\n ...(param.examples &&\n typeof param.examples === 'object' && {\n examples: param.examples as ParameterWithSchemaObject['examples'],\n }),\n } satisfies ParameterWithSchemaObject\n }\n\n paramEntries.set(`${param.in}:${param.name}`, {\n param: paramObject,\n examples: {},\n })\n }\n\n const paramTypes = Object.keys(PARAM_TYPE_TO_IN)\n\n for (const requestExample of requestExamples) {\n const exampleName = requestExample.name || 'Example'\n\n for (const paramType of paramTypes) {\n const inValue = PARAM_TYPE_TO_IN[paramType]\n const items = requestExample.parameters?.[paramType as keyof typeof requestExample.parameters] || []\n\n for (const item of items) {\n const key = `${inValue}:${item.key}`\n\n // Lets not save any params without a key\n if (!item.key) {\n continue\n }\n\n const lowerKey = item.key.toLowerCase()\n\n /**\n * Lazily create a parameter stub when one does not already exist\n * Path parameters are always required per the OpenAPI spec\n *\n * We do not add Accept: *\\/*\n * We do not add any Content-Type headers that are auto added in the client\n */\n if (\n !paramEntries.has(key) &&\n (lowerKey !== 'content-type' || !CONTENT_TYPES[item.value as keyof typeof CONTENT_TYPES]) &&\n (lowerKey !== 'accept' || item.value !== '*/*')\n ) {\n paramEntries.set(key, {\n param: {\n name: item.key,\n in: (inValue as ParameterObject['in']) ?? 'query',\n required: inValue === 'path',\n deprecated: false,\n schema: { type: 'string' },\n },\n examples: {},\n })\n }\n\n // We have skipped the content-type or accept headers above\n const param = paramEntries.get(key)\n if (!param) {\n continue\n }\n\n param.examples[exampleName] = {\n value: item.value,\n 'x-disabled': !item.enabled,\n }\n }\n }\n }\n\n // Build the final parameter list, only attaching `examples` when there are any\n return Array.from(paramEntries.values()).map(({ param, examples }) => {\n if (Object.keys(examples).length > 0) {\n ;(param as ParameterWithSchemaObject).examples = examples\n }\n return param\n })\n}\n\n/** Maps legacy raw body encoding names (e.g. \"json\", \"xml\") to their corresponding MIME content types */\nconst RAW_ENCODING_TO_CONTENT_TYPE: Record<string, string> = {\n json: 'application/json',\n xml: 'application/xml',\n yaml: 'application/yaml',\n edn: 'application/edn',\n text: 'text/plain',\n html: 'text/html',\n javascript: 'application/javascript',\n}\n\n/**\n * Extracts the content type and example value from a single request example body.\n *\n * The legacy data model stored body content in one of three shapes:\n * - `raw` \u2014 text-based body with an encoding hint (json, xml, etc.)\n * - `formData` \u2014 key/value pairs with either multipart or URL-encoded encoding\n * - `binary` \u2014 file upload with no inline content\n */\nconst extractBodyExample = (\n body: v_2_5_0['RequestExample']['body'],\n): { contentType: string; value: unknown } | undefined => {\n if (!body?.activeBody) {\n return undefined\n }\n\n // Raw text body \u2014 resolve the short encoding name to a full MIME type\n if (body.activeBody === 'raw' && body.raw) {\n return {\n contentType: RAW_ENCODING_TO_CONTENT_TYPE[body.raw.encoding] || 'text/plain',\n value: body.raw.value,\n }\n }\n\n // Form data \u2014 distinguish between multipart (file uploads) and URL-encoded\n if (body.activeBody === 'formData' && body.formData) {\n return {\n contentType: body.formData.encoding === 'form-data' ? 'multipart/form-data' : 'application/x-www-form-urlencoded',\n value: body.formData.value.flatMap((param) =>\n param.key\n ? {\n name: param.key,\n value: param.value,\n isDisabled: !param.enabled,\n }\n : [],\n ),\n }\n }\n\n // Binary uploads have no inline content to migrate\n if (body.activeBody === 'binary') {\n return { contentType: 'binary', value: {} }\n }\n\n return undefined\n}\n\n/**\n * Merges request examples into request body examples.\n *\n * The v2.5.0 data model stored request examples separately from the\n * operation's requestBody. In the new model, examples live directly inside\n * `requestBody.content[contentType].examples`. This function bridges the two\n * by grouping examples by content type in a single pass and writing them into\n * the requestBody structure.\n *\n * Returns the original requestBody unchanged when no examples have body content.\n */\nconst mergeExamplesIntoRequestBody = (\n requestBody: RequestBodyObject,\n requestExamples: v_2_5_0['RequestExample'][],\n): RequestBodyObject => {\n /**\n * Single pass: extract each example body and bucket it by content type.\n * Using a plain object as the inner value (instead of a nested Map) avoids\n * a second conversion step when assigning to the result.\n */\n const groupedByContentType = new Map<string, Record<string, { value: unknown }>>()\n\n /** We track the selected content type for each example */\n const selectedContentTypes = {} as Record<string, string>\n\n for (const example of requestExamples) {\n const extracted = extractBodyExample(example.body)\n if (!extracted) {\n continue\n }\n\n const name = example.name || 'Example'\n const group = groupedByContentType.get(extracted.contentType)\n\n if (group) {\n group[name] = { value: extracted.value }\n } else {\n groupedByContentType.set(extracted.contentType, { [name]: { value: extracted.value } })\n }\n\n selectedContentTypes[name] = extracted.contentType\n }\n\n // Nothing to merge \u2014 return early so we do not mutate the requestBody\n if (groupedByContentType.size === 0) {\n return requestBody\n }\n\n // Ensure the requestBody and its content map exist before writing\n const result = requestBody ?? {}\n result.content ??= {}\n\n for (const [contentType, examples] of groupedByContentType) {\n result.content[contentType] ??= {}\n result.content[contentType].examples = examples\n }\n\n // Add the x-scalar-selected-content-type mapping\n if (Object.keys(selectedContentTypes).length > 0) {\n result['x-scalar-selected-content-type'] = selectedContentTypes\n }\n\n return result\n}\n\n/**\n * Transforms legacy tags into OpenAPI tags and tag groups.\n *\n * Legacy structure:\n * - Tags can have children (nested tags)\n * - Top-level parent tags become tag groups\n * - Child tags and standalone tags become regular tags\n */\nconst transformLegacyTags = (\n collection: v_2_5_0['Collection'],\n dataRecords: v_2_5_0['DataRecord'],\n): { tags: TagObject[]; tagGroups: Array<{ name: string; tags: string[] }> } => {\n const tags: TagObject[] = []\n const tagGroups: XTagGroup[] = []\n\n /**\n * Identifies which tags are top-level (appear in collection.children).\n * Top-level parent tags become tag groups, others become regular tags.\n */\n const topLevelTagUids = new Set(collection.children.filter((uid) => dataRecords.tags[uid] !== undefined))\n\n /**\n * Identifies which tags have children.\n * Only top-level parent tags become tag groups.\n */\n const parentTagUids = new Set(\n collection.tags.filter((uid) => {\n const tag = dataRecords.tags[uid]\n return tag?.children && tag.children.length > 0\n }),\n )\n\n /**\n * Process each tag to create either a tag group or a regular tag.\n */\n for (const tagUid of collection.tags) {\n const tag = dataRecords.tags[tagUid]\n if (!tag) {\n continue\n }\n\n const isTopLevelParent = topLevelTagUids.has(tagUid) && parentTagUids.has(tagUid)\n\n if (isTopLevelParent) {\n /**\n * Top-level parent tags become tag groups.\n * Resolve child tag names, filtering out any missing children.\n */\n const childTagNames = tag.children\n .map((childUid) => dataRecords.tags[childUid]?.name)\n .filter((name): name is string => name !== undefined)\n\n if (childTagNames.length > 0) {\n tagGroups.push({\n name: tag.name,\n tags: childTagNames,\n })\n }\n } else {\n /**\n * All other tags (child tags and standalone tags) become regular tags.\n * Preserve optional fields from the legacy tag.\n */\n const tagObject: TagObject = { name: tag.name }\n\n if (tag.description) {\n tagObject.description = tag.description\n }\n if (tag.externalDocs) {\n tagObject.externalDocs = tag.externalDocs\n }\n\n tags.push(tagObject)\n }\n }\n\n return { tags, tagGroups }\n}\n\n/** Transforms a collection and everything it includes into a WorkspaceDocument + auth */\nconst transformCollectionToDocument = (\n documentName: string,\n collection: v_2_5_0['Collection'],\n dataRecords: v_2_5_0['DataRecord'],\n): { document: WorkspaceDocument; auth: Auth } => {\n // Resolve selectedServerUid \u2192 server URL for x-scalar-selected-server\n const selectedServerUrl =\n collection.selectedServerUid && dataRecords.servers[collection.selectedServerUid]\n ? dataRecords.servers[collection.selectedServerUid]?.url\n : undefined\n\n // Transform tags: separate parent tags (groups) from child tags\n const { tags, tagGroups } = transformLegacyTags(collection, dataRecords)\n\n // Transform requests into paths\n const paths = transformRequestsToPaths(collection, dataRecords)\n\n const document: Record<string, unknown> = {\n openapi: collection.openapi || '3.1.0',\n info: collection.info || {\n title: documentName,\n version: '1.0',\n },\n servers: collection.servers.flatMap((uid) => {\n const server = dataRecords.servers[uid]\n if (!server) {\n return []\n }\n\n const { uid: _, ...rest } = server\n return [rest]\n }),\n paths,\n /**\n * Preserve all component types from the collection and merge with transformed security schemes.\n * OpenAPI components object supports: schemas, responses, parameters, examples,\n * requestBodies, headers, securitySchemes, links, callbacks, pathItems\n */\n components: {\n // Preserve existing components from the collection (schemas, responses, parameters, etc.)\n ...(collection.components || {}),\n // Merge security schemes (transformed from UIDs) with any existing security schemes\n securitySchemes: {\n ...((collection.components as Record<string, unknown>)?.securitySchemes || {}),\n ...collection.securitySchemes.reduce((acc, uid) => {\n const securityScheme = dataRecords.securitySchemes[uid]\n if (!securityScheme) {\n return acc\n }\n\n const { uid: _uid, nameKey: _nameKey, ...publicSecurityScheme } = removeSecretFields(securityScheme)\n\n // Clean the flows\n if (securityScheme.type === 'oauth2') {\n const selectedScopes = new Set<string>()\n\n return {\n ...acc,\n [securityScheme.nameKey]: {\n ...publicSecurityScheme,\n flows: objectEntries(securityScheme.flows).reduce(\n (acc, [key, flow]) => {\n if (!flow) {\n return acc\n }\n\n // Store any selected scopes from the config\n if ('selectedScopes' in flow && Array.isArray(flow.selectedScopes)) {\n flow.selectedScopes?.forEach((scope) => selectedScopes.add(scope))\n }\n\n acc[key] = removeSecretFields(flow) as Oauth2Flow\n return acc\n },\n {} as Record<string, Oauth2Flow>,\n ),\n 'x-default-scopes': Array.from(selectedScopes),\n },\n }\n }\n\n return {\n ...acc,\n [securityScheme.nameKey]: publicSecurityScheme,\n }\n }, {}),\n },\n },\n security: collection.security || [],\n tags,\n webhooks: collection.webhooks,\n externalDocs: collection.externalDocs,\n 'x-scalar-original-document-hash': '',\n\n // Preserve scalar extensions\n 'x-scalar-icon': collection['x-scalar-icon'],\n\n // Convert legacy record-based environment variables to the new array format\n 'x-scalar-environments': transformLegacyEnvironments(collection['x-scalar-environments']),\n\n // useCollectionSecurity \u2192 x-scalar-set-operation-security\n 'x-scalar-set-operation-security': collection.useCollectionSecurity ?? false,\n }\n\n // Add x-tagGroups if there are any parent tags\n if (tagGroups.length > 0) {\n document['x-tagGroups'] = tagGroups\n }\n\n // x-scalar-active-environment \u2192 x-scalar-client-config-active-environment\n if (collection['x-scalar-active-environment']) {\n document['x-scalar-client-config-active-environment'] = collection['x-scalar-active-environment']\n }\n\n // selectedServerUid \u2192 x-scalar-selected-server (resolved to URL)\n if (selectedServerUrl) {\n document['x-scalar-selected-server'] = selectedServerUrl\n }\n\n // documentUrl \u2192 x-scalar-original-source-url\n if (collection.documentUrl) {\n document['x-scalar-original-source-url'] = collection.documentUrl\n }\n\n // Break any circular JS object references before coercion.\n // The legacy client dereferenced $refs inline, creating circular object graphs\n // that would cause JSON serialization and schema validation to fail.\n const safeDocument = circularToRefs(document, {\n '$ref-value': '',\n '$global': false,\n 'summary': 'This ref was re-created from a circular schema reference',\n })\n\n return {\n document: coerceValue(OpenAPIDocumentSchema, safeDocument),\n auth: coerceValue(AuthSchema, {\n secrets: collection.securitySchemes.reduce((acc, uid) => {\n const securityScheme = dataRecords.securitySchemes[uid]\n if (!securityScheme) {\n return acc\n }\n\n // Oauth 2\n if (securityScheme.type === 'oauth2') {\n return {\n ...acc,\n [securityScheme.nameKey]: {\n type: securityScheme.type,\n ...objectEntries(securityScheme.flows).reduce(\n (acc, [key, flow]) => {\n if (!flow) {\n return acc\n }\n\n acc[key] = extractConfigSecrets(flow)\n return acc\n },\n {} as Record<string, Record<string, string>>,\n ),\n },\n }\n }\n\n // The rest\n return {\n ...acc,\n [securityScheme.nameKey]: {\n type: securityScheme.type,\n ...extractConfigSecrets(securityScheme),\n },\n }\n }, {}),\n selected: {},\n }),\n }\n}\n\n/**\n * Clears legacy localStorage data after successful migration.\n *\n * NOT called automatically - old data is preserved as a safety net for rollback.\n * Call only after migration succeeds and a grace period passes (e.g., 30 days).\n *\n * To rollback: clear IndexedDB and reload - migration will run again automatically.\n */\nexport const clearLegacyLocalStorage = (): void => {\n const keysToRemove = [\n 'collection',\n 'cookie',\n 'environment',\n 'requestExample',\n 'request',\n 'securityScheme',\n 'server',\n 'tag',\n 'workspace',\n DATA_VERSION_LS_LEY,\n ]\n\n keysToRemove.forEach((key) => {\n localStorage.removeItem(key)\n })\n\n console.info('\uD83E\uDDF9 Cleared legacy localStorage data')\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["rest", "acc"]
|
|
7
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { v_2_5_0 } from '../migrations/v-2.5.0/types.generated.js';
|
|
2
2
|
/** Handles all data migrations per entity */
|
|
3
|
-
export declare const migrator: () =>
|
|
3
|
+
export declare const migrator: () => {
|
|
4
|
+
arrays: v_2_5_0["DataArray"];
|
|
5
|
+
records: v_2_5_0["DataRecord"];
|
|
6
|
+
};
|
|
4
7
|
//# sourceMappingURL=migrator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../src/migrations/migrator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAEnE,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,QAAO,OAAO,CAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../src/migrations/migrator.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAEnE,6CAA6C;AAC7C,eAAO,MAAM,QAAQ,QAAO;IAAE,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;CAqDzF,CAAA"}
|
|
@@ -34,18 +34,20 @@ const migrator = () => {
|
|
|
34
34
|
if (semverLessThan(dataVersion, "2.5.0")) {
|
|
35
35
|
data = migrate_v_2_5_0(data);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
return {
|
|
38
|
+
arrays: {
|
|
39
|
+
collections: Object.values(data.collections),
|
|
40
|
+
cookies: Object.values(data.cookies),
|
|
41
|
+
environments: Object.values(data.environments),
|
|
42
|
+
requestExamples: Object.values(data.requestExamples),
|
|
43
|
+
requests: Object.values(data.requests),
|
|
44
|
+
securitySchemes: Object.values(data.securitySchemes),
|
|
45
|
+
servers: Object.values(data.servers),
|
|
46
|
+
tags: Object.values(data.tags),
|
|
47
|
+
workspaces: Object.values(data.workspaces)
|
|
48
|
+
},
|
|
49
|
+
records: data
|
|
47
50
|
};
|
|
48
|
-
return data;
|
|
49
51
|
};
|
|
50
52
|
export {
|
|
51
53
|
migrator
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/migrations/migrator.ts"],
|
|
4
|
-
"sourcesContent": ["import { getLocalStorageVersion, parseLocalStorage } from '@/migrations/local-storage'\nimport { semverLessThan } from '@/migrations/semver'\nimport { migrate_v_2_1_0 } from '@/migrations/v-2.1.0/migration'\nimport { migrate_v_2_2_0 } from '@/migrations/v-2.2.0/migration'\nimport { migrate_v_2_3_0 } from '@/migrations/v-2.3.0/migration'\nimport { migrate_v_2_4_0 } from '@/migrations/v-2.4.0/migration'\nimport { migrate_v_2_5_0 } from '@/migrations/v-2.5.0/migration'\nimport type { v_2_5_0 } from '@/migrations/v-2.5.0/types.generated'\n\n/** Handles all data migrations per entity */\nexport const migrator = (): v_2_5_0['DataArray'] => {\n const dataVersion = getLocalStorageVersion()\n console.info('Data version: ' + dataVersion)\n\n // First we gather all of the old data\n let data = {\n collections: parseLocalStorage('collection'),\n cookies: parseLocalStorage('cookie'),\n environments: parseLocalStorage('environment'),\n requestExamples: parseLocalStorage('requestExample'),\n requests: parseLocalStorage('request'),\n securitySchemes: parseLocalStorage('securityScheme'),\n servers: parseLocalStorage('server'),\n tags: parseLocalStorage('tag'),\n workspaces: parseLocalStorage('workspace'),\n } as any\n\n // 0.0.0 -> 2.1.0 migration\n if (semverLessThan(dataVersion, '2.1.0')) {\n data = migrate_v_2_1_0(data)\n }\n // 2.1.0 -> 2.2.0 migration\n if (semverLessThan(dataVersion, '2.2.0')) {\n data = migrate_v_2_2_0(data)\n }\n // 2.2.0 -> 2.3.0 migration\n if (semverLessThan(dataVersion, '2.3.0')) {\n data = migrate_v_2_3_0(data)\n }\n // 2.3.0 -> 2.4.0 migration\n if (semverLessThan(dataVersion, '2.4.0')) {\n data = migrate_v_2_4_0(data)\n }\n // 2.4.0 -> 2.5.0 migration\n if (semverLessThan(dataVersion, '2.5.0')) {\n data = migrate_v_2_5_0(data)\n }\n\n // Convert to data array\n
|
|
5
|
-
"mappings": "AAAA,SAAS,wBAAwB,yBAAyB;AAC1D,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAIzB,MAAM,WAAW,
|
|
4
|
+
"sourcesContent": ["import { getLocalStorageVersion, parseLocalStorage } from '@/migrations/local-storage'\nimport { semverLessThan } from '@/migrations/semver'\nimport { migrate_v_2_1_0 } from '@/migrations/v-2.1.0/migration'\nimport { migrate_v_2_2_0 } from '@/migrations/v-2.2.0/migration'\nimport { migrate_v_2_3_0 } from '@/migrations/v-2.3.0/migration'\nimport { migrate_v_2_4_0 } from '@/migrations/v-2.4.0/migration'\nimport { migrate_v_2_5_0 } from '@/migrations/v-2.5.0/migration'\nimport type { v_2_5_0 } from '@/migrations/v-2.5.0/types.generated'\n\n/** Handles all data migrations per entity */\nexport const migrator = (): { arrays: v_2_5_0['DataArray']; records: v_2_5_0['DataRecord'] } => {\n const dataVersion = getLocalStorageVersion()\n console.info('Data version: ' + dataVersion)\n\n // First we gather all of the old data\n let data = {\n collections: parseLocalStorage('collection'),\n cookies: parseLocalStorage('cookie'),\n environments: parseLocalStorage('environment'),\n requestExamples: parseLocalStorage('requestExample'),\n requests: parseLocalStorage('request'),\n securitySchemes: parseLocalStorage('securityScheme'),\n servers: parseLocalStorage('server'),\n tags: parseLocalStorage('tag'),\n workspaces: parseLocalStorage('workspace'),\n } as any\n\n // 0.0.0 -> 2.1.0 migration\n if (semverLessThan(dataVersion, '2.1.0')) {\n data = migrate_v_2_1_0(data)\n }\n // 2.1.0 -> 2.2.0 migration\n if (semverLessThan(dataVersion, '2.2.0')) {\n data = migrate_v_2_2_0(data)\n }\n // 2.2.0 -> 2.3.0 migration\n if (semverLessThan(dataVersion, '2.3.0')) {\n data = migrate_v_2_3_0(data)\n }\n // 2.3.0 -> 2.4.0 migration\n if (semverLessThan(dataVersion, '2.4.0')) {\n data = migrate_v_2_4_0(data)\n }\n // 2.4.0 -> 2.5.0 migration\n if (semverLessThan(dataVersion, '2.5.0')) {\n data = migrate_v_2_5_0(data)\n }\n\n // Convert to data array\n return {\n arrays: {\n collections: Object.values(data.collections),\n cookies: Object.values(data.cookies),\n environments: Object.values(data.environments),\n requestExamples: Object.values(data.requestExamples),\n requests: Object.values(data.requests),\n securitySchemes: Object.values(data.securitySchemes),\n servers: Object.values(data.servers),\n tags: Object.values(data.tags),\n workspaces: Object.values(data.workspaces),\n } satisfies v_2_5_0['DataArray'],\n records: data,\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,wBAAwB,yBAAyB;AAC1D,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAChC,SAAS,uBAAuB;AAIzB,MAAM,WAAW,MAAwE;AAC9F,QAAM,cAAc,uBAAuB;AAC3C,UAAQ,KAAK,mBAAmB,WAAW;AAG3C,MAAI,OAAO;AAAA,IACT,aAAa,kBAAkB,YAAY;AAAA,IAC3C,SAAS,kBAAkB,QAAQ;AAAA,IACnC,cAAc,kBAAkB,aAAa;AAAA,IAC7C,iBAAiB,kBAAkB,gBAAgB;AAAA,IACnD,UAAU,kBAAkB,SAAS;AAAA,IACrC,iBAAiB,kBAAkB,gBAAgB;AAAA,IACnD,SAAS,kBAAkB,QAAQ;AAAA,IACnC,MAAM,kBAAkB,KAAK;AAAA,IAC7B,YAAY,kBAAkB,WAAW;AAAA,EAC3C;AAGA,MAAI,eAAe,aAAa,OAAO,GAAG;AACxC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAEA,MAAI,eAAe,aAAa,OAAO,GAAG;AACxC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAEA,MAAI,eAAe,aAAa,OAAO,GAAG;AACxC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAEA,MAAI,eAAe,aAAa,OAAO,GAAG;AACxC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAEA,MAAI,eAAe,aAAa,OAAO,GAAG;AACxC,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AAGA,SAAO;AAAA,IACL,QAAQ;AAAA,MACN,aAAa,OAAO,OAAO,KAAK,WAAW;AAAA,MAC3C,SAAS,OAAO,OAAO,KAAK,OAAO;AAAA,MACnC,cAAc,OAAO,OAAO,KAAK,YAAY;AAAA,MAC7C,iBAAiB,OAAO,OAAO,KAAK,eAAe;AAAA,MACnD,UAAU,OAAO,OAAO,KAAK,QAAQ;AAAA,MACrC,iBAAiB,OAAO,OAAO,KAAK,eAAe;AAAA,MACnD,SAAS,OAAO,OAAO,KAAK,OAAO;AAAA,MACnC,MAAM,OAAO,OAAO,KAAK,IAAI;AAAA,MAC7B,YAAY,OAAO,OAAO,KAAK,UAAU;AAAA,IAC3C;AAAA,IACA,SAAS;AAAA,EACX;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"specification",
|
|
17
17
|
"yaml"
|
|
18
18
|
],
|
|
19
|
-
"version": "0.6.
|
|
19
|
+
"version": "0.6.46",
|
|
20
20
|
"engines": {
|
|
21
21
|
"node": ">=20"
|
|
22
22
|
},
|
|
@@ -90,22 +90,23 @@
|
|
|
90
90
|
"vue": "^3.5.26",
|
|
91
91
|
"yaml": "^2.8.0",
|
|
92
92
|
"zod": "^4.3.5",
|
|
93
|
-
"@scalar/helpers": "0.2.
|
|
94
|
-
"@scalar/json-magic": "0.11.
|
|
95
|
-
"@scalar/object-utils": "1.2.
|
|
96
|
-
"@scalar/openapi-types": "0.5.3",
|
|
93
|
+
"@scalar/helpers": "0.2.15",
|
|
94
|
+
"@scalar/json-magic": "0.11.4",
|
|
95
|
+
"@scalar/object-utils": "1.2.29",
|
|
97
96
|
"@scalar/themes": "0.14.0",
|
|
98
|
-
"@scalar/types": "0.6.
|
|
99
|
-
"@scalar/workspace-store": "0.
|
|
97
|
+
"@scalar/types": "0.6.6",
|
|
98
|
+
"@scalar/workspace-store": "0.34.2",
|
|
99
|
+
"@scalar/openapi-types": "0.5.3"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
|
102
102
|
"@types/node": "^22.19.3",
|
|
103
|
+
"fake-indexeddb": "6.2.3",
|
|
103
104
|
"vite": "^7.3.1",
|
|
104
105
|
"vitest": "4.0.16",
|
|
105
106
|
"zod-to-ts": "github:amritk/zod-to-ts#build",
|
|
106
|
-
"@scalar/openapi-parser": "0.24.10",
|
|
107
107
|
"@scalar/build-tooling": "0.4.1",
|
|
108
|
-
"@scalar/openapi-types": "0.5.3"
|
|
108
|
+
"@scalar/openapi-types": "0.5.3",
|
|
109
|
+
"@scalar/openapi-parser": "0.24.13"
|
|
109
110
|
},
|
|
110
111
|
"scripts": {
|
|
111
112
|
"build": "scalar-build-esbuild",
|