mvc-kit 2.12.5 → 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.
Files changed (186) hide show
  1. package/agent-config/bin/postinstall.mjs +4 -3
  2. package/agent-config/bin/setup.mjs +5 -1
  3. package/agent-config/claude-code/agents/mvc-kit-architect.md +11 -8
  4. package/agent-config/claude-code/skills/guide/SKILL.md +20 -7
  5. package/agent-config/claude-code/skills/guide/patterns.md +12 -0
  6. package/agent-config/claude-code/skills/guide/recipes.md +510 -0
  7. package/agent-config/claude-code/skills/guide/testing.md +297 -0
  8. package/agent-config/claude-code/skills/review/SKILL.md +3 -13
  9. package/agent-config/claude-code/skills/review/checklist.md +30 -5
  10. package/agent-config/claude-code/skills/scaffold/SKILL.md +4 -13
  11. package/agent-config/lib/install-claude.mjs +84 -25
  12. package/dist/Channel.cjs +276 -300
  13. package/dist/Channel.cjs.map +1 -1
  14. package/dist/Channel.js +275 -299
  15. package/dist/Channel.js.map +1 -1
  16. package/dist/Collection.cjs +424 -504
  17. package/dist/Collection.cjs.map +1 -1
  18. package/dist/Collection.js +423 -503
  19. package/dist/Collection.js.map +1 -1
  20. package/dist/Controller.cjs +70 -67
  21. package/dist/Controller.cjs.map +1 -1
  22. package/dist/Controller.js +69 -66
  23. package/dist/Controller.js.map +1 -1
  24. package/dist/EventBus.cjs +77 -88
  25. package/dist/EventBus.cjs.map +1 -1
  26. package/dist/EventBus.js +76 -87
  27. package/dist/EventBus.js.map +1 -1
  28. package/dist/Feed.cjs +81 -77
  29. package/dist/Feed.cjs.map +1 -1
  30. package/dist/Feed.js +80 -76
  31. package/dist/Feed.js.map +1 -1
  32. package/dist/Model.cjs +181 -207
  33. package/dist/Model.cjs.map +1 -1
  34. package/dist/Model.js +179 -205
  35. package/dist/Model.js.map +1 -1
  36. package/dist/Pagination.cjs +75 -73
  37. package/dist/Pagination.cjs.map +1 -1
  38. package/dist/Pagination.js +74 -72
  39. package/dist/Pagination.js.map +1 -1
  40. package/dist/Pending.cjs +255 -287
  41. package/dist/Pending.cjs.map +1 -1
  42. package/dist/Pending.js +253 -285
  43. package/dist/Pending.js.map +1 -1
  44. package/dist/PersistentCollection.cjs +242 -285
  45. package/dist/PersistentCollection.cjs.map +1 -1
  46. package/dist/PersistentCollection.js +241 -284
  47. package/dist/PersistentCollection.js.map +1 -1
  48. package/dist/Resource.cjs +166 -174
  49. package/dist/Resource.cjs.map +1 -1
  50. package/dist/Resource.js +164 -172
  51. package/dist/Resource.js.map +1 -1
  52. package/dist/Selection.cjs +84 -94
  53. package/dist/Selection.cjs.map +1 -1
  54. package/dist/Selection.js +83 -93
  55. package/dist/Selection.js.map +1 -1
  56. package/dist/Service.cjs +54 -55
  57. package/dist/Service.cjs.map +1 -1
  58. package/dist/Service.js +53 -54
  59. package/dist/Service.js.map +1 -1
  60. package/dist/Sorting.cjs +102 -101
  61. package/dist/Sorting.cjs.map +1 -1
  62. package/dist/Sorting.js +102 -101
  63. package/dist/Sorting.js.map +1 -1
  64. package/dist/Trackable.cjs +112 -80
  65. package/dist/Trackable.cjs.map +1 -1
  66. package/dist/Trackable.js +111 -79
  67. package/dist/Trackable.js.map +1 -1
  68. package/dist/ViewModel.cjs +528 -576
  69. package/dist/ViewModel.cjs.map +1 -1
  70. package/dist/ViewModel.js +525 -573
  71. package/dist/ViewModel.js.map +1 -1
  72. package/dist/bindPublicMethods.cjs +43 -24
  73. package/dist/bindPublicMethods.cjs.map +1 -1
  74. package/dist/bindPublicMethods.js +43 -24
  75. package/dist/bindPublicMethods.js.map +1 -1
  76. package/dist/errors.cjs +67 -68
  77. package/dist/errors.cjs.map +1 -1
  78. package/dist/errors.js +68 -71
  79. package/dist/errors.js.map +1 -1
  80. package/dist/mvc-kit.cjs +44 -46
  81. package/dist/mvc-kit.js +5 -32
  82. package/dist/produceDraft.cjs +105 -95
  83. package/dist/produceDraft.cjs.map +1 -1
  84. package/dist/produceDraft.js +106 -97
  85. package/dist/produceDraft.js.map +1 -1
  86. package/dist/react/components/CardList.cjs +30 -40
  87. package/dist/react/components/CardList.cjs.map +1 -1
  88. package/dist/react/components/CardList.js +31 -41
  89. package/dist/react/components/CardList.js.map +1 -1
  90. package/dist/react/components/DataTable.cjs +146 -169
  91. package/dist/react/components/DataTable.cjs.map +1 -1
  92. package/dist/react/components/DataTable.js +147 -170
  93. package/dist/react/components/DataTable.js.map +1 -1
  94. package/dist/react/components/InfiniteScroll.cjs +51 -42
  95. package/dist/react/components/InfiniteScroll.cjs.map +1 -1
  96. package/dist/react/components/InfiniteScroll.js +52 -43
  97. package/dist/react/components/InfiniteScroll.js.map +1 -1
  98. package/dist/react/components/types.cjs +10 -6
  99. package/dist/react/components/types.cjs.map +1 -1
  100. package/dist/react/components/types.js +11 -9
  101. package/dist/react/components/types.js.map +1 -1
  102. package/dist/react/guards.cjs +10 -6
  103. package/dist/react/guards.cjs.map +1 -1
  104. package/dist/react/guards.js +11 -9
  105. package/dist/react/guards.js.map +1 -1
  106. package/dist/react/provider.cjs +23 -20
  107. package/dist/react/provider.cjs.map +1 -1
  108. package/dist/react/provider.js +23 -21
  109. package/dist/react/provider.js.map +1 -1
  110. package/dist/react/use-event-bus.cjs +24 -20
  111. package/dist/react/use-event-bus.cjs.map +1 -1
  112. package/dist/react/use-event-bus.js +24 -21
  113. package/dist/react/use-event-bus.js.map +1 -1
  114. package/dist/react/use-instance.cjs +43 -36
  115. package/dist/react/use-instance.cjs.map +1 -1
  116. package/dist/react/use-instance.js +43 -36
  117. package/dist/react/use-instance.js.map +1 -1
  118. package/dist/react/use-local.cjs +48 -64
  119. package/dist/react/use-local.cjs.map +1 -1
  120. package/dist/react/use-local.js +47 -63
  121. package/dist/react/use-local.js.map +1 -1
  122. package/dist/react/use-model.cjs +84 -98
  123. package/dist/react/use-model.cjs.map +1 -1
  124. package/dist/react/use-model.js +84 -100
  125. package/dist/react/use-model.js.map +1 -1
  126. package/dist/react/use-singleton.cjs +19 -23
  127. package/dist/react/use-singleton.cjs.map +1 -1
  128. package/dist/react/use-singleton.js +16 -20
  129. package/dist/react/use-singleton.js.map +1 -1
  130. package/dist/react/use-subscribe-only.cjs +28 -22
  131. package/dist/react/use-subscribe-only.cjs.map +1 -1
  132. package/dist/react/use-subscribe-only.js +28 -22
  133. package/dist/react/use-subscribe-only.js.map +1 -1
  134. package/dist/react/use-teardown.cjs +20 -19
  135. package/dist/react/use-teardown.cjs.map +1 -1
  136. package/dist/react/use-teardown.js +20 -19
  137. package/dist/react/use-teardown.js.map +1 -1
  138. package/dist/react-native/NativeCollection.cjs +98 -78
  139. package/dist/react-native/NativeCollection.cjs.map +1 -1
  140. package/dist/react-native/NativeCollection.js +97 -77
  141. package/dist/react-native/NativeCollection.js.map +1 -1
  142. package/dist/react-native.cjs +2 -4
  143. package/dist/react-native.js +1 -4
  144. package/dist/react.cjs +24 -26
  145. package/dist/react.js +1 -17
  146. package/dist/singleton.cjs +28 -22
  147. package/dist/singleton.cjs.map +1 -1
  148. package/dist/singleton.js +29 -26
  149. package/dist/singleton.js.map +1 -1
  150. package/dist/walkPrototypeChain.cjs +20 -12
  151. package/dist/walkPrototypeChain.cjs.map +1 -1
  152. package/dist/walkPrototypeChain.js +21 -13
  153. package/dist/walkPrototypeChain.js.map +1 -1
  154. package/dist/web/IndexedDBCollection.cjs +53 -36
  155. package/dist/web/IndexedDBCollection.cjs.map +1 -1
  156. package/dist/web/IndexedDBCollection.js +52 -35
  157. package/dist/web/IndexedDBCollection.js.map +1 -1
  158. package/dist/web/WebStorageCollection.cjs +82 -84
  159. package/dist/web/WebStorageCollection.cjs.map +1 -1
  160. package/dist/web/WebStorageCollection.js +81 -83
  161. package/dist/web/WebStorageCollection.js.map +1 -1
  162. package/dist/web/idb.cjs +107 -99
  163. package/dist/web/idb.cjs.map +1 -1
  164. package/dist/web/idb.js +108 -105
  165. package/dist/web/idb.js.map +1 -1
  166. package/dist/web.cjs +4 -6
  167. package/dist/web.js +1 -5
  168. package/dist/wrapAsyncMethods.cjs +141 -168
  169. package/dist/wrapAsyncMethods.cjs.map +1 -1
  170. package/dist/wrapAsyncMethods.js +141 -168
  171. package/dist/wrapAsyncMethods.js.map +1 -1
  172. package/package.json +8 -8
  173. package/src/Pending.test.ts +1 -2
  174. package/src/Sorting.test.ts +1 -1
  175. package/src/produceDraft.test.ts +3 -3
  176. package/src/react/components/CardList.test.tsx +1 -1
  177. package/src/react/components/DataTable.test.tsx +1 -1
  178. package/src/react/components/InfiniteScroll.test.tsx +5 -5
  179. package/dist/mvc-kit.cjs.map +0 -1
  180. package/dist/mvc-kit.js.map +0 -1
  181. package/dist/react-native.cjs.map +0 -1
  182. package/dist/react-native.js.map +0 -1
  183. package/dist/react.cjs.map +0 -1
  184. package/dist/react.js.map +0 -1
  185. package/dist/web.cjs.map +0 -1
  186. package/dist/web.js.map +0 -1
@@ -1,34 +1,40 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const registry = /* @__PURE__ */ new Map();
1
+ //#region src/singleton.ts
2
+ var registry = /* @__PURE__ */ new Map();
4
3
  function singleton(Class, ...args) {
5
- const existing = registry.get(Class);
6
- if (existing && !existing.disposed) {
7
- return existing;
8
- }
9
- const instance = args.length === 0 && "DEFAULT_STATE" in Class ? new Class(Class.DEFAULT_STATE) : new Class(...args);
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
- const existing = registry.get(Class);
15
- return existing !== void 0 && !existing.disposed;
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
- const instance = registry.get(Class);
19
- if (instance) {
20
- instance.dispose();
21
- registry.delete(Class);
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
- for (const instance of registry.values()) {
26
- instance.dispose();
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
- //# sourceMappingURL=singleton.cjs.map
39
+
40
+ //# sourceMappingURL=singleton.cjs.map
@@ -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"],"names":[],"mappings":";;AAMA,MAAM,+BAAe,IAAA;AAgBd,SAAS,UACd,UACG,MACA;AACH,QAAM,WAAW,SAAS,IAAI,KAA2B;AAEzD,MAAI,YAAY,CAAC,SAAS,UAAU;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,WAAY,KAAK,WAAW,KAAK,mBAAmB,QACtD,IAAI,MAAM,MAAM,aAAa,IAC7B,IAAI,MAAM,GAAG,IAAI;AAErB,WAAS,IAAI,OAA6B,QAAQ;AAClD,SAAO;AACT;AAMO,SAAS,aAAa,OAAoD;AAC/E,QAAM,WAAW,SAAS,IAAI,KAAK;AACnC,SAAO,aAAa,UAAa,CAAC,SAAS;AAC7C;AAMO,SAAS,SAAS,OAAiD;AACxE,QAAM,WAAW,SAAS,IAAI,KAAK;AACnC,MAAI,UAAU;AACZ,aAAS,QAAA;AACT,aAAS,OAAO,KAAK;AAAA,EACvB;AACF;AAKO,SAAS,cAAoB;AAClC,aAAW,YAAY,SAAS,UAAU;AACxC,aAAS,QAAA;AAAA,EACX;AACA,WAAS,MAAA;AACX;;;;;"}
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
- const registry = /* @__PURE__ */ new Map();
1
+ //#region src/singleton.ts
2
+ var registry = /* @__PURE__ */ new Map();
2
3
  function singleton(Class, ...args) {
3
- const existing = registry.get(Class);
4
- if (existing && !existing.disposed) {
5
- return existing;
6
- }
7
- const instance = args.length === 0 && "DEFAULT_STATE" in Class ? new Class(Class.DEFAULT_STATE) : new Class(...args);
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
- const existing = registry.get(Class);
13
- return existing !== void 0 && !existing.disposed;
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
- const instance = registry.get(Class);
17
- if (instance) {
18
- instance.dispose();
19
- registry.delete(Class);
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
- for (const instance of registry.values()) {
24
- instance.dispose();
25
- }
26
- registry.clear();
31
+ for (const instance of registry.values()) instance.dispose();
32
+ registry.clear();
27
33
  }
28
- export {
29
- hasSingleton,
30
- singleton,
31
- teardown,
32
- teardownAll
33
- };
34
- //# sourceMappingURL=singleton.js.map
34
+ //#endregion
35
+ export { hasSingleton, singleton, teardown, teardownAll };
36
+
37
+ //# sourceMappingURL=singleton.js.map
@@ -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"],"names":[],"mappings":"AAMA,MAAM,+BAAe,IAAA;AAgBd,SAAS,UACd,UACG,MACA;AACH,QAAM,WAAW,SAAS,IAAI,KAA2B;AAEzD,MAAI,YAAY,CAAC,SAAS,UAAU;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,WAAY,KAAK,WAAW,KAAK,mBAAmB,QACtD,IAAI,MAAM,MAAM,aAAa,IAC7B,IAAI,MAAM,GAAG,IAAI;AAErB,WAAS,IAAI,OAA6B,QAAQ;AAClD,SAAO;AACT;AAMO,SAAS,aAAa,OAAoD;AAC/E,QAAM,WAAW,SAAS,IAAI,KAAK;AACnC,SAAO,aAAa,UAAa,CAAC,SAAS;AAC7C;AAMO,SAAS,SAAS,OAAiD;AACxE,QAAM,WAAW,SAAS,IAAI,KAAK;AACnC,MAAI,UAAU;AACZ,aAAS,QAAA;AACT,aAAS,OAAO,KAAK;AAAA,EACvB;AACF;AAKO,SAAS,cAAoB;AAClC,aAAW,YAAY,SAAS,UAAU;AACxC,aAAS,QAAA;AAAA,EACX;AACA,WAAS,MAAA;AACX;"}
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
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
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
- let proto = Object.getPrototypeOf(instance);
5
- while (proto && proto !== stopAt) {
6
- const descriptors = Object.getOwnPropertyDescriptors(proto);
7
- for (const [key, desc] of Object.entries(descriptors)) {
8
- if (key === "constructor") continue;
9
- visitor(key, desc, proto);
10
- }
11
- proto = Object.getPrototypeOf(proto);
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
- //# sourceMappingURL=walkPrototypeChain.cjs.map
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"],"names":[],"mappings":";;AAOO,SAAS,mBACd,UACA,QACA,SACM;AACN,MAAI,QAAQ,OAAO,eAAe,QAAQ;AAC1C,SAAO,SAAS,UAAU,QAAQ;AAChC,UAAM,cAAc,OAAO,0BAA0B,KAAK;AAC1D,eAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACrD,UAAI,QAAQ,cAAe;AAC3B,cAAQ,KAAK,MAAM,KAAK;AAAA,IAC1B;AACA,YAAQ,OAAO,eAAe,KAAK;AAAA,EACrC;AACF;;"}
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
- let proto = Object.getPrototypeOf(instance);
3
- while (proto && proto !== stopAt) {
4
- const descriptors = Object.getOwnPropertyDescriptors(proto);
5
- for (const [key, desc] of Object.entries(descriptors)) {
6
- if (key === "constructor") continue;
7
- visitor(key, desc, proto);
8
- }
9
- proto = Object.getPrototypeOf(proto);
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
- export {
13
- walkPrototypeChain
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"],"names":[],"mappings":"AAOO,SAAS,mBACd,UACA,QACA,SACM;AACN,MAAI,QAAQ,OAAO,eAAe,QAAQ;AAC1C,SAAO,SAAS,UAAU,QAAQ;AAChC,UAAM,cAAc,OAAO,0BAA0B,KAAK;AAC1D,eAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,WAAW,GAAG;AACrD,UAAI,QAAQ,cAAe;AAC3B,cAAQ,KAAK,MAAM,KAAK;AAAA,IAC1B;AACA,YAAQ,OAAO,eAAe,KAAK;AAAA,EACrC;AACF;"}
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
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const PersistentCollection = require("../PersistentCollection.cjs");
4
- const idb = require("./idb.cjs");
5
- class IndexedDBCollection extends PersistentCollection.PersistentCollection {
6
- /** IndexedDB database name. Override to use a separate database. */
7
- static DB_NAME = "mvc-kit";
8
- get _dbName() {
9
- return this.constructor.DB_NAME;
10
- }
11
- _getStore(mode) {
12
- return idb.getStore(this._dbName, this.storageKey, mode);
13
- }
14
- // ── Persist interface (per-item strategy) ──
15
- async persistGetAll() {
16
- const store = await this._getStore("readonly");
17
- return idb.idbGetAll(store);
18
- }
19
- async persistGet(id) {
20
- const store = await this._getStore("readonly");
21
- return idb.idbGet(store, id);
22
- }
23
- async persistSet(items) {
24
- const store = await this._getStore("readwrite");
25
- return idb.idbPut(store, items);
26
- }
27
- async persistRemove(ids) {
28
- const store = await this._getStore("readwrite");
29
- return idb.idbDelete(store, ids);
30
- }
31
- async persistClear() {
32
- const store = await this._getStore("readwrite");
33
- return idb.idbClear(store);
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
- //# sourceMappingURL=IndexedDBCollection.cjs.map
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"],"names":["PersistentCollection","getStore","idbGetAll","idbGet","idbPut","idbDelete","idbClear"],"mappings":";;;;AAyBO,MAAe,4BAEZA,qBAAAA,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAAU;AAAA,EAEjB,IAAY,UAAkB;AAC5B,WAAQ,KAAK,YAA2C;AAAA,EAC1D;AAAA,EAEQ,UAAU,MAA0B;AAC1C,WAAOC,IAAAA,SAAS,KAAK,SAAS,KAAK,YAAY,IAAI;AAAA,EACrD;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAOC,IAAAA,UAAa,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAOC,IAAAA,OAAU,OAAO,EAAiB;AAAA,EAC3C;AAAA,EAEA,MAAgB,WAAW,OAA2B;AACpD,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAgB,cAAc,KAA+B;AAC3D,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,UAAU,OAAO,GAAoB;AAAA,EAC9C;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAOC,IAAAA,SAAS,KAAK;AAAA,EACvB;AACF;;"}
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, idbGetAll, idbGet, idbPut, idbDelete, idbClear } from "./idb.js";
3
- class IndexedDBCollection extends PersistentCollection {
4
- /** IndexedDB database name. Override to use a separate database. */
5
- static DB_NAME = "mvc-kit";
6
- get _dbName() {
7
- return this.constructor.DB_NAME;
8
- }
9
- _getStore(mode) {
10
- return getStore(this._dbName, this.storageKey, mode);
11
- }
12
- // ── Persist interface (per-item strategy) ──
13
- async persistGetAll() {
14
- const store = await this._getStore("readonly");
15
- return idbGetAll(store);
16
- }
17
- async persistGet(id) {
18
- const store = await this._getStore("readonly");
19
- return idbGet(store, id);
20
- }
21
- async persistSet(items) {
22
- const store = await this._getStore("readwrite");
23
- return idbPut(store, items);
24
- }
25
- async persistRemove(ids) {
26
- const store = await this._getStore("readwrite");
27
- return idbDelete(store, ids);
28
- }
29
- async persistClear() {
30
- const store = await this._getStore("readwrite");
31
- return idbClear(store);
32
- }
33
- }
34
- export {
35
- IndexedDBCollection
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
- //# sourceMappingURL=IndexedDBCollection.js.map
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"],"names":[],"mappings":";;AAyBO,MAAe,4BAEZ,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAAU;AAAA,EAEjB,IAAY,UAAkB;AAC5B,WAAQ,KAAK,YAA2C;AAAA,EAC1D;AAAA,EAEQ,UAAU,MAA0B;AAC1C,WAAO,SAAS,KAAK,SAAS,KAAK,YAAY,IAAI;AAAA,EACrD;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAO,UAAa,KAAK;AAAA,EAC3B;AAAA,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,QAAQ,MAAM,KAAK,UAAU,UAAU;AAC7C,WAAO,OAAU,OAAO,EAAiB;AAAA,EAC3C;AAAA,EAEA,MAAgB,WAAW,OAA2B;AACpD,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,OAAO,OAAO,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAgB,cAAc,KAA+B;AAC3D,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,UAAU,OAAO,GAAoB;AAAA,EAC9C;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,QAAQ,MAAM,KAAK,UAAU,WAAW;AAC9C,WAAO,SAAS,KAAK;AAAA,EACvB;AACF;"}
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"}