mvc-kit 2.12.4 → 2.13.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/agent-config/bin/postinstall.mjs +4 -3
- package/agent-config/bin/setup.mjs +5 -1
- package/agent-config/claude-code/agents/mvc-kit-architect.md +11 -8
- package/agent-config/claude-code/skills/guide/SKILL.md +20 -7
- package/agent-config/claude-code/skills/guide/patterns.md +12 -0
- package/agent-config/claude-code/skills/guide/recipes.md +510 -0
- package/agent-config/claude-code/skills/guide/testing.md +297 -0
- package/agent-config/claude-code/skills/review/SKILL.md +3 -13
- package/agent-config/claude-code/skills/review/checklist.md +30 -5
- package/agent-config/claude-code/skills/scaffold/SKILL.md +4 -13
- package/agent-config/lib/install-claude.mjs +84 -25
- package/dist/Channel.cjs +276 -300
- package/dist/Channel.cjs.map +1 -1
- package/dist/Channel.js +275 -299
- package/dist/Channel.js.map +1 -1
- package/dist/Collection.cjs +424 -504
- package/dist/Collection.cjs.map +1 -1
- package/dist/Collection.js +423 -503
- package/dist/Collection.js.map +1 -1
- package/dist/Controller.cjs +70 -67
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.js +69 -66
- package/dist/Controller.js.map +1 -1
- package/dist/EventBus.cjs +77 -88
- package/dist/EventBus.cjs.map +1 -1
- package/dist/EventBus.js +76 -87
- package/dist/EventBus.js.map +1 -1
- package/dist/Feed.cjs +81 -77
- package/dist/Feed.cjs.map +1 -1
- package/dist/Feed.js +80 -76
- package/dist/Feed.js.map +1 -1
- package/dist/Model.cjs +181 -207
- package/dist/Model.cjs.map +1 -1
- package/dist/Model.js +179 -205
- package/dist/Model.js.map +1 -1
- package/dist/Pagination.cjs +75 -73
- package/dist/Pagination.cjs.map +1 -1
- package/dist/Pagination.js +74 -72
- package/dist/Pagination.js.map +1 -1
- package/dist/Pending.cjs +255 -287
- package/dist/Pending.cjs.map +1 -1
- package/dist/Pending.js +253 -285
- package/dist/Pending.js.map +1 -1
- package/dist/PersistentCollection.cjs +242 -285
- package/dist/PersistentCollection.cjs.map +1 -1
- package/dist/PersistentCollection.js +241 -284
- package/dist/PersistentCollection.js.map +1 -1
- package/dist/Resource.cjs +166 -174
- package/dist/Resource.cjs.map +1 -1
- package/dist/Resource.js +164 -172
- package/dist/Resource.js.map +1 -1
- package/dist/Selection.cjs +84 -94
- package/dist/Selection.cjs.map +1 -1
- package/dist/Selection.js +83 -93
- package/dist/Selection.js.map +1 -1
- package/dist/Service.cjs +54 -55
- package/dist/Service.cjs.map +1 -1
- package/dist/Service.js +53 -54
- package/dist/Service.js.map +1 -1
- package/dist/Sorting.cjs +102 -101
- package/dist/Sorting.cjs.map +1 -1
- package/dist/Sorting.js +102 -101
- package/dist/Sorting.js.map +1 -1
- package/dist/Trackable.cjs +112 -80
- package/dist/Trackable.cjs.map +1 -1
- package/dist/Trackable.js +111 -79
- package/dist/Trackable.js.map +1 -1
- package/dist/ViewModel.cjs +528 -576
- package/dist/ViewModel.cjs.map +1 -1
- package/dist/ViewModel.js +525 -573
- package/dist/ViewModel.js.map +1 -1
- package/dist/bindPublicMethods.cjs +43 -24
- package/dist/bindPublicMethods.cjs.map +1 -1
- package/dist/bindPublicMethods.js +43 -24
- package/dist/bindPublicMethods.js.map +1 -1
- package/dist/errors.cjs +67 -68
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +68 -71
- package/dist/errors.js.map +1 -1
- package/dist/mvc-kit.cjs +44 -46
- package/dist/mvc-kit.js +5 -32
- package/dist/produceDraft.cjs +105 -95
- package/dist/produceDraft.cjs.map +1 -1
- package/dist/produceDraft.js +106 -97
- package/dist/produceDraft.js.map +1 -1
- package/dist/react/components/CardList.cjs +30 -40
- package/dist/react/components/CardList.cjs.map +1 -1
- package/dist/react/components/CardList.js +31 -41
- package/dist/react/components/CardList.js.map +1 -1
- package/dist/react/components/DataTable.cjs +146 -169
- package/dist/react/components/DataTable.cjs.map +1 -1
- package/dist/react/components/DataTable.js +147 -170
- package/dist/react/components/DataTable.js.map +1 -1
- package/dist/react/components/InfiniteScroll.cjs +51 -42
- package/dist/react/components/InfiniteScroll.cjs.map +1 -1
- package/dist/react/components/InfiniteScroll.js +52 -43
- package/dist/react/components/InfiniteScroll.js.map +1 -1
- package/dist/react/components/types.cjs +10 -6
- package/dist/react/components/types.cjs.map +1 -1
- package/dist/react/components/types.js +11 -9
- package/dist/react/components/types.js.map +1 -1
- package/dist/react/guards.cjs +10 -6
- package/dist/react/guards.cjs.map +1 -1
- package/dist/react/guards.js +11 -9
- package/dist/react/guards.js.map +1 -1
- package/dist/react/provider.cjs +23 -20
- package/dist/react/provider.cjs.map +1 -1
- package/dist/react/provider.js +23 -21
- package/dist/react/provider.js.map +1 -1
- package/dist/react/use-event-bus.cjs +24 -20
- package/dist/react/use-event-bus.cjs.map +1 -1
- package/dist/react/use-event-bus.js +24 -21
- package/dist/react/use-event-bus.js.map +1 -1
- package/dist/react/use-instance.cjs +43 -36
- package/dist/react/use-instance.cjs.map +1 -1
- package/dist/react/use-instance.js +43 -36
- package/dist/react/use-instance.js.map +1 -1
- package/dist/react/use-local.cjs +48 -64
- package/dist/react/use-local.cjs.map +1 -1
- package/dist/react/use-local.js +47 -63
- package/dist/react/use-local.js.map +1 -1
- package/dist/react/use-model.cjs +84 -98
- package/dist/react/use-model.cjs.map +1 -1
- package/dist/react/use-model.js +84 -100
- package/dist/react/use-model.js.map +1 -1
- package/dist/react/use-singleton.cjs +19 -23
- package/dist/react/use-singleton.cjs.map +1 -1
- package/dist/react/use-singleton.js +16 -20
- package/dist/react/use-singleton.js.map +1 -1
- package/dist/react/use-subscribe-only.cjs +28 -22
- package/dist/react/use-subscribe-only.cjs.map +1 -1
- package/dist/react/use-subscribe-only.js +28 -22
- package/dist/react/use-subscribe-only.js.map +1 -1
- package/dist/react/use-teardown.cjs +20 -19
- package/dist/react/use-teardown.cjs.map +1 -1
- package/dist/react/use-teardown.js +20 -19
- package/dist/react/use-teardown.js.map +1 -1
- package/dist/react-native/NativeCollection.cjs +98 -78
- package/dist/react-native/NativeCollection.cjs.map +1 -1
- package/dist/react-native/NativeCollection.js +97 -77
- package/dist/react-native/NativeCollection.js.map +1 -1
- package/dist/react-native.cjs +2 -4
- package/dist/react-native.js +1 -4
- package/dist/react.cjs +24 -26
- package/dist/react.js +1 -17
- package/dist/singleton.cjs +28 -22
- package/dist/singleton.cjs.map +1 -1
- package/dist/singleton.js +29 -26
- package/dist/singleton.js.map +1 -1
- package/dist/walkPrototypeChain.cjs +20 -12
- package/dist/walkPrototypeChain.cjs.map +1 -1
- package/dist/walkPrototypeChain.js +21 -13
- package/dist/walkPrototypeChain.js.map +1 -1
- package/dist/web/IndexedDBCollection.cjs +53 -36
- package/dist/web/IndexedDBCollection.cjs.map +1 -1
- package/dist/web/IndexedDBCollection.js +52 -35
- package/dist/web/IndexedDBCollection.js.map +1 -1
- package/dist/web/WebStorageCollection.cjs +82 -84
- package/dist/web/WebStorageCollection.cjs.map +1 -1
- package/dist/web/WebStorageCollection.js +81 -83
- package/dist/web/WebStorageCollection.js.map +1 -1
- package/dist/web/idb.cjs +107 -99
- package/dist/web/idb.cjs.map +1 -1
- package/dist/web/idb.js +108 -105
- package/dist/web/idb.js.map +1 -1
- package/dist/web.cjs +4 -6
- package/dist/web.js +1 -5
- package/dist/wrapAsyncMethods.cjs +141 -168
- package/dist/wrapAsyncMethods.cjs.map +1 -1
- package/dist/wrapAsyncMethods.js +141 -168
- package/dist/wrapAsyncMethods.js.map +1 -1
- package/package.json +8 -8
- package/src/Pending.test.ts +1 -2
- package/src/Sorting.test.ts +1 -1
- package/src/produceDraft.test.ts +3 -3
- package/src/react/components/CardList.test.tsx +1 -1
- package/src/react/components/DataTable.test.tsx +1 -1
- package/src/react/components/InfiniteScroll.test.tsx +5 -5
- package/dist/mvc-kit.cjs.map +0 -1
- package/dist/mvc-kit.js.map +0 -1
- package/dist/react-native.cjs.map +0 -1
- package/dist/react-native.js.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/web.cjs.map +0 -1
- package/dist/web.js.map +0 -1
package/dist/singleton.cjs
CHANGED
|
@@ -1,34 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const registry = /* @__PURE__ */ new Map();
|
|
1
|
+
//#region src/singleton.ts
|
|
2
|
+
var registry = /* @__PURE__ */ new Map();
|
|
4
3
|
function singleton(Class, ...args) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
registry.set(Class, instance);
|
|
11
|
-
return instance;
|
|
4
|
+
const existing = registry.get(Class);
|
|
5
|
+
if (existing && !existing.disposed) return existing;
|
|
6
|
+
const instance = args.length === 0 && "DEFAULT_STATE" in Class ? new Class(Class.DEFAULT_STATE) : new Class(...args);
|
|
7
|
+
registry.set(Class, instance);
|
|
8
|
+
return instance;
|
|
12
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Check if a singleton instance exists for a class.
|
|
12
|
+
*/
|
|
13
13
|
function hasSingleton(Class) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const existing = registry.get(Class);
|
|
15
|
+
return existing !== void 0 && !existing.disposed;
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Disposes and removes the singleton instance for the given class.
|
|
19
|
+
*/
|
|
17
20
|
function teardown(Class) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
const instance = registry.get(Class);
|
|
22
|
+
if (instance) {
|
|
23
|
+
instance.dispose();
|
|
24
|
+
registry.delete(Class);
|
|
25
|
+
}
|
|
23
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Disposes all singletons and clears the registry. Typically used in test cleanup.
|
|
29
|
+
*/
|
|
24
30
|
function teardownAll() {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
registry.clear();
|
|
31
|
+
for (const instance of registry.values()) instance.dispose();
|
|
32
|
+
registry.clear();
|
|
29
33
|
}
|
|
34
|
+
//#endregion
|
|
30
35
|
exports.hasSingleton = hasSingleton;
|
|
31
36
|
exports.singleton = singleton;
|
|
32
37
|
exports.teardown = teardown;
|
|
33
38
|
exports.teardownAll = teardownAll;
|
|
34
|
-
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=singleton.cjs.map
|
package/dist/singleton.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleton.cjs","sources":["../src/singleton.ts"],"sourcesContent":["import type { Disposable } from './types';\n\n// Using 'any' for registry types to avoid variance issues with generics\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyDisposableClass = new (...args: any[]) => Disposable;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst registry = new Map<AnyDisposableClass, Disposable>();\n\n/**\n * Get-or-create a singleton instance for the given class.\n * Returns the existing instance if one exists and is not disposed; otherwise creates a new one.\n *\n * If the class defines `static DEFAULT_STATE`, it is used as the constructor argument\n * when no args are passed — eliminating repeated object literals at every call site.\n */\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE: unknown },\n): T;\nexport function singleton<T extends Disposable, Args extends unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE?: unknown },\n ...args: unknown[]\n): T {\n const existing = registry.get(Class as AnyDisposableClass);\n\n if (existing && !existing.disposed) {\n return existing as T;\n }\n\n const instance = (args.length === 0 && 'DEFAULT_STATE' in Class)\n ? new Class(Class.DEFAULT_STATE)\n : new Class(...args);\n\n registry.set(Class as AnyDisposableClass, instance);\n return instance;\n}\n\n/**\n * Check if a singleton instance exists for a class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function hasSingleton(Class: new (...args: any[]) => Disposable): boolean {\n const existing = registry.get(Class);\n return existing !== undefined && !existing.disposed;\n}\n\n/**\n * Disposes and removes the singleton instance for the given class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function teardown(Class: new (...args: any[]) => Disposable): void {\n const instance = registry.get(Class);\n if (instance) {\n instance.dispose();\n registry.delete(Class);\n }\n}\n\n/**\n * Disposes all singletons and clears the registry. Typically used in test cleanup.\n */\nexport function teardownAll(): void {\n for (const instance of registry.values()) {\n instance.dispose();\n }\n registry.clear();\n}\n"],"
|
|
1
|
+
{"version":3,"file":"singleton.cjs","names":[],"sources":["../src/singleton.ts"],"sourcesContent":["import type { Disposable } from './types';\n\n// Using 'any' for registry types to avoid variance issues with generics\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyDisposableClass = new (...args: any[]) => Disposable;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst registry = new Map<AnyDisposableClass, Disposable>();\n\n/**\n * Get-or-create a singleton instance for the given class.\n * Returns the existing instance if one exists and is not disposed; otherwise creates a new one.\n *\n * If the class defines `static DEFAULT_STATE`, it is used as the constructor argument\n * when no args are passed — eliminating repeated object literals at every call site.\n */\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE: unknown },\n): T;\nexport function singleton<T extends Disposable, Args extends unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE?: unknown },\n ...args: unknown[]\n): T {\n const existing = registry.get(Class as AnyDisposableClass);\n\n if (existing && !existing.disposed) {\n return existing as T;\n }\n\n const instance = (args.length === 0 && 'DEFAULT_STATE' in Class)\n ? new Class(Class.DEFAULT_STATE)\n : new Class(...args);\n\n registry.set(Class as AnyDisposableClass, instance);\n return instance;\n}\n\n/**\n * Check if a singleton instance exists for a class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function hasSingleton(Class: new (...args: any[]) => Disposable): boolean {\n const existing = registry.get(Class);\n return existing !== undefined && !existing.disposed;\n}\n\n/**\n * Disposes and removes the singleton instance for the given class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function teardown(Class: new (...args: any[]) => Disposable): void {\n const instance = registry.get(Class);\n if (instance) {\n instance.dispose();\n registry.delete(Class);\n }\n}\n\n/**\n * Disposes all singletons and clears the registry. Typically used in test cleanup.\n */\nexport function teardownAll(): void {\n for (const instance of registry.values()) {\n instance.dispose();\n }\n registry.clear();\n}\n"],"mappings":";AAMA,IAAM,2BAAW,IAAI,KAAqC;AAgB1D,SAAgB,UACd,OACA,GAAG,MACA;CACH,MAAM,WAAW,SAAS,IAAI,MAA4B;AAE1D,KAAI,YAAY,CAAC,SAAS,SACxB,QAAO;CAGT,MAAM,WAAY,KAAK,WAAW,KAAK,mBAAmB,QACtD,IAAI,MAAM,MAAM,cAAc,GAC9B,IAAI,MAAM,GAAG,KAAK;AAEtB,UAAS,IAAI,OAA6B,SAAS;AACnD,QAAO;;;;;AAOT,SAAgB,aAAa,OAAoD;CAC/E,MAAM,WAAW,SAAS,IAAI,MAAM;AACpC,QAAO,aAAa,KAAA,KAAa,CAAC,SAAS;;;;;AAO7C,SAAgB,SAAS,OAAiD;CACxE,MAAM,WAAW,SAAS,IAAI,MAAM;AACpC,KAAI,UAAU;AACZ,WAAS,SAAS;AAClB,WAAS,OAAO,MAAM;;;;;;AAO1B,SAAgB,cAAoB;AAClC,MAAK,MAAM,YAAY,SAAS,QAAQ,CACtC,UAAS,SAAS;AAEpB,UAAS,OAAO"}
|
package/dist/singleton.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/singleton.ts
|
|
2
|
+
var registry = /* @__PURE__ */ new Map();
|
|
2
3
|
function singleton(Class, ...args) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
registry.set(Class, instance);
|
|
9
|
-
return instance;
|
|
4
|
+
const existing = registry.get(Class);
|
|
5
|
+
if (existing && !existing.disposed) return existing;
|
|
6
|
+
const instance = args.length === 0 && "DEFAULT_STATE" in Class ? new Class(Class.DEFAULT_STATE) : new Class(...args);
|
|
7
|
+
registry.set(Class, instance);
|
|
8
|
+
return instance;
|
|
10
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Check if a singleton instance exists for a class.
|
|
12
|
+
*/
|
|
11
13
|
function hasSingleton(Class) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
+
const existing = registry.get(Class);
|
|
15
|
+
return existing !== void 0 && !existing.disposed;
|
|
14
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Disposes and removes the singleton instance for the given class.
|
|
19
|
+
*/
|
|
15
20
|
function teardown(Class) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
const instance = registry.get(Class);
|
|
22
|
+
if (instance) {
|
|
23
|
+
instance.dispose();
|
|
24
|
+
registry.delete(Class);
|
|
25
|
+
}
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Disposes all singletons and clears the registry. Typically used in test cleanup.
|
|
29
|
+
*/
|
|
22
30
|
function teardownAll() {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
registry.clear();
|
|
31
|
+
for (const instance of registry.values()) instance.dispose();
|
|
32
|
+
registry.clear();
|
|
27
33
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
teardownAll
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=singleton.js.map
|
|
34
|
+
//#endregion
|
|
35
|
+
export { hasSingleton, singleton, teardown, teardownAll };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=singleton.js.map
|
package/dist/singleton.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleton.js","sources":["../src/singleton.ts"],"sourcesContent":["import type { Disposable } from './types';\n\n// Using 'any' for registry types to avoid variance issues with generics\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyDisposableClass = new (...args: any[]) => Disposable;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst registry = new Map<AnyDisposableClass, Disposable>();\n\n/**\n * Get-or-create a singleton instance for the given class.\n * Returns the existing instance if one exists and is not disposed; otherwise creates a new one.\n *\n * If the class defines `static DEFAULT_STATE`, it is used as the constructor argument\n * when no args are passed — eliminating repeated object literals at every call site.\n */\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE: unknown },\n): T;\nexport function singleton<T extends Disposable, Args extends unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE?: unknown },\n ...args: unknown[]\n): T {\n const existing = registry.get(Class as AnyDisposableClass);\n\n if (existing && !existing.disposed) {\n return existing as T;\n }\n\n const instance = (args.length === 0 && 'DEFAULT_STATE' in Class)\n ? new Class(Class.DEFAULT_STATE)\n : new Class(...args);\n\n registry.set(Class as AnyDisposableClass, instance);\n return instance;\n}\n\n/**\n * Check if a singleton instance exists for a class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function hasSingleton(Class: new (...args: any[]) => Disposable): boolean {\n const existing = registry.get(Class);\n return existing !== undefined && !existing.disposed;\n}\n\n/**\n * Disposes and removes the singleton instance for the given class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function teardown(Class: new (...args: any[]) => Disposable): void {\n const instance = registry.get(Class);\n if (instance) {\n instance.dispose();\n registry.delete(Class);\n }\n}\n\n/**\n * Disposes all singletons and clears the registry. Typically used in test cleanup.\n */\nexport function teardownAll(): void {\n for (const instance of registry.values()) {\n instance.dispose();\n }\n registry.clear();\n}\n"],"
|
|
1
|
+
{"version":3,"file":"singleton.js","names":[],"sources":["../src/singleton.ts"],"sourcesContent":["import type { Disposable } from './types';\n\n// Using 'any' for registry types to avoid variance issues with generics\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyDisposableClass = new (...args: any[]) => Disposable;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst registry = new Map<AnyDisposableClass, Disposable>();\n\n/**\n * Get-or-create a singleton instance for the given class.\n * Returns the existing instance if one exists and is not disposed; otherwise creates a new one.\n *\n * If the class defines `static DEFAULT_STATE`, it is used as the constructor argument\n * when no args are passed — eliminating repeated object literals at every call site.\n */\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE: unknown },\n): T;\nexport function singleton<T extends Disposable, Args extends unknown[]>(\n Class: new (...args: Args) => T,\n ...args: Args\n): T;\nexport function singleton<T extends Disposable>(\n Class: (new (...args: any[]) => T) & { DEFAULT_STATE?: unknown },\n ...args: unknown[]\n): T {\n const existing = registry.get(Class as AnyDisposableClass);\n\n if (existing && !existing.disposed) {\n return existing as T;\n }\n\n const instance = (args.length === 0 && 'DEFAULT_STATE' in Class)\n ? new Class(Class.DEFAULT_STATE)\n : new Class(...args);\n\n registry.set(Class as AnyDisposableClass, instance);\n return instance;\n}\n\n/**\n * Check if a singleton instance exists for a class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function hasSingleton(Class: new (...args: any[]) => Disposable): boolean {\n const existing = registry.get(Class);\n return existing !== undefined && !existing.disposed;\n}\n\n/**\n * Disposes and removes the singleton instance for the given class.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function teardown(Class: new (...args: any[]) => Disposable): void {\n const instance = registry.get(Class);\n if (instance) {\n instance.dispose();\n registry.delete(Class);\n }\n}\n\n/**\n * Disposes all singletons and clears the registry. Typically used in test cleanup.\n */\nexport function teardownAll(): void {\n for (const instance of registry.values()) {\n instance.dispose();\n }\n registry.clear();\n}\n"],"mappings":";AAMA,IAAM,2BAAW,IAAI,KAAqC;AAgB1D,SAAgB,UACd,OACA,GAAG,MACA;CACH,MAAM,WAAW,SAAS,IAAI,MAA4B;AAE1D,KAAI,YAAY,CAAC,SAAS,SACxB,QAAO;CAGT,MAAM,WAAY,KAAK,WAAW,KAAK,mBAAmB,QACtD,IAAI,MAAM,MAAM,cAAc,GAC9B,IAAI,MAAM,GAAG,KAAK;AAEtB,UAAS,IAAI,OAA6B,SAAS;AACnD,QAAO;;;;;AAOT,SAAgB,aAAa,OAAoD;CAC/E,MAAM,WAAW,SAAS,IAAI,MAAM;AACpC,QAAO,aAAa,KAAA,KAAa,CAAC,SAAS;;;;;AAO7C,SAAgB,SAAS,OAAiD;CACxE,MAAM,WAAW,SAAS,IAAI,MAAM;AACpC,KAAI,UAAU;AACZ,WAAS,SAAS;AAClB,WAAS,OAAO,MAAM;;;;;;AAO1B,SAAgB,cAAoB;AAClC,MAAK,MAAM,YAAY,SAAS,QAAQ,CACtC,UAAS,SAAS;AAEpB,UAAS,OAAO"}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/walkPrototypeChain.ts
|
|
2
|
+
/**
|
|
3
|
+
* Walk the prototype chain from `instance`'s class up to (but not including)
|
|
4
|
+
* `stopAt`. Calls `visitor` for each own property descriptor found.
|
|
5
|
+
*
|
|
6
|
+
* Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),
|
|
7
|
+
* ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().
|
|
8
|
+
*/
|
|
3
9
|
function walkPrototypeChain(instance, stopAt, visitor) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
let proto = Object.getPrototypeOf(instance);
|
|
11
|
+
while (proto && proto !== stopAt) {
|
|
12
|
+
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
|
13
|
+
for (const [key, desc] of Object.entries(descriptors)) {
|
|
14
|
+
if (key === "constructor") continue;
|
|
15
|
+
visitor(key, desc, proto);
|
|
16
|
+
}
|
|
17
|
+
proto = Object.getPrototypeOf(proto);
|
|
18
|
+
}
|
|
13
19
|
}
|
|
20
|
+
//#endregion
|
|
14
21
|
exports.walkPrototypeChain = walkPrototypeChain;
|
|
15
|
-
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=walkPrototypeChain.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walkPrototypeChain.cjs","sources":["../src/walkPrototypeChain.ts"],"sourcesContent":["/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),\n * ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n"],"
|
|
1
|
+
{"version":3,"file":"walkPrototypeChain.cjs","names":[],"sources":["../src/walkPrototypeChain.ts"],"sourcesContent":["/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),\n * ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,mBACd,UACA,QACA,SACM;CACN,IAAI,QAAQ,OAAO,eAAe,SAAS;AAC3C,QAAO,SAAS,UAAU,QAAQ;EAChC,MAAM,cAAc,OAAO,0BAA0B,MAAM;AAC3D,OAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,YAAY,EAAE;AACrD,OAAI,QAAQ,cAAe;AAC3B,WAAQ,KAAK,MAAM,MAAM;;AAE3B,UAAQ,OAAO,eAAe,MAAM"}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
+
//#region src/walkPrototypeChain.ts
|
|
2
|
+
/**
|
|
3
|
+
* Walk the prototype chain from `instance`'s class up to (but not including)
|
|
4
|
+
* `stopAt`. Calls `visitor` for each own property descriptor found.
|
|
5
|
+
*
|
|
6
|
+
* Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),
|
|
7
|
+
* ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().
|
|
8
|
+
*/
|
|
1
9
|
function walkPrototypeChain(instance, stopAt, visitor) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
let proto = Object.getPrototypeOf(instance);
|
|
11
|
+
while (proto && proto !== stopAt) {
|
|
12
|
+
const descriptors = Object.getOwnPropertyDescriptors(proto);
|
|
13
|
+
for (const [key, desc] of Object.entries(descriptors)) {
|
|
14
|
+
if (key === "constructor") continue;
|
|
15
|
+
visitor(key, desc, proto);
|
|
16
|
+
}
|
|
17
|
+
proto = Object.getPrototypeOf(proto);
|
|
18
|
+
}
|
|
11
19
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
//# sourceMappingURL=walkPrototypeChain.js.map
|
|
20
|
+
//#endregion
|
|
21
|
+
export { walkPrototypeChain };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=walkPrototypeChain.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walkPrototypeChain.js","sources":["../src/walkPrototypeChain.ts"],"sourcesContent":["/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),\n * ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n"],"
|
|
1
|
+
{"version":3,"file":"walkPrototypeChain.js","names":[],"sources":["../src/walkPrototypeChain.ts"],"sourcesContent":["/**\n * Walk the prototype chain from `instance`'s class up to (but not including)\n * `stopAt`. Calls `visitor` for each own property descriptor found.\n *\n * Shared utility — used by ViewModel's _processMembers(), wrapAsyncMethods(),\n * ViewModel/Resource's _guardReservedKeys(), and bindPublicMethods().\n */\nexport function walkPrototypeChain(\n instance: object,\n stopAt: object,\n visitor: (key: string, desc: PropertyDescriptor, proto: object) => void,\n): void {\n let proto = Object.getPrototypeOf(instance);\n while (proto && proto !== stopAt) {\n const descriptors = Object.getOwnPropertyDescriptors(proto);\n for (const [key, desc] of Object.entries(descriptors)) {\n if (key === 'constructor') continue;\n visitor(key, desc, proto);\n }\n proto = Object.getPrototypeOf(proto);\n }\n}\n"],"mappings":";;;;;;;;AAOA,SAAgB,mBACd,UACA,QACA,SACM;CACN,IAAI,QAAQ,OAAO,eAAe,SAAS;AAC3C,QAAO,SAAS,UAAU,QAAQ;EAChC,MAAM,cAAc,OAAO,0BAA0B,MAAM;AAC3D,OAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,YAAY,EAAE;AACrD,OAAI,QAAQ,cAAe;AAC3B,WAAQ,KAAK,MAAM,MAAM;;AAE3B,UAAQ,OAAO,eAAe,MAAM"}
|
|
@@ -1,37 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
const require_PersistentCollection = require("../PersistentCollection.cjs");
|
|
2
|
+
const require_idb = require("./idb.cjs");
|
|
3
|
+
//#region src/web/IndexedDBCollection.ts
|
|
4
|
+
/**
|
|
5
|
+
* PersistentCollection backed by IndexedDB. Stores items individually by `id`
|
|
6
|
+
* in a dedicated object store (named by `storageKey`).
|
|
7
|
+
*
|
|
8
|
+
* **Requires manual `hydrate()` call** (async storage).
|
|
9
|
+
* Typically called in ViewModel's `onInit()`.
|
|
10
|
+
*
|
|
11
|
+
* Uses per-item strategy: each item is stored as a separate entry in the object store.
|
|
12
|
+
* No JSON serialization needed — IndexedDB uses structured cloning.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* class MessagesCollection extends IndexedDBCollection<Message> {
|
|
16
|
+
* protected readonly storageKey = 'messages';
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* // In ViewModel:
|
|
20
|
+
* async onInit() {
|
|
21
|
+
* await this.collection.hydrate();
|
|
22
|
+
* if (this.collection.length === 0) this.load();
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
var IndexedDBCollection = class extends require_PersistentCollection.PersistentCollection {
|
|
27
|
+
/** IndexedDB database name. Override to use a separate database. */
|
|
28
|
+
static DB_NAME = "mvc-kit";
|
|
29
|
+
get _dbName() {
|
|
30
|
+
return this.constructor.DB_NAME;
|
|
31
|
+
}
|
|
32
|
+
_getStore(mode) {
|
|
33
|
+
return require_idb.getStore(this._dbName, this.storageKey, mode);
|
|
34
|
+
}
|
|
35
|
+
async persistGetAll() {
|
|
36
|
+
return require_idb.idbGetAll(await this._getStore("readonly"));
|
|
37
|
+
}
|
|
38
|
+
async persistGet(id) {
|
|
39
|
+
return require_idb.idbGet(await this._getStore("readonly"), id);
|
|
40
|
+
}
|
|
41
|
+
async persistSet(items) {
|
|
42
|
+
return require_idb.idbPut(await this._getStore("readwrite"), items);
|
|
43
|
+
}
|
|
44
|
+
async persistRemove(ids) {
|
|
45
|
+
return require_idb.idbDelete(await this._getStore("readwrite"), ids);
|
|
46
|
+
}
|
|
47
|
+
async persistClear() {
|
|
48
|
+
return require_idb.idbClear(await this._getStore("readwrite"));
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
36
52
|
exports.IndexedDBCollection = IndexedDBCollection;
|
|
37
|
-
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=IndexedDBCollection.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IndexedDBCollection.cjs","sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"
|
|
1
|
+
{"version":3,"file":"IndexedDBCollection.cjs","names":[],"sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAsB,sBAAtB,cAEU,6BAAA,qBAAwB;;CAEhC,OAAO,UAAU;CAEjB,IAAY,UAAkB;AAC5B,SAAQ,KAAK,YAA2C;;CAG1D,UAAkB,MAA0B;AAC1C,SAAO,YAAA,SAAS,KAAK,SAAS,KAAK,YAAY,KAAK;;CAKtD,MAAgB,gBAA8B;AAE5C,SAAO,YAAA,UADO,MAAM,KAAK,UAAU,WAAW,CACpB;;CAG5B,MAAgB,WAAW,IAAgC;AAEzD,SAAO,YAAA,OADO,MAAM,KAAK,UAAU,WAAW,EACtB,GAAkB;;CAG5C,MAAgB,WAAW,OAA2B;AAEpD,SAAO,YAAA,OADO,MAAM,KAAK,UAAU,YAAY,EAC1B,MAAM;;CAG7B,MAAgB,cAAc,KAA+B;AAE3D,SAAO,YAAA,UADO,MAAM,KAAK,UAAU,YAAY,EACvB,IAAqB;;CAG/C,MAAgB,eAA8B;AAE5C,SAAO,YAAA,SADO,MAAM,KAAK,UAAU,YAAY,CACzB"}
|
|
@@ -1,37 +1,54 @@
|
|
|
1
1
|
import { PersistentCollection } from "../PersistentCollection.js";
|
|
2
|
-
import { getStore,
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
import { getStore, idbClear, idbDelete, idbGet, idbGetAll, idbPut } from "./idb.js";
|
|
3
|
+
//#region src/web/IndexedDBCollection.ts
|
|
4
|
+
/**
|
|
5
|
+
* PersistentCollection backed by IndexedDB. Stores items individually by `id`
|
|
6
|
+
* in a dedicated object store (named by `storageKey`).
|
|
7
|
+
*
|
|
8
|
+
* **Requires manual `hydrate()` call** (async storage).
|
|
9
|
+
* Typically called in ViewModel's `onInit()`.
|
|
10
|
+
*
|
|
11
|
+
* Uses per-item strategy: each item is stored as a separate entry in the object store.
|
|
12
|
+
* No JSON serialization needed — IndexedDB uses structured cloning.
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* class MessagesCollection extends IndexedDBCollection<Message> {
|
|
16
|
+
* protected readonly storageKey = 'messages';
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* // In ViewModel:
|
|
20
|
+
* async onInit() {
|
|
21
|
+
* await this.collection.hydrate();
|
|
22
|
+
* if (this.collection.length === 0) this.load();
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
var IndexedDBCollection = class extends PersistentCollection {
|
|
27
|
+
/** IndexedDB database name. Override to use a separate database. */
|
|
28
|
+
static DB_NAME = "mvc-kit";
|
|
29
|
+
get _dbName() {
|
|
30
|
+
return this.constructor.DB_NAME;
|
|
31
|
+
}
|
|
32
|
+
_getStore(mode) {
|
|
33
|
+
return getStore(this._dbName, this.storageKey, mode);
|
|
34
|
+
}
|
|
35
|
+
async persistGetAll() {
|
|
36
|
+
return idbGetAll(await this._getStore("readonly"));
|
|
37
|
+
}
|
|
38
|
+
async persistGet(id) {
|
|
39
|
+
return idbGet(await this._getStore("readonly"), id);
|
|
40
|
+
}
|
|
41
|
+
async persistSet(items) {
|
|
42
|
+
return idbPut(await this._getStore("readwrite"), items);
|
|
43
|
+
}
|
|
44
|
+
async persistRemove(ids) {
|
|
45
|
+
return idbDelete(await this._getStore("readwrite"), ids);
|
|
46
|
+
}
|
|
47
|
+
async persistClear() {
|
|
48
|
+
return idbClear(await this._getStore("readwrite"));
|
|
49
|
+
}
|
|
36
50
|
};
|
|
37
|
-
//#
|
|
51
|
+
//#endregion
|
|
52
|
+
export { IndexedDBCollection };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=IndexedDBCollection.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IndexedDBCollection.js","sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"
|
|
1
|
+
{"version":3,"file":"IndexedDBCollection.js","names":[],"sources":["../../src/web/IndexedDBCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\nimport { getStore, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from './idb';\n\n/**\n * PersistentCollection backed by IndexedDB. Stores items individually by `id`\n * in a dedicated object store (named by `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n * Typically called in ViewModel's `onInit()`.\n *\n * Uses per-item strategy: each item is stored as a separate entry in the object store.\n * No JSON serialization needed — IndexedDB uses structured cloning.\n *\n * ```ts\n * class MessagesCollection extends IndexedDBCollection<Message> {\n * protected readonly storageKey = 'messages';\n * }\n *\n * // In ViewModel:\n * async onInit() {\n * await this.collection.hydrate();\n * if (this.collection.length === 0) this.load();\n * }\n * ```\n */\nexport abstract class IndexedDBCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** IndexedDB database name. Override to use a separate database. */\n static DB_NAME = 'mvc-kit';\n\n private get _dbName(): string {\n return (this.constructor as typeof IndexedDBCollection).DB_NAME;\n }\n\n private _getStore(mode: IDBTransactionMode) {\n return getStore(this._dbName, this.storageKey, mode);\n }\n\n // ── Persist interface (per-item strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const store = await this._getStore('readonly');\n return idbGetAll<T>(store);\n }\n\n protected async persistGet(id: T['id']): Promise<T | null> {\n const store = await this._getStore('readonly');\n return idbGet<T>(store, id as IDBValidKey);\n }\n\n protected async persistSet(items: T[]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbPut(store, items);\n }\n\n protected async persistRemove(ids: T['id'][]): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbDelete(store, ids as IDBValidKey[]);\n }\n\n protected async persistClear(): Promise<void> {\n const store = await this._getStore('readwrite');\n return idbClear(store);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAsB,sBAAtB,cAEU,qBAAwB;;CAEhC,OAAO,UAAU;CAEjB,IAAY,UAAkB;AAC5B,SAAQ,KAAK,YAA2C;;CAG1D,UAAkB,MAA0B;AAC1C,SAAO,SAAS,KAAK,SAAS,KAAK,YAAY,KAAK;;CAKtD,MAAgB,gBAA8B;AAE5C,SAAO,UADO,MAAM,KAAK,UAAU,WAAW,CACpB;;CAG5B,MAAgB,WAAW,IAAgC;AAEzD,SAAO,OADO,MAAM,KAAK,UAAU,WAAW,EACtB,GAAkB;;CAG5C,MAAgB,WAAW,OAA2B;AAEpD,SAAO,OADO,MAAM,KAAK,UAAU,YAAY,EAC1B,MAAM;;CAG7B,MAAgB,cAAc,KAA+B;AAE3D,SAAO,UADO,MAAM,KAAK,UAAU,YAAY,EACvB,IAAqB;;CAG/C,MAAgB,eAA8B;AAE5C,SAAO,SADO,MAAM,KAAK,UAAU,YAAY,CACzB"}
|