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,85 +1,83 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const PersistentCollection = require("../PersistentCollection.cjs");
4
- const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
5
- class WebStorageCollection extends PersistentCollection.PersistentCollection {
6
- /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
7
- static STORAGE = "local";
8
- _autoHydrated = false;
9
- get _storage() {
10
- return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
11
- }
12
- _ensureHydrated() {
13
- if (this._autoHydrated) return;
14
- this._autoHydrated = true;
15
- this._hydrateSync();
16
- }
17
- // ── Override access points to trigger lazy hydration ──
18
- get items() {
19
- this._ensureHydrated();
20
- return super.items;
21
- }
22
- get state() {
23
- return this.items;
24
- }
25
- get length() {
26
- this._ensureHydrated();
27
- return super.length;
28
- }
29
- get(id) {
30
- this._ensureHydrated();
31
- return super.get(id);
32
- }
33
- has(id) {
34
- this._ensureHydrated();
35
- return super.has(id);
36
- }
37
- // ── Persist interface (blob strategy) ──
38
- persistGetAll() {
39
- const raw = this._storage.getItem(this.storageKey);
40
- if (!raw) return [];
41
- try {
42
- return this.deserialize(raw);
43
- } catch {
44
- if (__DEV__) {
45
- console.warn(
46
- `[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
47
- );
48
- }
49
- return [];
50
- }
51
- }
52
- persistGet(id) {
53
- const all = this.persistGetAll();
54
- return all.find((i) => i.id === id) ?? null;
55
- }
56
- persistSet(_items) {
57
- try {
58
- this._storage.setItem(this.storageKey, this.serialize([...this.items]));
59
- } catch (err) {
60
- if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
61
- console.warn(
62
- `[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
63
- );
64
- }
65
- throw err;
66
- }
67
- }
68
- persistRemove(_ids) {
69
- try {
70
- this._storage.setItem(this.storageKey, this.serialize([...this.items]));
71
- } catch (err) {
72
- if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
73
- console.warn(
74
- `[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
75
- );
76
- }
77
- throw err;
78
- }
79
- }
80
- persistClear() {
81
- this._storage.removeItem(this.storageKey);
82
- }
83
- }
1
+ const require_PersistentCollection = require("../PersistentCollection.cjs");
2
+ //#region src/web/WebStorageCollection.ts
3
+ var __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
4
+ /**
5
+ * PersistentCollection backed by localStorage or sessionStorage.
6
+ * Auto-hydrates on first access (sync storage no need for manual `hydrate()` call).
7
+ *
8
+ * Uses blob strategy: all items stored as a single JSON string under `storageKey`.
9
+ *
10
+ * ```ts
11
+ * class CartCollection extends WebStorageCollection<CartItem> {
12
+ * protected readonly storageKey = 'cart';
13
+ * }
14
+ * ```
15
+ */
16
+ var WebStorageCollection = class extends require_PersistentCollection.PersistentCollection {
17
+ /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
18
+ static STORAGE = "local";
19
+ _autoHydrated = false;
20
+ get _storage() {
21
+ return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
22
+ }
23
+ _ensureHydrated() {
24
+ if (this._autoHydrated) return;
25
+ this._autoHydrated = true;
26
+ this._hydrateSync();
27
+ }
28
+ get items() {
29
+ this._ensureHydrated();
30
+ return super.items;
31
+ }
32
+ get state() {
33
+ return this.items;
34
+ }
35
+ get length() {
36
+ this._ensureHydrated();
37
+ return super.length;
38
+ }
39
+ get(id) {
40
+ this._ensureHydrated();
41
+ return super.get(id);
42
+ }
43
+ has(id) {
44
+ this._ensureHydrated();
45
+ return super.has(id);
46
+ }
47
+ persistGetAll() {
48
+ const raw = this._storage.getItem(this.storageKey);
49
+ if (!raw) return [];
50
+ try {
51
+ return this.deserialize(raw);
52
+ } catch {
53
+ if (__DEV__) console.warn(`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`);
54
+ return [];
55
+ }
56
+ }
57
+ persistGet(id) {
58
+ return this.persistGetAll().find((i) => i.id === id) ?? null;
59
+ }
60
+ persistSet(_items) {
61
+ try {
62
+ this._storage.setItem(this.storageKey, this.serialize([...this.items]));
63
+ } catch (err) {
64
+ if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") console.warn(`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`);
65
+ throw err;
66
+ }
67
+ }
68
+ persistRemove(_ids) {
69
+ try {
70
+ this._storage.setItem(this.storageKey, this.serialize([...this.items]));
71
+ } catch (err) {
72
+ if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") console.warn(`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`);
73
+ throw err;
74
+ }
75
+ }
76
+ persistClear() {
77
+ this._storage.removeItem(this.storageKey);
78
+ }
79
+ };
80
+ //#endregion
84
81
  exports.WebStorageCollection = WebStorageCollection;
85
- //# sourceMappingURL=WebStorageCollection.cjs.map
82
+
83
+ //# sourceMappingURL=WebStorageCollection.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebStorageCollection.cjs","sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"names":["PersistentCollection"],"mappings":";;;AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAcnD,MAAe,6BAEZA,qBAAAA,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAA+B;AAAA,EAE9B,gBAAgB;AAAA,EAExB,IAAY,WAAoB;AAC9B,WAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;AAAA,EACN;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,cAAe;AACxB,SAAK,gBAAgB;AACrB,SAAK,aAAA;AAAA,EACP;AAAA;AAAA,EAIA,IAAI,QAAa;AACf,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAiB;AACnB,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,IAA4B;AAC9B,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA,EAEA,IAAI,IAAsB;AACxB,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA;AAAA,EAIU,gBAAqB;AAC7B,UAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,UAAU;AACjD,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,QAAI;AACF,aAAO,KAAK,YAAY,GAAG;AAAA,IAC7B,QAAQ;AACN,UAAI,SAAS;AACX,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAE/D;AACA,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEU,WAAW,IAAuB;AAC1C,UAAM,MAAM,KAAK,cAAA;AACjB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEU,WAAW,QAAmB;AACtC,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,cAAc,MAAuB;AAC7C,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,eAAqB;AAC7B,SAAK,SAAS,WAAW,KAAK,UAAU;AAAA,EAC1C;AACF;;"}
1
+ {"version":3,"file":"WebStorageCollection.cjs","names":[],"sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"mappings":";;AAEA,IAAM,UAAU,OAAO,oBAAoB,eAAe;;;;;;;;;;;;;AAc1D,IAAsB,uBAAtB,cAEU,6BAAA,qBAAwB;;CAEhC,OAAO,UAA+B;CAEtC,gBAAwB;CAExB,IAAY,WAAoB;AAC9B,SAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;;CAGN,kBAAgC;AAC9B,MAAI,KAAK,cAAe;AACxB,OAAK,gBAAgB;AACrB,OAAK,cAAc;;CAKrB,IAAI,QAAa;AACf,OAAK,iBAAiB;AACtB,SAAO,MAAM;;CAGf,IAAI,QAAa;AACf,SAAO,KAAK;;CAGd,IAAI,SAAiB;AACnB,OAAK,iBAAiB;AACtB,SAAO,MAAM;;CAGf,IAAI,IAA4B;AAC9B,OAAK,iBAAiB;AACtB,SAAO,MAAM,IAAI,GAAG;;CAGtB,IAAI,IAAsB;AACxB,OAAK,iBAAiB;AACtB,SAAO,MAAM,IAAI,GAAG;;CAKtB,gBAA+B;EAC7B,MAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,WAAW;AAClD,MAAI,CAAC,IAAK,QAAO,EAAE;AACnB,MAAI;AACF,UAAO,KAAK,YAAY,IAAI;UACtB;AACN,OAAI,QACF,SAAQ,KACN,4CAA4C,KAAK,WAAW,0BAC7D;AAEH,UAAO,EAAE;;;CAIb,WAAqB,IAAuB;AAE1C,SADY,KAAK,eAAe,CACrB,MAAM,MAAM,EAAE,OAAO,GAAG,IAAI;;CAGzC,WAAqB,QAAmB;AACtC,MAAI;AACF,QAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;WAChE,KAAK;AACZ,OAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,qBACzD,SAAQ,KACN,4CAA4C,KAAK,WAAW,4DAE7D;AAEH,SAAM;;;CAIV,cAAwB,MAAuB;AAC7C,MAAI;AACF,QAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;WAChE,KAAK;AACZ,OAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,qBACzD,SAAQ,KACN,4CAA4C,KAAK,WAAW,4DAE7D;AAEH,SAAM;;;CAIV,eAA+B;AAC7B,OAAK,SAAS,WAAW,KAAK,WAAW"}
@@ -1,85 +1,83 @@
1
1
  import { PersistentCollection } from "../PersistentCollection.js";
2
- const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
3
- class WebStorageCollection extends PersistentCollection {
4
- /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
5
- static STORAGE = "local";
6
- _autoHydrated = false;
7
- get _storage() {
8
- return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
9
- }
10
- _ensureHydrated() {
11
- if (this._autoHydrated) return;
12
- this._autoHydrated = true;
13
- this._hydrateSync();
14
- }
15
- // ── Override access points to trigger lazy hydration ──
16
- get items() {
17
- this._ensureHydrated();
18
- return super.items;
19
- }
20
- get state() {
21
- return this.items;
22
- }
23
- get length() {
24
- this._ensureHydrated();
25
- return super.length;
26
- }
27
- get(id) {
28
- this._ensureHydrated();
29
- return super.get(id);
30
- }
31
- has(id) {
32
- this._ensureHydrated();
33
- return super.has(id);
34
- }
35
- // ── Persist interface (blob strategy) ──
36
- persistGetAll() {
37
- const raw = this._storage.getItem(this.storageKey);
38
- if (!raw) return [];
39
- try {
40
- return this.deserialize(raw);
41
- } catch {
42
- if (__DEV__) {
43
- console.warn(
44
- `[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
45
- );
46
- }
47
- return [];
48
- }
49
- }
50
- persistGet(id) {
51
- const all = this.persistGetAll();
52
- return all.find((i) => i.id === id) ?? null;
53
- }
54
- persistSet(_items) {
55
- try {
56
- this._storage.setItem(this.storageKey, this.serialize([...this.items]));
57
- } catch (err) {
58
- if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
59
- console.warn(
60
- `[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
61
- );
62
- }
63
- throw err;
64
- }
65
- }
66
- persistRemove(_ids) {
67
- try {
68
- this._storage.setItem(this.storageKey, this.serialize([...this.items]));
69
- } catch (err) {
70
- if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") {
71
- console.warn(
72
- `[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`
73
- );
74
- }
75
- throw err;
76
- }
77
- }
78
- persistClear() {
79
- this._storage.removeItem(this.storageKey);
80
- }
81
- }
82
- export {
83
- WebStorageCollection
2
+ //#region src/web/WebStorageCollection.ts
3
+ var __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
4
+ /**
5
+ * PersistentCollection backed by localStorage or sessionStorage.
6
+ * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).
7
+ *
8
+ * Uses blob strategy: all items stored as a single JSON string under `storageKey`.
9
+ *
10
+ * ```ts
11
+ * class CartCollection extends WebStorageCollection<CartItem> {
12
+ * protected readonly storageKey = 'cart';
13
+ * }
14
+ * ```
15
+ */
16
+ var WebStorageCollection = class extends PersistentCollection {
17
+ /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */
18
+ static STORAGE = "local";
19
+ _autoHydrated = false;
20
+ get _storage() {
21
+ return this.constructor.STORAGE === "session" ? sessionStorage : localStorage;
22
+ }
23
+ _ensureHydrated() {
24
+ if (this._autoHydrated) return;
25
+ this._autoHydrated = true;
26
+ this._hydrateSync();
27
+ }
28
+ get items() {
29
+ this._ensureHydrated();
30
+ return super.items;
31
+ }
32
+ get state() {
33
+ return this.items;
34
+ }
35
+ get length() {
36
+ this._ensureHydrated();
37
+ return super.length;
38
+ }
39
+ get(id) {
40
+ this._ensureHydrated();
41
+ return super.get(id);
42
+ }
43
+ has(id) {
44
+ this._ensureHydrated();
45
+ return super.has(id);
46
+ }
47
+ persistGetAll() {
48
+ const raw = this._storage.getItem(this.storageKey);
49
+ if (!raw) return [];
50
+ try {
51
+ return this.deserialize(raw);
52
+ } catch {
53
+ if (__DEV__) console.warn(`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`);
54
+ return [];
55
+ }
56
+ }
57
+ persistGet(id) {
58
+ return this.persistGetAll().find((i) => i.id === id) ?? null;
59
+ }
60
+ persistSet(_items) {
61
+ try {
62
+ this._storage.setItem(this.storageKey, this.serialize([...this.items]));
63
+ } catch (err) {
64
+ if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") console.warn(`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`);
65
+ throw err;
66
+ }
67
+ }
68
+ persistRemove(_ids) {
69
+ try {
70
+ this._storage.setItem(this.storageKey, this.serialize([...this.items]));
71
+ } catch (err) {
72
+ if (__DEV__ && err instanceof DOMException && err.name === "QuotaExceededError") console.warn(`[mvc-kit] QuotaExceededError writing to "${this.storageKey}". Consider using IndexedDBCollection for larger datasets.`);
73
+ throw err;
74
+ }
75
+ }
76
+ persistClear() {
77
+ this._storage.removeItem(this.storageKey);
78
+ }
84
79
  };
85
- //# sourceMappingURL=WebStorageCollection.js.map
80
+ //#endregion
81
+ export { WebStorageCollection };
82
+
83
+ //# sourceMappingURL=WebStorageCollection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebStorageCollection.js","sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAcnD,MAAe,6BAEZ,qBAAwB;AAAA;AAAA,EAEhC,OAAO,UAA+B;AAAA,EAE9B,gBAAgB;AAAA,EAExB,IAAY,WAAoB;AAC9B,WAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;AAAA,EACN;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,cAAe;AACxB,SAAK,gBAAgB;AACrB,SAAK,aAAA;AAAA,EACP;AAAA;AAAA,EAIA,IAAI,QAAa;AACf,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,QAAa;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAiB;AACnB,SAAK,gBAAA;AACL,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,IAAI,IAA4B;AAC9B,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA,EAEA,IAAI,IAAsB;AACxB,SAAK,gBAAA;AACL,WAAO,MAAM,IAAI,EAAE;AAAA,EACrB;AAAA;AAAA,EAIU,gBAAqB;AAC7B,UAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,UAAU;AACjD,QAAI,CAAC,IAAK,QAAO,CAAA;AACjB,QAAI;AACF,aAAO,KAAK,YAAY,GAAG;AAAA,IAC7B,QAAQ;AACN,UAAI,SAAS;AACX,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAE/D;AACA,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEU,WAAW,IAAuB;AAC1C,UAAM,MAAM,KAAK,cAAA;AACjB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEU,WAAW,QAAmB;AACtC,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,cAAc,MAAuB;AAC7C,QAAI;AACF,WAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,IACxE,SAAS,KAAK;AACZ,UAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,sBAAsB;AAC/E,gBAAQ;AAAA,UACN,4CAA4C,KAAK,UAAU;AAAA,QAAA;AAAA,MAG/D;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEU,eAAqB;AAC7B,SAAK,SAAS,WAAW,KAAK,UAAU;AAAA,EAC1C;AACF;"}
1
+ {"version":3,"file":"WebStorageCollection.js","names":[],"sources":["../../src/web/WebStorageCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\n/**\n * PersistentCollection backed by localStorage or sessionStorage.\n * Auto-hydrates on first access (sync storage — no need for manual `hydrate()` call).\n *\n * Uses blob strategy: all items stored as a single JSON string under `storageKey`.\n *\n * ```ts\n * class CartCollection extends WebStorageCollection<CartItem> {\n * protected readonly storageKey = 'cart';\n * }\n * ```\n */\nexport abstract class WebStorageCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /** Which Web Storage backend to use. Override to 'session' for sessionStorage. */\n static STORAGE: 'local' | 'session' = 'local';\n\n private _autoHydrated = false;\n\n private get _storage(): Storage {\n return (this.constructor as typeof WebStorageCollection).STORAGE === 'session'\n ? sessionStorage\n : localStorage;\n }\n\n private _ensureHydrated(): void {\n if (this._autoHydrated) return;\n this._autoHydrated = true;\n this._hydrateSync();\n }\n\n // ── Override access points to trigger lazy hydration ──\n\n get items(): T[] {\n this._ensureHydrated();\n return super.items;\n }\n\n get state(): T[] {\n return this.items;\n }\n\n get length(): number {\n this._ensureHydrated();\n return super.length;\n }\n\n get(id: T['id']): T | undefined {\n this._ensureHydrated();\n return super.get(id);\n }\n\n has(id: T['id']): boolean {\n this._ensureHydrated();\n return super.has(id);\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected persistGetAll(): T[] {\n const raw = this._storage.getItem(this.storageKey);\n if (!raw) return [];\n try {\n return this.deserialize(raw);\n } catch {\n if (__DEV__) {\n console.warn(\n `[mvc-kit] Corrupted data in storage key \"${this.storageKey}\". Ignoring stored data.`,\n );\n }\n return [];\n }\n }\n\n protected persistGet(id: T['id']): T | null {\n const all = this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected persistSet(_items: T[]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistRemove(_ids: T['id'][]): void {\n try {\n this._storage.setItem(this.storageKey, this.serialize([...this.items]));\n } catch (err) {\n if (__DEV__ && err instanceof DOMException && err.name === 'QuotaExceededError') {\n console.warn(\n `[mvc-kit] QuotaExceededError writing to \"${this.storageKey}\". ` +\n `Consider using IndexedDBCollection for larger datasets.`,\n );\n }\n throw err;\n }\n }\n\n protected persistClear(): void {\n this._storage.removeItem(this.storageKey);\n }\n}\n"],"mappings":";;AAEA,IAAM,UAAU,OAAO,oBAAoB,eAAe;;;;;;;;;;;;;AAc1D,IAAsB,uBAAtB,cAEU,qBAAwB;;CAEhC,OAAO,UAA+B;CAEtC,gBAAwB;CAExB,IAAY,WAAoB;AAC9B,SAAQ,KAAK,YAA4C,YAAY,YACjE,iBACA;;CAGN,kBAAgC;AAC9B,MAAI,KAAK,cAAe;AACxB,OAAK,gBAAgB;AACrB,OAAK,cAAc;;CAKrB,IAAI,QAAa;AACf,OAAK,iBAAiB;AACtB,SAAO,MAAM;;CAGf,IAAI,QAAa;AACf,SAAO,KAAK;;CAGd,IAAI,SAAiB;AACnB,OAAK,iBAAiB;AACtB,SAAO,MAAM;;CAGf,IAAI,IAA4B;AAC9B,OAAK,iBAAiB;AACtB,SAAO,MAAM,IAAI,GAAG;;CAGtB,IAAI,IAAsB;AACxB,OAAK,iBAAiB;AACtB,SAAO,MAAM,IAAI,GAAG;;CAKtB,gBAA+B;EAC7B,MAAM,MAAM,KAAK,SAAS,QAAQ,KAAK,WAAW;AAClD,MAAI,CAAC,IAAK,QAAO,EAAE;AACnB,MAAI;AACF,UAAO,KAAK,YAAY,IAAI;UACtB;AACN,OAAI,QACF,SAAQ,KACN,4CAA4C,KAAK,WAAW,0BAC7D;AAEH,UAAO,EAAE;;;CAIb,WAAqB,IAAuB;AAE1C,SADY,KAAK,eAAe,CACrB,MAAM,MAAM,EAAE,OAAO,GAAG,IAAI;;CAGzC,WAAqB,QAAmB;AACtC,MAAI;AACF,QAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;WAChE,KAAK;AACZ,OAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,qBACzD,SAAQ,KACN,4CAA4C,KAAK,WAAW,4DAE7D;AAEH,SAAM;;;CAIV,cAAwB,MAAuB;AAC7C,MAAI;AACF,QAAK,SAAS,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;WAChE,KAAK;AACZ,OAAI,WAAW,eAAe,gBAAgB,IAAI,SAAS,qBACzD,SAAQ,KACN,4CAA4C,KAAK,WAAW,4DAE7D;AAEH,SAAM;;;CAIV,eAA+B;AAC7B,OAAK,SAAS,WAAW,KAAK,WAAW"}
package/dist/web/idb.cjs CHANGED
@@ -1,121 +1,129 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const _connections = /* @__PURE__ */ new Map();
4
- const _stores = /* @__PURE__ */ new Map();
5
- let _openQueue = Promise.resolve();
1
+ //#region src/web/idb.ts
2
+ /**
3
+ * Shared IndexedDB connection manager.
4
+ * Deduplicates indexedDB.open() calls and handles dynamic object store creation
5
+ * by bumping the DB version when a new storageKey is encountered.
6
+ */
7
+ var _connections = /* @__PURE__ */ new Map();
8
+ var _stores = /* @__PURE__ */ new Map();
9
+ var _openQueue = Promise.resolve();
6
10
  function openDB(dbName, storeName) {
7
- const existing = _connections.get(dbName);
8
- if (existing) {
9
- if (existing.objectStoreNames.contains(storeName)) {
10
- return Promise.resolve(existing);
11
- }
12
- existing.close();
13
- _connections.delete(dbName);
14
- }
15
- let stores = _stores.get(dbName);
16
- if (!stores) {
17
- stores = /* @__PURE__ */ new Set();
18
- _stores.set(dbName, stores);
19
- }
20
- stores.add(storeName);
21
- const result = _openQueue.then(() => doOpen(dbName, stores));
22
- _openQueue = result.then(() => {
23
- }, () => {
24
- });
25
- return result;
11
+ const existing = _connections.get(dbName);
12
+ if (existing) {
13
+ if (existing.objectStoreNames.contains(storeName)) return Promise.resolve(existing);
14
+ existing.close();
15
+ _connections.delete(dbName);
16
+ }
17
+ let stores = _stores.get(dbName);
18
+ if (!stores) {
19
+ stores = /* @__PURE__ */ new Set();
20
+ _stores.set(dbName, stores);
21
+ }
22
+ stores.add(storeName);
23
+ const result = _openQueue.then(() => doOpen(dbName, stores));
24
+ _openQueue = result.then(() => {}, () => {});
25
+ return result;
26
26
  }
27
27
  function doOpen(dbName, stores) {
28
- const existingDb = _connections.get(dbName);
29
- existingDb?.close();
30
- _connections.delete(dbName);
31
- return new Promise((resolve, reject) => {
32
- const probe = indexedDB.open(dbName);
33
- probe.onsuccess = () => {
34
- const db = probe.result;
35
- const version = db.version;
36
- let needsUpgrade = false;
37
- for (const name of stores) {
38
- if (!db.objectStoreNames.contains(name)) {
39
- needsUpgrade = true;
40
- break;
41
- }
42
- }
43
- if (!needsUpgrade) {
44
- _connections.set(dbName, db);
45
- resolve(db);
46
- return;
47
- }
48
- db.close();
49
- const upgrade = indexedDB.open(dbName, version + 1);
50
- upgrade.onupgradeneeded = () => {
51
- const udb = upgrade.result;
52
- for (const name of stores) {
53
- if (!udb.objectStoreNames.contains(name)) {
54
- udb.createObjectStore(name, { keyPath: "id" });
55
- }
56
- }
57
- };
58
- upgrade.onsuccess = () => {
59
- _connections.set(dbName, upgrade.result);
60
- resolve(upgrade.result);
61
- };
62
- upgrade.onerror = () => reject(upgrade.error);
63
- };
64
- probe.onerror = () => reject(probe.error);
65
- });
28
+ _connections.get(dbName)?.close();
29
+ _connections.delete(dbName);
30
+ return new Promise((resolve, reject) => {
31
+ const probe = indexedDB.open(dbName);
32
+ probe.onsuccess = () => {
33
+ const db = probe.result;
34
+ const version = db.version;
35
+ let needsUpgrade = false;
36
+ for (const name of stores) if (!db.objectStoreNames.contains(name)) {
37
+ needsUpgrade = true;
38
+ break;
39
+ }
40
+ if (!needsUpgrade) {
41
+ _connections.set(dbName, db);
42
+ resolve(db);
43
+ return;
44
+ }
45
+ db.close();
46
+ const upgrade = indexedDB.open(dbName, version + 1);
47
+ upgrade.onupgradeneeded = () => {
48
+ const udb = upgrade.result;
49
+ for (const name of stores) if (!udb.objectStoreNames.contains(name)) udb.createObjectStore(name, { keyPath: "id" });
50
+ };
51
+ upgrade.onsuccess = () => {
52
+ _connections.set(dbName, upgrade.result);
53
+ resolve(upgrade.result);
54
+ };
55
+ upgrade.onerror = () => reject(upgrade.error);
56
+ };
57
+ probe.onerror = () => reject(probe.error);
58
+ });
66
59
  }
60
+ /**
61
+ * Open a transaction and return the object store for the given database and store name.
62
+ */
67
63
  function getStore(dbName, storeName, mode) {
68
- return openDB(dbName, storeName).then((db) => {
69
- const tx = db.transaction(storeName, mode);
70
- return tx.objectStore(storeName);
71
- });
64
+ return openDB(dbName, storeName).then((db) => {
65
+ return db.transaction(storeName, mode).objectStore(storeName);
66
+ });
72
67
  }
68
+ /**
69
+ * Retrieve all items from an IndexedDB object store.
70
+ */
73
71
  function idbGetAll(store) {
74
- return new Promise((resolve, reject) => {
75
- const request = store.getAll();
76
- request.onsuccess = () => resolve(request.result);
77
- request.onerror = () => reject(request.error);
78
- });
72
+ return new Promise((resolve, reject) => {
73
+ const request = store.getAll();
74
+ request.onsuccess = () => resolve(request.result);
75
+ request.onerror = () => reject(request.error);
76
+ });
79
77
  }
78
+ /**
79
+ * Retrieve a single item by key from an IndexedDB object store.
80
+ */
80
81
  function idbGet(store, id) {
81
- return new Promise((resolve, reject) => {
82
- const request = store.get(id);
83
- request.onsuccess = () => resolve(request.result ?? null);
84
- request.onerror = () => reject(request.error);
85
- });
82
+ return new Promise((resolve, reject) => {
83
+ const request = store.get(id);
84
+ request.onsuccess = () => resolve(request.result ?? null);
85
+ request.onerror = () => reject(request.error);
86
+ });
86
87
  }
88
+ /**
89
+ * Write (put) multiple items into an IndexedDB object store.
90
+ */
87
91
  function idbPut(store, items) {
88
- return new Promise((resolve, reject) => {
89
- const tx = store.transaction;
90
- for (const item of items) {
91
- store.put(item);
92
- }
93
- tx.oncomplete = () => resolve();
94
- tx.onerror = () => reject(tx.error);
95
- });
92
+ return new Promise((resolve, reject) => {
93
+ const tx = store.transaction;
94
+ for (const item of items) store.put(item);
95
+ tx.oncomplete = () => resolve();
96
+ tx.onerror = () => reject(tx.error);
97
+ });
96
98
  }
99
+ /**
100
+ * Delete multiple items by key from an IndexedDB object store.
101
+ */
97
102
  function idbDelete(store, ids) {
98
- return new Promise((resolve, reject) => {
99
- const tx = store.transaction;
100
- for (const id of ids) {
101
- store.delete(id);
102
- }
103
- tx.oncomplete = () => resolve();
104
- tx.onerror = () => reject(tx.error);
105
- });
103
+ return new Promise((resolve, reject) => {
104
+ const tx = store.transaction;
105
+ for (const id of ids) store.delete(id);
106
+ tx.oncomplete = () => resolve();
107
+ tx.onerror = () => reject(tx.error);
108
+ });
106
109
  }
110
+ /**
111
+ * Clear all items from an IndexedDB object store.
112
+ */
107
113
  function idbClear(store) {
108
- return new Promise((resolve, reject) => {
109
- const tx = store.transaction;
110
- store.clear();
111
- tx.oncomplete = () => resolve();
112
- tx.onerror = () => reject(tx.error);
113
- });
114
+ return new Promise((resolve, reject) => {
115
+ const tx = store.transaction;
116
+ store.clear();
117
+ tx.oncomplete = () => resolve();
118
+ tx.onerror = () => reject(tx.error);
119
+ });
114
120
  }
121
+ //#endregion
115
122
  exports.getStore = getStore;
116
123
  exports.idbClear = idbClear;
117
124
  exports.idbDelete = idbDelete;
118
125
  exports.idbGet = idbGet;
119
126
  exports.idbGetAll = idbGetAll;
120
127
  exports.idbPut = idbPut;
121
- //# sourceMappingURL=idb.cjs.map
128
+
129
+ //# sourceMappingURL=idb.cjs.map