@scalar/workspace-store 0.17.0 → 0.18.0
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 +64 -0
- package/dist/client.d.ts +38 -26
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +286 -84
- package/dist/client.js.map +3 -3
- package/dist/events/bus.d.ts +86 -0
- package/dist/events/bus.d.ts.map +1 -0
- package/dist/events/bus.js +58 -0
- package/dist/events/bus.js.map +7 -0
- package/dist/events/definitions/analytics.d.ts +27 -0
- package/dist/events/definitions/analytics.d.ts.map +1 -0
- package/dist/events/definitions/analytics.js +1 -0
- package/dist/events/definitions/analytics.js.map +7 -0
- package/dist/events/definitions/auth.d.ts +30 -0
- package/dist/events/definitions/auth.d.ts.map +1 -0
- package/dist/events/definitions/auth.js +1 -0
- package/dist/events/definitions/auth.js.map +7 -0
- package/dist/events/definitions/document.d.ts +14 -0
- package/dist/events/definitions/document.d.ts.map +1 -0
- package/dist/events/definitions/document.js +1 -0
- package/dist/events/definitions/document.js.map +7 -0
- package/dist/events/definitions/index.d.ts +10 -0
- package/dist/events/definitions/index.d.ts.map +1 -0
- package/dist/events/definitions/index.js +1 -0
- package/dist/events/definitions/index.js.map +7 -0
- package/dist/events/definitions/meta.d.ts +11 -0
- package/dist/events/definitions/meta.d.ts.map +1 -0
- package/dist/events/definitions/meta.js +1 -0
- package/dist/events/definitions/meta.js.map +7 -0
- package/dist/events/definitions/operation.d.ts +11 -0
- package/dist/events/definitions/operation.d.ts.map +1 -0
- package/dist/events/definitions/operation.js +1 -0
- package/dist/events/definitions/operation.js.map +7 -0
- package/dist/events/definitions/server.d.ts +50 -0
- package/dist/events/definitions/server.d.ts.map +1 -0
- package/dist/events/definitions/server.js +1 -0
- package/dist/events/definitions/server.js.map +7 -0
- package/dist/events/definitions/ui.d.ts +52 -0
- package/dist/events/definitions/ui.d.ts.map +1 -0
- package/dist/events/definitions/ui.js +1 -0
- package/dist/events/definitions/ui.js.map +7 -0
- package/dist/events/index.d.ts +2 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +3 -1
- package/dist/events/index.js.map +2 -2
- package/dist/events/listeners.d.ts +2 -1
- package/dist/events/listeners.d.ts.map +1 -1
- package/dist/events/listeners.js.map +2 -2
- package/dist/events/{definitions.d.ts → old-definitions.d.ts} +35 -11
- package/dist/events/old-definitions.d.ts.map +1 -0
- package/dist/events/{definitions.js → old-definitions.js} +1 -1
- package/dist/events/old-definitions.js.map +7 -0
- package/dist/helpers/debounce.d.ts +28 -0
- package/dist/helpers/debounce.d.ts.map +1 -0
- package/dist/helpers/debounce.js +31 -0
- package/dist/helpers/debounce.js.map +7 -0
- package/dist/helpers/detect-changes-proxy.d.ts +47 -0
- package/dist/helpers/detect-changes-proxy.d.ts.map +1 -0
- package/dist/helpers/detect-changes-proxy.js +59 -0
- package/dist/helpers/detect-changes-proxy.js.map +7 -0
- package/dist/helpers/overrides-proxy.d.ts +17 -6
- package/dist/helpers/overrides-proxy.d.ts.map +1 -1
- package/dist/helpers/overrides-proxy.js +33 -18
- package/dist/helpers/overrides-proxy.js.map +3 -3
- package/dist/helpers/unpack-proxy.d.ts +6 -0
- package/dist/helpers/unpack-proxy.d.ts.map +1 -0
- package/dist/helpers/unpack-proxy.js +9 -0
- package/dist/helpers/unpack-proxy.js.map +7 -0
- package/dist/mutators/request.d.ts +1 -1
- package/dist/mutators/request.d.ts.map +1 -1
- package/dist/mutators/request.js.map +1 -1
- package/dist/navigation/get-navigation-options.d.ts +1 -1
- package/dist/navigation/get-navigation-options.d.ts.map +1 -1
- package/dist/navigation/get-navigation-options.js +66 -54
- package/dist/navigation/get-navigation-options.js.map +2 -2
- package/dist/navigation/helpers/get-tag.d.ts +7 -2
- package/dist/navigation/helpers/get-tag.d.ts.map +1 -1
- package/dist/navigation/helpers/get-tag.js +16 -2
- package/dist/navigation/helpers/get-tag.js.map +2 -2
- package/dist/navigation/helpers/traverse-description.d.ts +7 -2
- package/dist/navigation/helpers/traverse-description.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-description.js +24 -6
- package/dist/navigation/helpers/traverse-description.js.map +2 -2
- package/dist/navigation/helpers/traverse-document.d.ts +5 -2
- package/dist/navigation/helpers/traverse-document.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-document.js +53 -15
- package/dist/navigation/helpers/traverse-document.js.map +2 -2
- package/dist/navigation/helpers/traverse-paths.d.ts +9 -3
- package/dist/navigation/helpers/traverse-paths.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-paths.js +63 -9
- package/dist/navigation/helpers/traverse-paths.js.map +2 -2
- package/dist/navigation/helpers/traverse-schemas.d.ts +7 -8
- package/dist/navigation/helpers/traverse-schemas.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-schemas.js +35 -7
- package/dist/navigation/helpers/traverse-schemas.js.map +2 -2
- package/dist/navigation/helpers/traverse-tags.d.ts +8 -4
- package/dist/navigation/helpers/traverse-tags.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-tags.js +65 -17
- package/dist/navigation/helpers/traverse-tags.js.map +2 -2
- package/dist/navigation/helpers/traverse-webhooks.d.ts +9 -3
- package/dist/navigation/helpers/traverse-webhooks.d.ts.map +1 -1
- package/dist/navigation/helpers/traverse-webhooks.js +43 -17
- package/dist/navigation/helpers/traverse-webhooks.js.map +2 -2
- package/dist/navigation/types.d.ts +5 -24
- package/dist/navigation/types.d.ts.map +1 -1
- package/dist/persistence/index.d.ts +86 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +196 -0
- package/dist/persistence/index.js.map +7 -0
- package/dist/persistence/indexdb.d.ts +87 -0
- package/dist/persistence/indexdb.d.ts.map +1 -0
- package/dist/persistence/indexdb.js +125 -0
- package/dist/persistence/indexdb.js.map +7 -0
- package/dist/{plugins.d.ts → plugins/bundler/index.d.ts} +1 -1
- package/dist/plugins/bundler/index.d.ts.map +1 -0
- package/dist/{plugins.js → plugins/bundler/index.js} +2 -2
- package/dist/{plugins.js.map → plugins/bundler/index.js.map} +1 -1
- package/dist/plugins/client/index.d.ts +3 -0
- package/dist/plugins/client/index.d.ts.map +1 -0
- package/dist/plugins/client/index.js +5 -0
- package/dist/plugins/client/index.js.map +7 -0
- package/dist/plugins/client/persistence.d.ts +13 -0
- package/dist/plugins/client/persistence.d.ts.map +1 -0
- package/dist/plugins/client/persistence.js +57 -0
- package/dist/plugins/client/persistence.js.map +7 -0
- package/dist/schemas/extensions.d.ts +1 -0
- package/dist/schemas/extensions.d.ts.map +1 -1
- package/dist/schemas/extensions.js +1 -0
- package/dist/schemas/extensions.js.map +2 -2
- package/dist/schemas/inmemory-workspace.d.ts +73 -14
- package/dist/schemas/inmemory-workspace.d.ts.map +1 -1
- package/dist/schemas/inmemory-workspace.js +1 -9
- package/dist/schemas/inmemory-workspace.js.map +2 -2
- package/dist/schemas/navigation.d.ts +128 -1
- package/dist/schemas/navigation.d.ts.map +1 -1
- package/dist/schemas/navigation.js +20 -1
- package/dist/schemas/navigation.js.map +2 -2
- package/dist/schemas/reference-config/index.d.ts +233 -200
- package/dist/schemas/reference-config/index.d.ts.map +1 -1
- package/dist/schemas/reference-config/index.js.map +2 -2
- package/dist/schemas/reference-config/settings.d.ts +35 -3
- package/dist/schemas/reference-config/settings.d.ts.map +1 -1
- package/dist/schemas/reference-config/settings.js +1 -1
- package/dist/schemas/reference-config/settings.js.map +1 -1
- package/dist/schemas/v3.1/strict/openapi-document.d.ts +1165 -71
- package/dist/schemas/v3.1/strict/openapi-document.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/openapi-document.js +16 -9
- package/dist/schemas/v3.1/strict/openapi-document.js.map +2 -2
- package/dist/schemas/v3.1/strict/parameter.d.ts +23 -1
- package/dist/schemas/v3.1/strict/parameter.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/parameter.js +5 -1
- package/dist/schemas/v3.1/strict/parameter.js.map +2 -2
- package/dist/schemas/v3.1/strict/ref-definitions.d.ts +2 -0
- package/dist/schemas/v3.1/strict/ref-definitions.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/ref-definitions.js +4 -1
- package/dist/schemas/v3.1/strict/ref-definitions.js.map +2 -2
- package/dist/schemas/v3.1/strict/schema.d.ts +2 -2
- package/dist/schemas/v3.1/strict/schema.d.ts.map +1 -1
- package/dist/schemas/v3.1/strict/schema.js +1 -1
- package/dist/schemas/v3.1/strict/schema.js.map +2 -2
- package/dist/schemas/workspace-specification/config.d.ts +35 -8
- package/dist/schemas/workspace-specification/config.d.ts.map +1 -1
- package/dist/schemas/workspace-specification/config.js.map +1 -1
- package/dist/schemas/workspace-specification/index.d.ts +38 -5
- package/dist/schemas/workspace-specification/index.d.ts.map +1 -1
- package/dist/schemas/workspace-specification/index.js.map +1 -1
- package/dist/schemas/workspace.d.ts +245 -17
- package/dist/schemas/workspace.d.ts.map +1 -1
- package/dist/schemas/workspace.js +3 -1
- package/dist/schemas/workspace.js.map +2 -2
- package/dist/server.d.ts +4 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -6
- package/dist/server.js.map +2 -2
- package/dist/workspace-plugin.d.ts +49 -0
- package/dist/workspace-plugin.d.ts.map +1 -0
- package/dist/workspace-plugin.js +1 -0
- package/dist/workspace-plugin.js.map +7 -0
- package/package.json +22 -10
- package/dist/events/definitions.d.ts.map +0 -1
- package/dist/events/definitions.js.map +0 -7
- package/dist/plugins.d.ts.map +0 -1
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Static, TObject } from '@scalar/typebox';
|
|
2
|
+
type TableEntry<S extends TObject, K extends readonly (keyof Static<S>)[]> = {
|
|
3
|
+
schema: S;
|
|
4
|
+
index: K;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Initializes and manages an IndexedDB database connection for table-based persistence.
|
|
8
|
+
*
|
|
9
|
+
* @param name - The database name. Defaults to 'scalar-workspace-store'.
|
|
10
|
+
* @param tables - Table definitions: the tables to create and their key schemas.
|
|
11
|
+
* @param version - The database version. Bump this to trigger upgrades (default: 1).
|
|
12
|
+
* @param migrations - Optional migration steps to run for version upgrades.
|
|
13
|
+
* @returns An object with the following methods:
|
|
14
|
+
* - `get(tableName)` — Get a wrapper to interact with the object store for the given table name.
|
|
15
|
+
* - `closeDatabase()` — Closes the database connection.
|
|
16
|
+
*
|
|
17
|
+
* Example usage:
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Type } from '@scalar/typebox'
|
|
20
|
+
* import { createIndexDbConnection } from './indexdb.js'
|
|
21
|
+
*
|
|
22
|
+
* // Define a schema for a user
|
|
23
|
+
* const UserSchema = Type.Object({
|
|
24
|
+
* id: Type.String(),
|
|
25
|
+
* name: Type.String(),
|
|
26
|
+
* age: Type.Number(),
|
|
27
|
+
* })
|
|
28
|
+
*
|
|
29
|
+
* // Define tables in the database
|
|
30
|
+
* const dbConfig = {
|
|
31
|
+
* users: {
|
|
32
|
+
* schema: UserSchema,
|
|
33
|
+
* index: ['id'] as const,
|
|
34
|
+
* },
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* // Open the database connection and get table API
|
|
38
|
+
* const { get, closeDatabase } = await createIndexDbConnection({
|
|
39
|
+
* name: 'my-app-db',
|
|
40
|
+
* tables: dbConfig,
|
|
41
|
+
* version: 1,
|
|
42
|
+
* })
|
|
43
|
+
*
|
|
44
|
+
* // Get a strongly-typed users table API
|
|
45
|
+
* const usersTable = get('users')
|
|
46
|
+
*
|
|
47
|
+
* // Add a user
|
|
48
|
+
* await usersTable.addItem({ id: 'user-1' }, { name: 'Alice', age: 25 })
|
|
49
|
+
*
|
|
50
|
+
* // Retrieve a user by id
|
|
51
|
+
* const user = await usersTable.getItem({ id: 'user-1' })
|
|
52
|
+
*
|
|
53
|
+
* // Don't forget to close the database when done!
|
|
54
|
+
* closeDatabase()
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare const createIndexDbConnection: <T extends Record<string, TableEntry<any, readonly (keyof any)[]>>>({ name, tables, version, migrations, }: {
|
|
58
|
+
name: string;
|
|
59
|
+
tables: T;
|
|
60
|
+
version: number;
|
|
61
|
+
migrations?: {
|
|
62
|
+
version: number;
|
|
63
|
+
exec: (db: IDBDatabase, event: IDBVersionChangeEvent) => {};
|
|
64
|
+
}[];
|
|
65
|
+
}) => Promise<{
|
|
66
|
+
get: <Name extends keyof T>(name: Name) => {
|
|
67
|
+
addItem: (key: Record<T[Name]["index"][number], IDBValidKey>, value: Omit<(T[Name]["schema"] & {
|
|
68
|
+
params: [];
|
|
69
|
+
})["static"], T[Name]["index"][number]>) => Promise<(T[Name]["schema"] & {
|
|
70
|
+
params: [];
|
|
71
|
+
})["static"]>;
|
|
72
|
+
getItem: (key: Record<T[Name]["index"][number], IDBValidKey>) => Promise<(T[Name]["schema"] & {
|
|
73
|
+
params: [];
|
|
74
|
+
})["static"] | undefined>;
|
|
75
|
+
getRange: (partialKey: IDBValidKey[]) => Promise<(T[Name]["schema"] & {
|
|
76
|
+
params: [];
|
|
77
|
+
})["static"][]>;
|
|
78
|
+
deleteItem: (key: Record<T[Name]["index"][number], IDBValidKey>) => Promise<void>;
|
|
79
|
+
deleteRange: (partialKey: IDBValidKey[]) => Promise<number>;
|
|
80
|
+
getAll: () => Promise<(T[Name]["schema"] & {
|
|
81
|
+
params: [];
|
|
82
|
+
})["static"][]>;
|
|
83
|
+
};
|
|
84
|
+
closeDatabase: () => void;
|
|
85
|
+
}>;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=indexdb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexdb.d.ts","sourceRoot":"","sources":["../../src/persistence/indexdb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAW,MAAM,iBAAiB,CAAA;AAE/D,KAAK,UAAU,CAAC,CAAC,SAAS,OAAO,EAAE,CAAC,SAAS,SAAS,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI;IAC3E,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,CAAC,CAAA;CACT,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,uBAAuB,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,wCAK9G;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,CAAC,CAAA;IACT,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,CAAC,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,qBAAqB,KAAK,EAAE,CAAA;KAAE,EAAE,CAAA;CAChG;UAgCS,IAAI,SAAS,MAAM,CAAC,QAAQ,IAAI;;;;;;;;;+BA+FV,WAAW,EAAE;;;4EA6Ba,OAAO,CAAC,IAAI,CAAC;kCAmBpC,WAAW,EAAE,KAAG,OAAO,CAAC,MAAM,CAAC;;;;;;EAxIjE,CAAA"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const createIndexDbConnection = async ({
|
|
2
|
+
name = "scalar-workspace-store",
|
|
3
|
+
tables,
|
|
4
|
+
version = 1,
|
|
5
|
+
migrations = []
|
|
6
|
+
}) => {
|
|
7
|
+
const db = indexedDB.open(name, version);
|
|
8
|
+
db.onupgradeneeded = (e) => {
|
|
9
|
+
if (e.oldVersion < 1) {
|
|
10
|
+
const database = db.result;
|
|
11
|
+
Object.entries(tables).forEach(([name2, options]) => {
|
|
12
|
+
if (!database.objectStoreNames.contains(name2)) {
|
|
13
|
+
database.createObjectStore(name2, {
|
|
14
|
+
keyPath: options.index.length === 1 ? options.index[0] : options.index
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
migrations.forEach((migration) => {
|
|
20
|
+
if (e.oldVersion < migration.version) {
|
|
21
|
+
migration.exec(db.result, e);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
await new Promise((resolve, reject) => {
|
|
26
|
+
db.onsuccess = () => resolve(true);
|
|
27
|
+
db.onerror = () => reject(db.error);
|
|
28
|
+
});
|
|
29
|
+
return {
|
|
30
|
+
get: (name2) => {
|
|
31
|
+
return createTableWrapper(name2, db.result);
|
|
32
|
+
},
|
|
33
|
+
closeDatabase: () => {
|
|
34
|
+
db.result.close();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
function createTableWrapper(name, db) {
|
|
39
|
+
const getStore = (mode) => {
|
|
40
|
+
const tx = db.transaction(name, mode);
|
|
41
|
+
return tx.objectStore(name);
|
|
42
|
+
};
|
|
43
|
+
async function addItem(key, value) {
|
|
44
|
+
const store = getStore("readwrite");
|
|
45
|
+
const keyObj = { ...key };
|
|
46
|
+
const finalValue = { ...keyObj, ...value };
|
|
47
|
+
await requestAsPromise(store.put(finalValue));
|
|
48
|
+
return finalValue;
|
|
49
|
+
}
|
|
50
|
+
function getItem(key) {
|
|
51
|
+
const store = getStore("readonly");
|
|
52
|
+
const keyValues = Object.values(key);
|
|
53
|
+
const keyToUse = keyValues.length === 1 ? keyValues[0] : keyValues;
|
|
54
|
+
return requestAsPromise(store.get(keyToUse));
|
|
55
|
+
}
|
|
56
|
+
function getRange(partialKey) {
|
|
57
|
+
const store = getStore("readonly");
|
|
58
|
+
const results = [];
|
|
59
|
+
const upperBound = [...partialKey];
|
|
60
|
+
upperBound.push([]);
|
|
61
|
+
const range = IDBKeyRange.bound(partialKey, upperBound, false, true);
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
const request = store.openCursor(range);
|
|
64
|
+
request.onerror = () => reject(request.error);
|
|
65
|
+
request.onsuccess = (event) => {
|
|
66
|
+
const cursor = event.target.result;
|
|
67
|
+
if (cursor) {
|
|
68
|
+
results.push(cursor.value);
|
|
69
|
+
cursor.continue();
|
|
70
|
+
} else {
|
|
71
|
+
resolve(results);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function deleteItem(key) {
|
|
77
|
+
const store = getStore("readwrite");
|
|
78
|
+
const keyValues = Object.values(key);
|
|
79
|
+
const keyToUse = keyValues.length === 1 ? keyValues[0] : keyValues;
|
|
80
|
+
await requestAsPromise(store.delete(keyToUse));
|
|
81
|
+
}
|
|
82
|
+
function deleteRange(partialKey) {
|
|
83
|
+
const store = getStore("readwrite");
|
|
84
|
+
let deletedCount = 0;
|
|
85
|
+
const upperBound = [...partialKey];
|
|
86
|
+
upperBound.push([]);
|
|
87
|
+
const range = IDBKeyRange.bound(partialKey, upperBound, false, true);
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const request = store.openCursor(range);
|
|
90
|
+
request.onerror = () => reject(request.error);
|
|
91
|
+
request.onsuccess = (event) => {
|
|
92
|
+
const cursor = event.target.result;
|
|
93
|
+
if (cursor) {
|
|
94
|
+
cursor.delete();
|
|
95
|
+
deletedCount++;
|
|
96
|
+
cursor.continue();
|
|
97
|
+
} else {
|
|
98
|
+
resolve(deletedCount);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function getAll() {
|
|
104
|
+
const store = getStore("readonly");
|
|
105
|
+
return requestAsPromise(store.getAll());
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
addItem,
|
|
109
|
+
getItem,
|
|
110
|
+
getRange,
|
|
111
|
+
deleteItem,
|
|
112
|
+
deleteRange,
|
|
113
|
+
getAll
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function requestAsPromise(req) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
req.onsuccess = () => resolve(req.result);
|
|
119
|
+
req.onerror = () => reject(req.error);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
export {
|
|
123
|
+
createIndexDbConnection
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=indexdb.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/persistence/indexdb.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Static, TObject, TRecord } from '@scalar/typebox'\n\ntype TableEntry<S extends TObject, K extends readonly (keyof Static<S>)[]> = {\n schema: S\n index: K\n}\n\n/**\n * Initializes and manages an IndexedDB database connection for table-based persistence.\n *\n * @param name - The database name. Defaults to 'scalar-workspace-store'.\n * @param tables - Table definitions: the tables to create and their key schemas.\n * @param version - The database version. Bump this to trigger upgrades (default: 1).\n * @param migrations - Optional migration steps to run for version upgrades.\n * @returns An object with the following methods:\n * - `get(tableName)` \u2014 Get a wrapper to interact with the object store for the given table name.\n * - `closeDatabase()` \u2014 Closes the database connection.\n *\n * Example usage:\n * ```ts\n * import { Type } from '@scalar/typebox'\n * import { createIndexDbConnection } from './indexdb'\n *\n * // Define a schema for a user\n * const UserSchema = Type.Object({\n * id: Type.String(),\n * name: Type.String(),\n * age: Type.Number(),\n * })\n *\n * // Define tables in the database\n * const dbConfig = {\n * users: {\n * schema: UserSchema,\n * index: ['id'] as const,\n * },\n * }\n *\n * // Open the database connection and get table API\n * const { get, closeDatabase } = await createIndexDbConnection({\n * name: 'my-app-db',\n * tables: dbConfig,\n * version: 1,\n * })\n *\n * // Get a strongly-typed users table API\n * const usersTable = get('users')\n *\n * // Add a user\n * await usersTable.addItem({ id: 'user-1' }, { name: 'Alice', age: 25 })\n *\n * // Retrieve a user by id\n * const user = await usersTable.getItem({ id: 'user-1' })\n *\n * // Don't forget to close the database when done!\n * closeDatabase()\n * ```\n */\nexport const createIndexDbConnection = async <T extends Record<string, TableEntry<any, readonly (keyof any)[]>>>({\n name = 'scalar-workspace-store',\n tables,\n version = 1,\n migrations = [],\n}: {\n name: string\n tables: T\n version: number\n migrations?: { version: number; exec: (db: IDBDatabase, event: IDBVersionChangeEvent) => {} }[]\n}) => {\n const db = indexedDB.open(name, version)\n\n db.onupgradeneeded = (e) => {\n // Initial setup of object stores\n if (e.oldVersion < 1) {\n const database = db.result\n\n // Initialize all the tables\n Object.entries(tables).forEach(([name, options]) => {\n if (!database.objectStoreNames.contains(name)) {\n database.createObjectStore(name, {\n keyPath: options.index.length === 1 ? (options.index[0] as string) : (options.index as string[]),\n })\n }\n })\n }\n\n // Run any future migrations here\n migrations.forEach((migration) => {\n if (e.oldVersion < migration.version) {\n migration.exec(db.result, e)\n }\n })\n }\n\n await new Promise((resolve, reject) => {\n db.onsuccess = () => resolve(true)\n db.onerror = () => reject(db.error)\n })\n\n return {\n get: <Name extends keyof T>(name: Name) => {\n return createTableWrapper<T[Name]['schema'], T[Name]['index'][number]>(name as string, db.result)\n },\n closeDatabase: () => {\n db.result.close()\n },\n }\n}\n\n/**\n * Utility wrapper for interacting with an IndexedDB object store, typed by the schema.\n *\n * Usage example:\n * ```\n * // Define a TypeBox schema for users\n * const UserSchema = Type.Object({\n * id: Type.String(),\n * name: Type.String(),\n * age: Type.Number(),\n * })\n * \n * // Open or create the users table\n * const usersTable = createTableWrapper<typeof UserSchema, 'id'>('users', openDatabase)\n * \n * // Add a user\n await usersTable.addItem({ id: 'user-1' }, { name: 'Alice', age: 24 })\n * \n * // Get a user by id\n * const alic = await usersTable.getItem({ id: 'user-1' })\n * \n * // Get users with a partial key (use [] if no composite key)\n * const users = await usersTable.getRange(['user-1'])\n * \n * // Get all users\n * const allUsers = await usersTable.getAll()\n * ```\n *\n * @template T TypeBox schema type for objects in the store\n * @template K Key property names that compose the primary key\n *\n * @param name - Object store name\n * @param getDb - Function returning a Promise for the IDBDatabase\n * @returns Methods to interact with the object store\n */\nfunction createTableWrapper<T extends TRecord | TObject, const K extends keyof Static<T>>(\n name: string,\n db: IDBDatabase,\n) {\n /**\n * Gets the object store from the latest DB connection, for the given transaction mode.\n */\n const getStore = (mode: IDBTransactionMode): IDBObjectStore => {\n const tx = db.transaction(name, mode)\n return tx.objectStore(name)\n }\n\n /**\n * Adds or updates an item in the store.\n * @param key - The primary key values, as { key1, key2 }\n * @param value - The value for the other properties, omitting keys\n * @returns The full inserted/updated object\n */\n async function addItem(key: Record<K, IDBValidKey>, value: Omit<Static<T>, K>): Promise<Static<T>> {\n const store = getStore('readwrite')\n const keyObj: any = { ...key }\n const finalValue = { ...keyObj, ...value }\n await requestAsPromise(store.put(finalValue))\n\n return finalValue\n }\n\n /**\n * Retrieves a single item by composite key.\n * @param key - Key values. For a single key: { id: '...' }\n * @returns The found object or undefined\n */\n function getItem(key: Record<K, IDBValidKey>): Promise<Static<T> | undefined> {\n const store = getStore('readonly')\n const keyValues = Object.values(key)\n // For single keys, pass value directly; for compound keys, pass array\n const keyToUse = keyValues.length === 1 ? keyValues[0] : keyValues\n return requestAsPromise(store.get(keyToUse as IDBValidKey))\n }\n\n /**\n * Returns all records matching a partial (prefix) key. Use for composite keys.\n * For non-compound keys, pass single-element array: getRange(['some-id'])\n * For prefix search, pass subset of key parts.\n * @param partialKey - Array of partial key values\n * @returns Matching objects\n *\n * Example (composite [a,b]):\n * getRange(['foo']) // All with a === 'foo'\n * getRange(['foo', 'bar']) // All with a === 'foo' and b === 'bar'\n */\n function getRange(partialKey: IDBValidKey[]): Promise<Static<T>[]> {\n const store = getStore('readonly')\n const results: Static<T>[] = []\n\n // Construct upper bound to match all keys starting with partialKey\n const upperBound = [...partialKey]\n upperBound.push([]) // ensures upper bound includes all keys with this prefix\n const range = IDBKeyRange.bound(partialKey, upperBound, false, true)\n\n return new Promise((resolve, reject) => {\n const request = store.openCursor(range)\n request.onerror = () => reject(request.error)\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result\n if (cursor) {\n results.push(cursor.value)\n cursor.continue()\n } else {\n resolve(results)\n }\n }\n })\n }\n\n /**\n * Deletes an item from the store by its composite key.\n * @param key - Key values. For a single key: { id: '...' }\n * @returns void\n */\n async function deleteItem(key: Record<K, IDBValidKey>): Promise<void> {\n const store = getStore('readwrite')\n const keyValues = Object.values(key)\n // For single keys, pass value directly; for compound keys, pass array\n const keyToUse = keyValues.length === 1 ? keyValues[0] : keyValues\n await requestAsPromise(store.delete(keyToUse as IDBValidKey))\n }\n\n /**\n * Deletes all records matching a partial (prefix) key. Use for composite keys.\n * For non-compound keys, pass single-element array: deleteRange(['some-id'])\n * For prefix deletion, pass subset of key parts.\n * @param partialKey - Array of partial key values\n * @returns Number of deleted items\n *\n * Example (composite [a,b]):\n * deleteRange(['foo']) // Delete all with a === 'foo'\n * deleteRange(['foo', 'bar']) // Delete all with a === 'foo' and b === 'bar'\n */\n function deleteRange(partialKey: IDBValidKey[]): Promise<number> {\n const store = getStore('readwrite')\n let deletedCount = 0\n\n // Construct upper bound to match all keys starting with partialKey\n const upperBound = [...partialKey]\n upperBound.push([]) // ensures upper bound includes all keys with this prefix\n const range = IDBKeyRange.bound(partialKey, upperBound, false, true)\n\n return new Promise((resolve, reject) => {\n const request = store.openCursor(range)\n request.onerror = () => reject(request.error)\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result\n if (cursor) {\n cursor.delete()\n deletedCount++\n cursor.continue()\n } else {\n resolve(deletedCount)\n }\n }\n })\n }\n\n /**\n * Retrieves all items from the table.\n * @returns Array of all objects in the store\n */\n function getAll(): Promise<Static<T>[]> {\n const store = getStore('readonly')\n return requestAsPromise(store.getAll())\n }\n\n return {\n addItem,\n getItem,\n getRange,\n deleteItem,\n deleteRange,\n getAll,\n }\n}\n\n// ---- Utility ----\nfunction requestAsPromise<T>(req: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n req.onsuccess = () => resolve(req.result)\n req.onerror = () => reject(req.error)\n })\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["name"]
|
|
7
|
+
}
|
|
@@ -58,4 +58,4 @@ export declare const refsEverywhere: () => LifecyclePlugin;
|
|
|
58
58
|
* @returns {LifecyclePlugin} The plugin object for use in the bundler.
|
|
59
59
|
*/
|
|
60
60
|
export declare const restoreOriginalRefs: () => LifecyclePlugin;
|
|
61
|
-
//# sourceMappingURL=
|
|
61
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/bundler/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAIhE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,QAAO,eAahC,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,QAAO,eA+BxC,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,QAAO,eAwCjC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,mBAAmB,QAAO,eAuBtC,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isLocalRef } from "
|
|
1
|
+
import { isLocalRef } from "../../helpers/general.js";
|
|
2
2
|
const loadingStatus = () => {
|
|
3
3
|
return {
|
|
4
4
|
type: "lifecycle",
|
|
@@ -86,4 +86,4 @@ export {
|
|
|
86
86
|
refsEverywhere,
|
|
87
87
|
restoreOriginalRefs
|
|
88
88
|
};
|
|
89
|
-
//# sourceMappingURL=
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["
|
|
3
|
+
"sources": ["../../../src/plugins/bundler/index.ts"],
|
|
4
4
|
"sourcesContent": ["/**\n * This file contains a collection of plugins used for the bundler.\n * Plugins defined here can extend or modify the behavior of the bundling process,\n * such as adding lifecycle hooks or custom processing logic.\n */\n\nimport type { LifecyclePlugin } from '@scalar/json-magic/bundle'\n\nimport { isLocalRef } from '@/helpers/general'\n\n/**\n * A lifecycle plugin that adds a `$status` property to nodes during resolution.\n * - Sets `$status` to 'loading' when resolution starts.\n * - Sets `$status` to 'error' if resolution fails.\n * - Removes `$status` when resolution succeeds.\n */\nexport const loadingStatus = (): LifecyclePlugin => {\n return {\n type: 'lifecycle',\n onResolveStart: (node) => {\n node['$status'] = 'loading'\n },\n onResolveError: (node) => {\n node['$status'] = 'error'\n },\n onResolveSuccess: (node) => {\n delete node['$status']\n },\n }\n}\n\n/**\n * Lifecycle plugin to resolve and embed external content referenced by an 'externalValue' property in a node.\n *\n * When a node contains an 'externalValue' property (as a string), this plugin will:\n * - Fetch the external resource (such as a URL or file) using the fetchUrls plugin.\n * - If the fetch is successful, assign the fetched data to the node's 'value' property.\n *\n * This is useful for inlining external content (like examples or schemas) into the OpenAPI document during bundling.\n *\n * @param node - The node being processed, which may contain an 'externalValue' property.\n */\nexport const externalValueResolver = (): LifecyclePlugin => {\n return {\n type: 'lifecycle',\n onAfterNodeProcess: async (node, context) => {\n const externalValue = node['externalValue']\n const cache = context.resolutionCache\n\n // Only process if 'externalValue' is a string\n if (typeof externalValue !== 'string') {\n return\n }\n\n const loader = context.loaders.find((it) => it.validate(externalValue))\n\n // We can not process the external value\n if (!loader) {\n return\n }\n\n if (!cache.has(externalValue)) {\n cache.set(externalValue, loader.exec(externalValue))\n }\n\n const result = await cache.get(externalValue)\n\n // If fetch is successful, assign the data to the node's 'value' property\n if (result?.ok) {\n node['value'] = result.data\n }\n },\n }\n}\n\n/**\n * Lifecycle plugin to resolve $ref on any object, including non-standard locations like the info object.\n *\n * This plugin will:\n * - Detect if a node contains a $ref property (as a string).\n * - If the node is under the 'info' path, attempt to resolve the reference using fetchUrls.\n * - Replace the node's properties with the resolved data if successful.\n *\n * Note: This currently only supports refs on the 'info' object and does not handle primitive types.\n */\nexport const refsEverywhere = (): LifecyclePlugin => {\n return {\n type: 'lifecycle',\n onBeforeNodeProcess: async (node, context) => {\n const { path, resolutionCache, parentNode } = context\n const ref = node['$ref']\n\n // Only process nodes that have a $ref property as a string\n if (typeof ref !== 'string') {\n return\n }\n\n // Can not resolve top level refs\n if (!parentNode || !path.length) {\n return\n }\n\n const loader = context.loaders.find((it) => it.validate(ref))\n\n // Can not load the external ref\n if (!loader) {\n return\n }\n\n // Support resolving $ref on the info object\n if (path[0] === 'info') {\n // Use the cache to avoid duplicate fetches\n if (!resolutionCache.has(ref)) {\n resolutionCache.set(ref, loader.exec(ref))\n }\n\n const result = await resolutionCache.get(ref)\n\n if (result?.ok) {\n // Replace the ref with the resolved data\n parentNode[path.at(-1)!] = result.data\n }\n }\n },\n }\n}\n\n/**\n * Lifecycle plugin to restore original $ref values after processing.\n *\n * This plugin is intended to be used as a \"lifecycle\" plugin in the bundling process.\n * It operates in the `onAfterNodeProcess` hook, and its main purpose is to restore\n * the original $ref values for external references that may have been replaced or\n * rewritten during the bundling process.\n *\n * How it works:\n * - For each node processed, if the node contains a $ref property (as a string),\n * and the root document contains an \"x-ext-urls\" mapping object,\n * the plugin will attempt to restore the original $ref value.\n * - The \"x-ext-urls\" object is expected to be a mapping from the rewritten $ref\n * (e.g., a hashed or compressed reference) back to the original external URL or path.\n * - If a mapping exists for the current $ref, the plugin replaces the $ref value\n * with the original value from the mapping. If no mapping exists (e.g., for local refs),\n * the $ref value is left unchanged.\n *\n * This is useful for scenarios where you want to present or export the bundled document\n * with the original external $ref values, rather than the internal or rewritten ones.\n *\n * @returns {LifecyclePlugin} The plugin object for use in the bundler.\n */\nexport const restoreOriginalRefs = (): LifecyclePlugin => {\n return {\n type: 'lifecycle',\n onBeforeNodeProcess: (node, context) => {\n const ref = node['$ref']\n const root = context.rootNode\n const extUrls = root['x-ext-urls']\n\n // Only process if $ref is a string and x-ext-urls is a valid object\n if (typeof ref !== 'string' || typeof extUrls !== 'object' || extUrls === null || !isLocalRef(ref)) {\n return\n }\n\n // Working with local refs\n\n const segments = ref.split('/')\n const key = segments.at(-1) ?? ''\n\n // Replace the $ref with the original version from the mapping,\n // or keep the current version if there is no mapping (e.g., for local refs)\n node['$ref'] = (extUrls as Record<string, string>)[key] ?? ref\n },\n }\n}\n"],
|
|
5
5
|
"mappings": "AAQA,SAAS,kBAAkB;AAQpB,MAAM,gBAAgB,MAAuB;AAClD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,gBAAgB,CAAC,SAAS;AACxB,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA,IACA,gBAAgB,CAAC,SAAS;AACxB,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA,IACA,kBAAkB,CAAC,SAAS;AAC1B,aAAO,KAAK,SAAS;AAAA,IACvB;AAAA,EACF;AACF;AAaO,MAAM,wBAAwB,MAAuB;AAC1D,SAAO;AAAA,IACL,MAAM;AAAA,IACN,oBAAoB,OAAO,MAAM,YAAY;AAC3C,YAAM,gBAAgB,KAAK,eAAe;AAC1C,YAAM,QAAQ,QAAQ;AAGtB,UAAI,OAAO,kBAAkB,UAAU;AACrC;AAAA,MACF;AAEA,YAAM,SAAS,QAAQ,QAAQ,KAAK,CAAC,OAAO,GAAG,SAAS,aAAa,CAAC;AAGtE,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AAEA,UAAI,CAAC,MAAM,IAAI,aAAa,GAAG;AAC7B,cAAM,IAAI,eAAe,OAAO,KAAK,aAAa,CAAC;AAAA,MACrD;AAEA,YAAM,SAAS,MAAM,MAAM,IAAI,aAAa;AAG5C,UAAI,QAAQ,IAAI;AACd,aAAK,OAAO,IAAI,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;AAYO,MAAM,iBAAiB,MAAuB;AACnD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,qBAAqB,OAAO,MAAM,YAAY;AAC5C,YAAM,EAAE,MAAM,iBAAiB,WAAW,IAAI;AAC9C,YAAM,MAAM,KAAK,MAAM;AAGvB,UAAI,OAAO,QAAQ,UAAU;AAC3B;AAAA,MACF;AAGA,UAAI,CAAC,cAAc,CAAC,KAAK,QAAQ;AAC/B;AAAA,MACF;AAEA,YAAM,SAAS,QAAQ,QAAQ,KAAK,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC;AAG5D,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AAGA,UAAI,KAAK,CAAC,MAAM,QAAQ;AAEtB,YAAI,CAAC,gBAAgB,IAAI,GAAG,GAAG;AAC7B,0BAAgB,IAAI,KAAK,OAAO,KAAK,GAAG,CAAC;AAAA,QAC3C;AAEA,cAAM,SAAS,MAAM,gBAAgB,IAAI,GAAG;AAE5C,YAAI,QAAQ,IAAI;AAEd,qBAAW,KAAK,GAAG,EAAE,CAAE,IAAI,OAAO;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAyBO,MAAM,sBAAsB,MAAuB;AACxD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,qBAAqB,CAAC,MAAM,YAAY;AACtC,YAAM,MAAM,KAAK,MAAM;AACvB,YAAM,OAAO,QAAQ;AACrB,YAAM,UAAU,KAAK,YAAY;AAGjC,UAAI,OAAO,QAAQ,YAAY,OAAO,YAAY,YAAY,YAAY,QAAQ,CAAC,WAAW,GAAG,GAAG;AAClG;AAAA,MACF;AAIA,YAAM,WAAW,IAAI,MAAM,GAAG;AAC9B,YAAM,MAAM,SAAS,GAAG,EAAE,KAAK;AAI/B,WAAK,MAAM,IAAK,QAAmC,GAAG,KAAK;AAAA,IAC7D;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/client/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/plugins/client/index.ts"],
|
|
4
|
+
"sourcesContent": ["/** biome-ignore-all lint/performance/noBarrelFile: Plugins entry point */\nexport { persistencePlugin } from './persistence'\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,yBAAyB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WorkspacePlugin } from '../../workspace-plugin.js';
|
|
2
|
+
/**
|
|
3
|
+
* Plugin to persist workspace state changes with debounced writes.
|
|
4
|
+
* Each type of change (meta, documentConfigs, documents, etc.) is debounced by key (type + workspaceId + optional documentName).
|
|
5
|
+
* The debounce delay can be customized, defaults to 500ms.
|
|
6
|
+
*
|
|
7
|
+
* This avoids excessive writes to IndexedDB or other persistence layer when changes occur rapidly.
|
|
8
|
+
*/
|
|
9
|
+
export declare const persistencePlugin: ({ workspaceId, debounceDelay, }: {
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
debounceDelay?: number;
|
|
12
|
+
}) => Promise<WorkspacePlugin>;
|
|
13
|
+
//# sourceMappingURL=persistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../../../src/plugins/client/persistence.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAEzD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAAU,iCAGrC;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,KAAG,OAAO,CAAC,eAAe,CA0D1B,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { debounce } from "../../helpers/debounce.js";
|
|
2
|
+
import { createWorkspaceStorePersistence } from "../../persistence/index.js";
|
|
3
|
+
const persistencePlugin = async ({
|
|
4
|
+
workspaceId,
|
|
5
|
+
debounceDelay
|
|
6
|
+
}) => {
|
|
7
|
+
const persistence = await createWorkspaceStorePersistence();
|
|
8
|
+
const { execute } = debounce({ delay: debounceDelay ?? 500 });
|
|
9
|
+
return {
|
|
10
|
+
hooks: {
|
|
11
|
+
/**
|
|
12
|
+
* Handles all workspace state change events.
|
|
13
|
+
* Each write is debounced by a composite key to prevent frequent writes for the same entity.
|
|
14
|
+
*/
|
|
15
|
+
onWorkspaceStateChanges(event) {
|
|
16
|
+
if (event.type === "meta") {
|
|
17
|
+
return execute(["meta", workspaceId], () => persistence.meta.setItem(workspaceId, event.value));
|
|
18
|
+
}
|
|
19
|
+
if (event.type === "documentConfigs") {
|
|
20
|
+
return execute(
|
|
21
|
+
["documentConfigs", workspaceId, event.documentName],
|
|
22
|
+
() => persistence.documentConfigs.setItem(workspaceId, event.documentName, event.value)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (event.type === "documents") {
|
|
26
|
+
return execute(
|
|
27
|
+
["documents", workspaceId, event.documentName],
|
|
28
|
+
() => persistence.documents.setItem(workspaceId, event.documentName, event.value)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
if (event.type === "intermediateDocuments") {
|
|
32
|
+
return execute(
|
|
33
|
+
["intermediateDocuments", workspaceId, event.documentName],
|
|
34
|
+
() => persistence.intermediateDocuments.setItem(workspaceId, event.documentName, event.value)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
if (event.type === "originalDocuments") {
|
|
38
|
+
return execute(
|
|
39
|
+
["originalDocuments", workspaceId, event.documentName],
|
|
40
|
+
() => persistence.originalDocuments.setItem(workspaceId, event.documentName, event.value)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
if (event.type === "overrides") {
|
|
44
|
+
return execute(
|
|
45
|
+
["overrides", workspaceId, event.documentName],
|
|
46
|
+
() => persistence.overrides.setItem(workspaceId, event.documentName, event.value)
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export {
|
|
55
|
+
persistencePlugin
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=persistence.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/plugins/client/persistence.ts"],
|
|
4
|
+
"sourcesContent": ["import { debounce } from '@/helpers/debounce'\nimport { createWorkspaceStorePersistence } from '@/persistence'\nimport type { WorkspacePlugin } from '@/workspace-plugin'\n\n/**\n * Plugin to persist workspace state changes with debounced writes.\n * Each type of change (meta, documentConfigs, documents, etc.) is debounced by key (type + workspaceId + optional documentName).\n * The debounce delay can be customized, defaults to 500ms.\n *\n * This avoids excessive writes to IndexedDB or other persistence layer when changes occur rapidly.\n */\nexport const persistencePlugin = async ({\n workspaceId,\n debounceDelay,\n}: {\n workspaceId: string\n debounceDelay?: number\n}): Promise<WorkspacePlugin> => {\n // Create the persistence instance (e.g., IndexedDB, localForage, etc.)\n const persistence = await createWorkspaceStorePersistence()\n // Debounced execute function for batching similar state changes\n const { execute } = debounce({ delay: debounceDelay ?? 500 })\n\n return {\n hooks: {\n /**\n * Handles all workspace state change events.\n * Each write is debounced by a composite key to prevent frequent writes for the same entity.\n */\n onWorkspaceStateChanges(event) {\n // If the event is for workspace meta data, debounce by workspaceId\n if (event.type === 'meta') {\n return execute(['meta', workspaceId], () => persistence.meta.setItem(workspaceId, event.value))\n }\n\n // Debounce per document config and workspace\n if (event.type === 'documentConfigs') {\n return execute(['documentConfigs', workspaceId, event.documentName], () =>\n persistence.documentConfigs.setItem(workspaceId, event.documentName, event.value),\n )\n }\n\n // Debounce per document content and workspace\n if (event.type === 'documents') {\n return execute(['documents', workspaceId, event.documentName], () =>\n persistence.documents.setItem(workspaceId, event.documentName, event.value),\n )\n }\n\n // Debounce per intermediate document and workspace\n if (event.type === 'intermediateDocuments') {\n return execute(['intermediateDocuments', workspaceId, event.documentName], () =>\n persistence.intermediateDocuments.setItem(workspaceId, event.documentName, event.value),\n )\n }\n\n // Debounce per original document and workspace\n if (event.type === 'originalDocuments') {\n return execute(['originalDocuments', workspaceId, event.documentName], () =>\n persistence.originalDocuments.setItem(workspaceId, event.documentName, event.value),\n )\n }\n\n // Debounce per document override and workspace\n if (event.type === 'overrides') {\n return execute(['overrides', workspaceId, event.documentName], () =>\n persistence.overrides.setItem(workspaceId, event.documentName, event.value),\n )\n }\n\n // No action for other event types\n return\n },\n },\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,gBAAgB;AACzB,SAAS,uCAAuC;AAUzC,MAAM,oBAAoB,OAAO;AAAA,EACtC;AAAA,EACA;AACF,MAGgC;AAE9B,QAAM,cAAc,MAAM,gCAAgC;AAE1D,QAAM,EAAE,QAAQ,IAAI,SAAS,EAAE,OAAO,iBAAiB,IAAI,CAAC;AAE5D,SAAO;AAAA,IACL,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,MAKL,wBAAwB,OAAO;AAE7B,YAAI,MAAM,SAAS,QAAQ;AACzB,iBAAO,QAAQ,CAAC,QAAQ,WAAW,GAAG,MAAM,YAAY,KAAK,QAAQ,aAAa,MAAM,KAAK,CAAC;AAAA,QAChG;AAGA,YAAI,MAAM,SAAS,mBAAmB;AACpC,iBAAO;AAAA,YAAQ,CAAC,mBAAmB,aAAa,MAAM,YAAY;AAAA,YAAG,MACnE,YAAY,gBAAgB,QAAQ,aAAa,MAAM,cAAc,MAAM,KAAK;AAAA,UAClF;AAAA,QACF;AAGA,YAAI,MAAM,SAAS,aAAa;AAC9B,iBAAO;AAAA,YAAQ,CAAC,aAAa,aAAa,MAAM,YAAY;AAAA,YAAG,MAC7D,YAAY,UAAU,QAAQ,aAAa,MAAM,cAAc,MAAM,KAAK;AAAA,UAC5E;AAAA,QACF;AAGA,YAAI,MAAM,SAAS,yBAAyB;AAC1C,iBAAO;AAAA,YAAQ,CAAC,yBAAyB,aAAa,MAAM,YAAY;AAAA,YAAG,MACzE,YAAY,sBAAsB,QAAQ,aAAa,MAAM,cAAc,MAAM,KAAK;AAAA,UACxF;AAAA,QACF;AAGA,YAAI,MAAM,SAAS,qBAAqB;AACtC,iBAAO;AAAA,YAAQ,CAAC,qBAAqB,aAAa,MAAM,YAAY;AAAA,YAAG,MACrE,YAAY,kBAAkB,QAAQ,aAAa,MAAM,cAAc,MAAM,KAAK;AAAA,UACpF;AAAA,QACF;AAGA,YAAI,MAAM,SAAS,aAAa;AAC9B,iBAAO;AAAA,YAAQ,CAAC,aAAa,aAAa,MAAM,YAAY;AAAA,YAAG,MAC7D,YAAY,UAAU,QAAQ,aAAa,MAAM,cAAc,MAAM,KAAK;AAAA,UAC5E;AAAA,QACF;AAGA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -6,6 +6,7 @@ export declare const extensions: {
|
|
|
6
6
|
};
|
|
7
7
|
readonly workspace: {
|
|
8
8
|
readonly darkMode: "x-scalar-dark-mode";
|
|
9
|
+
readonly sidebarWidth: "x-scalar-sidebar-width";
|
|
9
10
|
readonly defaultClient: "x-scalar-default-client";
|
|
10
11
|
readonly activeDocument: "x-scalar-active-document";
|
|
11
12
|
readonly theme: "x-scalar-theme";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/schemas/extensions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU
|
|
1
|
+
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/schemas/extensions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAab,CAAA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/schemas/extensions.ts"],
|
|
4
|
-
"sourcesContent": ["export const extensions = {\n document: {\n navigation: 'x-scalar-navigation',\n activeAuth: 'x-scalar-active-auth',\n activeServer: 'x-scalar-active-server',\n },\n workspace: {\n darkMode: 'x-scalar-dark-mode',\n defaultClient: 'x-scalar-default-client',\n activeDocument: 'x-scalar-active-document',\n theme: 'x-scalar-theme',\n },\n} as const\n"],
|
|
5
|
-
"mappings": "AAAO,MAAM,aAAa;AAAA,EACxB,UAAU;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,WAAW;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AACF;",
|
|
4
|
+
"sourcesContent": ["export const extensions = {\n document: {\n navigation: 'x-scalar-navigation',\n activeAuth: 'x-scalar-active-auth',\n activeServer: 'x-scalar-active-server',\n },\n workspace: {\n darkMode: 'x-scalar-dark-mode',\n sidebarWidth: 'x-scalar-sidebar-width',\n defaultClient: 'x-scalar-default-client',\n activeDocument: 'x-scalar-active-document',\n theme: 'x-scalar-theme',\n },\n} as const\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,aAAa;AAAA,EACxB,UAAU;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,WAAW;AAAA,IACT,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|