mvc-kit 2.12.4 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,22 +1,23 @@
1
- import { useRef, useEffect } from "react";
2
1
  import { teardown } from "../singleton.js";
2
+ import { useEffect, useRef } from "react";
3
+ //#region src/react/use-teardown.ts
4
+ /**
5
+ * Teardown singleton class(es) on unmount.
6
+ * Uses deferred disposal to handle StrictMode's double-mount cycle.
7
+ */
3
8
  function useTeardown(...Classes) {
4
- const mountedRef = useRef(false);
5
- useEffect(() => {
6
- mountedRef.current = true;
7
- return () => {
8
- mountedRef.current = false;
9
- setTimeout(() => {
10
- if (!mountedRef.current) {
11
- for (const Class of Classes) {
12
- teardown(Class);
13
- }
14
- }
15
- }, 0);
16
- };
17
- }, []);
9
+ const mountedRef = useRef(false);
10
+ useEffect(() => {
11
+ mountedRef.current = true;
12
+ return () => {
13
+ mountedRef.current = false;
14
+ setTimeout(() => {
15
+ if (!mountedRef.current) for (const Class of Classes) teardown(Class);
16
+ }, 0);
17
+ };
18
+ }, []);
18
19
  }
19
- export {
20
- useTeardown
21
- };
22
- //# sourceMappingURL=use-teardown.js.map
20
+ //#endregion
21
+ export { useTeardown };
22
+
23
+ //# sourceMappingURL=use-teardown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-teardown.js","sources":["../../src/react/use-teardown.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { Disposable } from '../types';\nimport { teardown } from '../singleton';\n\n/**\n * Teardown singleton class(es) on unmount.\n * Uses deferred disposal to handle StrictMode's double-mount cycle.\n */\nexport function useTeardown(\n ...Classes: Array<new (...args: unknown[]) => Disposable>\n): void {\n const mountedRef = useRef(false);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n for (const Class of Classes) {\n teardown(Class);\n }\n }\n }, 0);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n"],"names":[],"mappings":";;AAQO,SAAS,eACX,SACG;AACN,QAAM,aAAa,OAAO,KAAK;AAE/B,YAAU,MAAM;AACd,eAAW,UAAU;AACrB,WAAO,MAAM;AACX,iBAAW,UAAU;AACrB,iBAAW,MAAM;AACf,YAAI,CAAC,WAAW,SAAS;AACvB,qBAAW,SAAS,SAAS;AAC3B,qBAAS,KAAK;AAAA,UAChB;AAAA,QACF;AAAA,MACF,GAAG,CAAC;AAAA,IACN;AAAA,EACF,GAAG,CAAA,CAAE;AACP;"}
1
+ {"version":3,"file":"use-teardown.js","names":[],"sources":["../../src/react/use-teardown.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { Disposable } from '../types';\nimport { teardown } from '../singleton';\n\n/**\n * Teardown singleton class(es) on unmount.\n * Uses deferred disposal to handle StrictMode's double-mount cycle.\n */\nexport function useTeardown(\n ...Classes: Array<new (...args: unknown[]) => Disposable>\n): void {\n const mountedRef = useRef(false);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n setTimeout(() => {\n if (!mountedRef.current) {\n for (const Class of Classes) {\n teardown(Class);\n }\n }\n }, 0);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,YACd,GAAG,SACG;CACN,MAAM,aAAa,OAAO,MAAM;AAEhC,iBAAgB;AACd,aAAW,UAAU;AACrB,eAAa;AACX,cAAW,UAAU;AACrB,oBAAiB;AACf,QAAI,CAAC,WAAW,QACd,MAAK,MAAM,SAAS,QAClB,UAAS,MAAM;MAGlB,EAAE;;IAEN,EAAE,CAAC"}
@@ -1,79 +1,99 @@
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
- let _adapter = null;
6
- class NativeCollection extends PersistentCollection.PersistentCollection {
7
- /**
8
- * Configure the default storage adapter for all NativeCollection subclasses.
9
- * Call once at app startup. Per-class method overrides take priority.
10
- */
11
- static configure(adapter) {
12
- _adapter = adapter;
13
- }
14
- /** Reset the configured adapter (for testing). */
15
- static resetAdapter() {
16
- _adapter = null;
17
- }
18
- // ── Per-class override points ──
19
- /** Read a value from the storage adapter. Override for custom storage backends. @protected */
20
- getItem(key) {
21
- if (_adapter) return _adapter.getItem(key);
22
- if (__DEV__) {
23
- throw new Error(
24
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
25
- );
26
- }
27
- throw new Error("[mvc-kit] No storage adapter configured.");
28
- }
29
- /** Write a value to the storage adapter. Override for custom storage backends. @protected */
30
- setItem(key, value) {
31
- if (_adapter) return _adapter.setItem(key, value);
32
- if (__DEV__) {
33
- throw new Error(
34
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
35
- );
36
- }
37
- throw new Error("[mvc-kit] No storage adapter configured.");
38
- }
39
- /** Remove a value from the storage adapter. Override for custom storage backends. @protected */
40
- removeItem(key) {
41
- if (_adapter) return _adapter.removeItem(key);
42
- if (__DEV__) {
43
- throw new Error(
44
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
45
- );
46
- }
47
- throw new Error("[mvc-kit] No storage adapter configured.");
48
- }
49
- // ── Persist interface (blob strategy) ──
50
- async persistGetAll() {
51
- const raw = await this.getItem(this.storageKey);
52
- if (!raw) return [];
53
- try {
54
- return this.deserialize(raw);
55
- } catch {
56
- if (__DEV__) {
57
- console.warn(
58
- `[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
59
- );
60
- }
61
- return [];
62
- }
63
- }
64
- async persistGet(id) {
65
- const all = await this.persistGetAll();
66
- return all.find((i) => i.id === id) ?? null;
67
- }
68
- async persistSet(_items) {
69
- await this.setItem(this.storageKey, this.serialize([...this.items]));
70
- }
71
- async persistRemove(_ids) {
72
- await this.setItem(this.storageKey, this.serialize([...this.items]));
73
- }
74
- async persistClear() {
75
- await this.removeItem(this.storageKey);
76
- }
77
- }
1
+ const require_PersistentCollection = require("../PersistentCollection.cjs");
2
+ //#region src/react-native/NativeCollection.ts
3
+ var __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
4
+ var _adapter = null;
5
+ /**
6
+ * PersistentCollection for React Native, backed by any async key-value store.
7
+ * Uses blob strategy (full state as a single JSON string under `storageKey`).
8
+ *
9
+ * **Requires manual `hydrate()` call** (async storage).
10
+ *
11
+ * ## Setup (once at app startup)
12
+ *
13
+ * ```ts
14
+ * import { NativeCollection } from 'mvc-kit/react-native';
15
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
16
+ *
17
+ * NativeCollection.configure({
18
+ * getItem: (key) => AsyncStorage.getItem(key),
19
+ * setItem: (key, value) => AsyncStorage.setItem(key, value),
20
+ * removeItem: (key) => AsyncStorage.removeItem(key),
21
+ * });
22
+ * ```
23
+ *
24
+ * ## Usage
25
+ *
26
+ * ```ts
27
+ * class TodosCollection extends NativeCollection<Todo> {
28
+ * protected readonly storageKey = 'todos';
29
+ * }
30
+ * ```
31
+ *
32
+ * ## Per-class override (edge cases)
33
+ *
34
+ * ```ts
35
+ * class SecureCollection extends NativeCollection<Secret> {
36
+ * protected readonly storageKey = 'secrets';
37
+ * protected async getItem(key: string) { return SecureStore.getItem(key); }
38
+ * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }
39
+ * protected async removeItem(key: string) { await SecureStore.removeItem(key); }
40
+ * }
41
+ * ```
42
+ */
43
+ var NativeCollection = class extends require_PersistentCollection.PersistentCollection {
44
+ /**
45
+ * Configure the default storage adapter for all NativeCollection subclasses.
46
+ * Call once at app startup. Per-class method overrides take priority.
47
+ */
48
+ static configure(adapter) {
49
+ _adapter = adapter;
50
+ }
51
+ /** Reset the configured adapter (for testing). */
52
+ static resetAdapter() {
53
+ _adapter = null;
54
+ }
55
+ /** Read a value from the storage adapter. Override for custom storage backends. @protected */
56
+ getItem(key) {
57
+ if (_adapter) return _adapter.getItem(key);
58
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
59
+ throw new Error("[mvc-kit] No storage adapter configured.");
60
+ }
61
+ /** Write a value to the storage adapter. Override for custom storage backends. @protected */
62
+ setItem(key, value) {
63
+ if (_adapter) return _adapter.setItem(key, value);
64
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
65
+ throw new Error("[mvc-kit] No storage adapter configured.");
66
+ }
67
+ /** Remove a value from the storage adapter. Override for custom storage backends. @protected */
68
+ removeItem(key) {
69
+ if (_adapter) return _adapter.removeItem(key);
70
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
71
+ throw new Error("[mvc-kit] No storage adapter configured.");
72
+ }
73
+ async persistGetAll() {
74
+ const raw = await this.getItem(this.storageKey);
75
+ if (!raw) return [];
76
+ try {
77
+ return this.deserialize(raw);
78
+ } catch {
79
+ if (__DEV__) console.warn(`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`);
80
+ return [];
81
+ }
82
+ }
83
+ async persistGet(id) {
84
+ return (await this.persistGetAll()).find((i) => i.id === id) ?? null;
85
+ }
86
+ async persistSet(_items) {
87
+ await this.setItem(this.storageKey, this.serialize([...this.items]));
88
+ }
89
+ async persistRemove(_ids) {
90
+ await this.setItem(this.storageKey, this.serialize([...this.items]));
91
+ }
92
+ async persistClear() {
93
+ await this.removeItem(this.storageKey);
94
+ }
95
+ };
96
+ //#endregion
78
97
  exports.NativeCollection = NativeCollection;
79
- //# sourceMappingURL=NativeCollection.cjs.map
98
+
99
+ //# sourceMappingURL=NativeCollection.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeCollection.cjs","sources":["../../src/react-native/NativeCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ninterface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\nlet _adapter: StorageAdapter | null = null;\n\n/**\n * PersistentCollection for React Native, backed by any async key-value store.\n * Uses blob strategy (full state as a single JSON string under `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n *\n * ## Setup (once at app startup)\n *\n * ```ts\n * import { NativeCollection } from 'mvc-kit/react-native';\n * import AsyncStorage from '@react-native-async-storage/async-storage';\n *\n * NativeCollection.configure({\n * getItem: (key) => AsyncStorage.getItem(key),\n * setItem: (key, value) => AsyncStorage.setItem(key, value),\n * removeItem: (key) => AsyncStorage.removeItem(key),\n * });\n * ```\n *\n * ## Usage\n *\n * ```ts\n * class TodosCollection extends NativeCollection<Todo> {\n * protected readonly storageKey = 'todos';\n * }\n * ```\n *\n * ## Per-class override (edge cases)\n *\n * ```ts\n * class SecureCollection extends NativeCollection<Secret> {\n * protected readonly storageKey = 'secrets';\n * protected async getItem(key: string) { return SecureStore.getItem(key); }\n * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }\n * protected async removeItem(key: string) { await SecureStore.removeItem(key); }\n * }\n * ```\n */\nexport abstract class NativeCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /**\n * Configure the default storage adapter for all NativeCollection subclasses.\n * Call once at app startup. Per-class method overrides take priority.\n */\n static configure(adapter: StorageAdapter): void {\n _adapter = adapter;\n }\n\n /** Reset the configured adapter (for testing). */\n static resetAdapter(): void {\n _adapter = null;\n }\n\n // ── Per-class override points ──\n\n /** Read a value from the storage adapter. Override for custom storage backends. @protected */\n protected getItem(key: string): Promise<string | null> {\n if (_adapter) return _adapter.getItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Write a value to the storage adapter. Override for custom storage backends. @protected */\n protected setItem(key: string, value: string): Promise<void> {\n if (_adapter) return _adapter.setItem(key, value);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Remove a value from the storage adapter. Override for custom storage backends. @protected */\n protected removeItem(key: string): Promise<void> {\n if (_adapter) return _adapter.removeItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const raw = await this.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 async persistGet(id: T['id']): Promise<T | null> {\n const all = await this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected async persistSet(_items: T[]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistRemove(_ids: T['id'][]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistClear(): Promise<void> {\n await this.removeItem(this.storageKey);\n }\n}\n"],"names":["PersistentCollection"],"mappings":";;;AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAQ1D,IAAI,WAAkC;AAwC/B,MAAe,yBAEZA,qBAAAA,qBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhC,OAAO,UAAU,SAA+B;AAC9C,eAAW;AAAA,EACb;AAAA;AAAA,EAGA,OAAO,eAAqB;AAC1B,eAAW;AAAA,EACb;AAAA;AAAA;AAAA,EAKU,QAAQ,KAAqC;AACrD,QAAI,SAAU,QAAO,SAAS,QAAQ,GAAG;AACzC,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAGU,QAAQ,KAAa,OAA8B;AAC3D,QAAI,SAAU,QAAO,SAAS,QAAQ,KAAK,KAAK;AAChD,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAGU,WAAW,KAA4B;AAC/C,QAAI,SAAU,QAAO,SAAS,WAAW,GAAG;AAC5C,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,UAAU;AAC9C,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,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,MAAM,MAAM,KAAK,cAAA;AACvB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEA,MAAgB,WAAW,QAA4B;AACrD,UAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,EACrE;AAAA,EAEA,MAAgB,cAAc,MAAgC;AAC5D,UAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,EACrE;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,KAAK,WAAW,KAAK,UAAU;AAAA,EACvC;AACF;;"}
1
+ {"version":3,"file":"NativeCollection.cjs","names":[],"sources":["../../src/react-native/NativeCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ninterface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\nlet _adapter: StorageAdapter | null = null;\n\n/**\n * PersistentCollection for React Native, backed by any async key-value store.\n * Uses blob strategy (full state as a single JSON string under `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n *\n * ## Setup (once at app startup)\n *\n * ```ts\n * import { NativeCollection } from 'mvc-kit/react-native';\n * import AsyncStorage from '@react-native-async-storage/async-storage';\n *\n * NativeCollection.configure({\n * getItem: (key) => AsyncStorage.getItem(key),\n * setItem: (key, value) => AsyncStorage.setItem(key, value),\n * removeItem: (key) => AsyncStorage.removeItem(key),\n * });\n * ```\n *\n * ## Usage\n *\n * ```ts\n * class TodosCollection extends NativeCollection<Todo> {\n * protected readonly storageKey = 'todos';\n * }\n * ```\n *\n * ## Per-class override (edge cases)\n *\n * ```ts\n * class SecureCollection extends NativeCollection<Secret> {\n * protected readonly storageKey = 'secrets';\n * protected async getItem(key: string) { return SecureStore.getItem(key); }\n * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }\n * protected async removeItem(key: string) { await SecureStore.removeItem(key); }\n * }\n * ```\n */\nexport abstract class NativeCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /**\n * Configure the default storage adapter for all NativeCollection subclasses.\n * Call once at app startup. Per-class method overrides take priority.\n */\n static configure(adapter: StorageAdapter): void {\n _adapter = adapter;\n }\n\n /** Reset the configured adapter (for testing). */\n static resetAdapter(): void {\n _adapter = null;\n }\n\n // ── Per-class override points ──\n\n /** Read a value from the storage adapter. Override for custom storage backends. @protected */\n protected getItem(key: string): Promise<string | null> {\n if (_adapter) return _adapter.getItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Write a value to the storage adapter. Override for custom storage backends. @protected */\n protected setItem(key: string, value: string): Promise<void> {\n if (_adapter) return _adapter.setItem(key, value);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Remove a value from the storage adapter. Override for custom storage backends. @protected */\n protected removeItem(key: string): Promise<void> {\n if (_adapter) return _adapter.removeItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const raw = await this.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 async persistGet(id: T['id']): Promise<T | null> {\n const all = await this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected async persistSet(_items: T[]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistRemove(_ids: T['id'][]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistClear(): Promise<void> {\n await this.removeItem(this.storageKey);\n }\n}\n"],"mappings":";;AAEA,IAAM,UAAU,OAAO,oBAAoB,eAAe;AAQ1D,IAAI,WAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCtC,IAAsB,mBAAtB,cAEU,6BAAA,qBAAwB;;;;;CAKhC,OAAO,UAAU,SAA+B;AAC9C,aAAW;;;CAIb,OAAO,eAAqB;AAC1B,aAAW;;;CAMb,QAAkB,KAAqC;AACrD,MAAI,SAAU,QAAO,SAAS,QAAQ,IAAI;AAC1C,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;;CAI7D,QAAkB,KAAa,OAA8B;AAC3D,MAAI,SAAU,QAAO,SAAS,QAAQ,KAAK,MAAM;AACjD,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;;CAI7D,WAAqB,KAA4B;AAC/C,MAAI,SAAU,QAAO,SAAS,WAAW,IAAI;AAC7C,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;CAK7D,MAAgB,gBAA8B;EAC5C,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,WAAW;AAC/C,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,MAAgB,WAAW,IAAgC;AAEzD,UADY,MAAM,KAAK,eAAe,EAC3B,MAAM,MAAM,EAAE,OAAO,GAAG,IAAI;;CAGzC,MAAgB,WAAW,QAA4B;AACrD,QAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;;CAGtE,MAAgB,cAAc,MAAgC;AAC5D,QAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;;CAGtE,MAAgB,eAA8B;AAC5C,QAAM,KAAK,WAAW,KAAK,WAAW"}
@@ -1,79 +1,99 @@
1
1
  import { PersistentCollection } from "../PersistentCollection.js";
2
- const __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
3
- let _adapter = null;
4
- class NativeCollection extends PersistentCollection {
5
- /**
6
- * Configure the default storage adapter for all NativeCollection subclasses.
7
- * Call once at app startup. Per-class method overrides take priority.
8
- */
9
- static configure(adapter) {
10
- _adapter = adapter;
11
- }
12
- /** Reset the configured adapter (for testing). */
13
- static resetAdapter() {
14
- _adapter = null;
15
- }
16
- // ── Per-class override points ──
17
- /** Read a value from the storage adapter. Override for custom storage backends. @protected */
18
- getItem(key) {
19
- if (_adapter) return _adapter.getItem(key);
20
- if (__DEV__) {
21
- throw new Error(
22
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
23
- );
24
- }
25
- throw new Error("[mvc-kit] No storage adapter configured.");
26
- }
27
- /** Write a value to the storage adapter. Override for custom storage backends. @protected */
28
- setItem(key, value) {
29
- if (_adapter) return _adapter.setItem(key, value);
30
- if (__DEV__) {
31
- throw new Error(
32
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
33
- );
34
- }
35
- throw new Error("[mvc-kit] No storage adapter configured.");
36
- }
37
- /** Remove a value from the storage adapter. Override for custom storage backends. @protected */
38
- removeItem(key) {
39
- if (_adapter) return _adapter.removeItem(key);
40
- if (__DEV__) {
41
- throw new Error(
42
- `[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`
43
- );
44
- }
45
- throw new Error("[mvc-kit] No storage adapter configured.");
46
- }
47
- // ── Persist interface (blob strategy) ──
48
- async persistGetAll() {
49
- const raw = await this.getItem(this.storageKey);
50
- if (!raw) return [];
51
- try {
52
- return this.deserialize(raw);
53
- } catch {
54
- if (__DEV__) {
55
- console.warn(
56
- `[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`
57
- );
58
- }
59
- return [];
60
- }
61
- }
62
- async persistGet(id) {
63
- const all = await this.persistGetAll();
64
- return all.find((i) => i.id === id) ?? null;
65
- }
66
- async persistSet(_items) {
67
- await this.setItem(this.storageKey, this.serialize([...this.items]));
68
- }
69
- async persistRemove(_ids) {
70
- await this.setItem(this.storageKey, this.serialize([...this.items]));
71
- }
72
- async persistClear() {
73
- await this.removeItem(this.storageKey);
74
- }
75
- }
76
- export {
77
- NativeCollection
2
+ //#region src/react-native/NativeCollection.ts
3
+ var __DEV__ = typeof __MVC_KIT_DEV__ !== "undefined" && __MVC_KIT_DEV__;
4
+ var _adapter = null;
5
+ /**
6
+ * PersistentCollection for React Native, backed by any async key-value store.
7
+ * Uses blob strategy (full state as a single JSON string under `storageKey`).
8
+ *
9
+ * **Requires manual `hydrate()` call** (async storage).
10
+ *
11
+ * ## Setup (once at app startup)
12
+ *
13
+ * ```ts
14
+ * import { NativeCollection } from 'mvc-kit/react-native';
15
+ * import AsyncStorage from '@react-native-async-storage/async-storage';
16
+ *
17
+ * NativeCollection.configure({
18
+ * getItem: (key) => AsyncStorage.getItem(key),
19
+ * setItem: (key, value) => AsyncStorage.setItem(key, value),
20
+ * removeItem: (key) => AsyncStorage.removeItem(key),
21
+ * });
22
+ * ```
23
+ *
24
+ * ## Usage
25
+ *
26
+ * ```ts
27
+ * class TodosCollection extends NativeCollection<Todo> {
28
+ * protected readonly storageKey = 'todos';
29
+ * }
30
+ * ```
31
+ *
32
+ * ## Per-class override (edge cases)
33
+ *
34
+ * ```ts
35
+ * class SecureCollection extends NativeCollection<Secret> {
36
+ * protected readonly storageKey = 'secrets';
37
+ * protected async getItem(key: string) { return SecureStore.getItem(key); }
38
+ * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }
39
+ * protected async removeItem(key: string) { await SecureStore.removeItem(key); }
40
+ * }
41
+ * ```
42
+ */
43
+ var NativeCollection = class extends PersistentCollection {
44
+ /**
45
+ * Configure the default storage adapter for all NativeCollection subclasses.
46
+ * Call once at app startup. Per-class method overrides take priority.
47
+ */
48
+ static configure(adapter) {
49
+ _adapter = adapter;
50
+ }
51
+ /** Reset the configured adapter (for testing). */
52
+ static resetAdapter() {
53
+ _adapter = null;
54
+ }
55
+ /** Read a value from the storage adapter. Override for custom storage backends. @protected */
56
+ getItem(key) {
57
+ if (_adapter) return _adapter.getItem(key);
58
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
59
+ throw new Error("[mvc-kit] No storage adapter configured.");
60
+ }
61
+ /** Write a value to the storage adapter. Override for custom storage backends. @protected */
62
+ setItem(key, value) {
63
+ if (_adapter) return _adapter.setItem(key, value);
64
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
65
+ throw new Error("[mvc-kit] No storage adapter configured.");
66
+ }
67
+ /** Remove a value from the storage adapter. Override for custom storage backends. @protected */
68
+ removeItem(key) {
69
+ if (_adapter) return _adapter.removeItem(key);
70
+ if (__DEV__) throw new Error(`[mvc-kit] No storage adapter configured for "${this.constructor.name}". Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`);
71
+ throw new Error("[mvc-kit] No storage adapter configured.");
72
+ }
73
+ async persistGetAll() {
74
+ const raw = await this.getItem(this.storageKey);
75
+ if (!raw) return [];
76
+ try {
77
+ return this.deserialize(raw);
78
+ } catch {
79
+ if (__DEV__) console.warn(`[mvc-kit] Corrupted data in storage key "${this.storageKey}". Ignoring stored data.`);
80
+ return [];
81
+ }
82
+ }
83
+ async persistGet(id) {
84
+ return (await this.persistGetAll()).find((i) => i.id === id) ?? null;
85
+ }
86
+ async persistSet(_items) {
87
+ await this.setItem(this.storageKey, this.serialize([...this.items]));
88
+ }
89
+ async persistRemove(_ids) {
90
+ await this.setItem(this.storageKey, this.serialize([...this.items]));
91
+ }
92
+ async persistClear() {
93
+ await this.removeItem(this.storageKey);
94
+ }
78
95
  };
79
- //# sourceMappingURL=NativeCollection.js.map
96
+ //#endregion
97
+ export { NativeCollection };
98
+
99
+ //# sourceMappingURL=NativeCollection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NativeCollection.js","sources":["../../src/react-native/NativeCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ninterface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\nlet _adapter: StorageAdapter | null = null;\n\n/**\n * PersistentCollection for React Native, backed by any async key-value store.\n * Uses blob strategy (full state as a single JSON string under `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n *\n * ## Setup (once at app startup)\n *\n * ```ts\n * import { NativeCollection } from 'mvc-kit/react-native';\n * import AsyncStorage from '@react-native-async-storage/async-storage';\n *\n * NativeCollection.configure({\n * getItem: (key) => AsyncStorage.getItem(key),\n * setItem: (key, value) => AsyncStorage.setItem(key, value),\n * removeItem: (key) => AsyncStorage.removeItem(key),\n * });\n * ```\n *\n * ## Usage\n *\n * ```ts\n * class TodosCollection extends NativeCollection<Todo> {\n * protected readonly storageKey = 'todos';\n * }\n * ```\n *\n * ## Per-class override (edge cases)\n *\n * ```ts\n * class SecureCollection extends NativeCollection<Secret> {\n * protected readonly storageKey = 'secrets';\n * protected async getItem(key: string) { return SecureStore.getItem(key); }\n * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }\n * protected async removeItem(key: string) { await SecureStore.removeItem(key); }\n * }\n * ```\n */\nexport abstract class NativeCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /**\n * Configure the default storage adapter for all NativeCollection subclasses.\n * Call once at app startup. Per-class method overrides take priority.\n */\n static configure(adapter: StorageAdapter): void {\n _adapter = adapter;\n }\n\n /** Reset the configured adapter (for testing). */\n static resetAdapter(): void {\n _adapter = null;\n }\n\n // ── Per-class override points ──\n\n /** Read a value from the storage adapter. Override for custom storage backends. @protected */\n protected getItem(key: string): Promise<string | null> {\n if (_adapter) return _adapter.getItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Write a value to the storage adapter. Override for custom storage backends. @protected */\n protected setItem(key: string, value: string): Promise<void> {\n if (_adapter) return _adapter.setItem(key, value);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Remove a value from the storage adapter. Override for custom storage backends. @protected */\n protected removeItem(key: string): Promise<void> {\n if (_adapter) return _adapter.removeItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const raw = await this.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 async persistGet(id: T['id']): Promise<T | null> {\n const all = await this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected async persistSet(_items: T[]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistRemove(_ids: T['id'][]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistClear(): Promise<void> {\n await this.removeItem(this.storageKey);\n }\n}\n"],"names":[],"mappings":";AAEA,MAAM,UAAU,OAAO,oBAAoB,eAAe;AAQ1D,IAAI,WAAkC;AAwC/B,MAAe,yBAEZ,qBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKhC,OAAO,UAAU,SAA+B;AAC9C,eAAW;AAAA,EACb;AAAA;AAAA,EAGA,OAAO,eAAqB;AAC1B,eAAW;AAAA,EACb;AAAA;AAAA;AAAA,EAKU,QAAQ,KAAqC;AACrD,QAAI,SAAU,QAAO,SAAS,QAAQ,GAAG;AACzC,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAGU,QAAQ,KAAa,OAA8B;AAC3D,QAAI,SAAU,QAAO,SAAS,QAAQ,KAAK,KAAK;AAChD,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAGU,WAAW,KAA4B;AAC/C,QAAI,SAAU,QAAO,SAAS,WAAW,GAAG;AAC5C,QAAI,SAAS;AACX,YAAM,IAAI;AAAA,QACR,gDAAgD,KAAK,YAAY,IAAI;AAAA,MAAA;AAAA,IAGzE;AACA,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAAA;AAAA,EAIA,MAAgB,gBAA8B;AAC5C,UAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,UAAU;AAC9C,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,EAEA,MAAgB,WAAW,IAAgC;AACzD,UAAM,MAAM,MAAM,KAAK,cAAA;AACvB,WAAO,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACzC;AAAA,EAEA,MAAgB,WAAW,QAA4B;AACrD,UAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,EACrE;AAAA,EAEA,MAAgB,cAAc,MAAgC;AAC5D,UAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AAAA,EACrE;AAAA,EAEA,MAAgB,eAA8B;AAC5C,UAAM,KAAK,WAAW,KAAK,UAAU;AAAA,EACvC;AACF;"}
1
+ {"version":3,"file":"NativeCollection.js","names":[],"sources":["../../src/react-native/NativeCollection.ts"],"sourcesContent":["import { PersistentCollection } from '../PersistentCollection';\n\nconst __DEV__ = typeof __MVC_KIT_DEV__ !== 'undefined' && __MVC_KIT_DEV__;\n\ninterface StorageAdapter {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n}\n\nlet _adapter: StorageAdapter | null = null;\n\n/**\n * PersistentCollection for React Native, backed by any async key-value store.\n * Uses blob strategy (full state as a single JSON string under `storageKey`).\n *\n * **Requires manual `hydrate()` call** (async storage).\n *\n * ## Setup (once at app startup)\n *\n * ```ts\n * import { NativeCollection } from 'mvc-kit/react-native';\n * import AsyncStorage from '@react-native-async-storage/async-storage';\n *\n * NativeCollection.configure({\n * getItem: (key) => AsyncStorage.getItem(key),\n * setItem: (key, value) => AsyncStorage.setItem(key, value),\n * removeItem: (key) => AsyncStorage.removeItem(key),\n * });\n * ```\n *\n * ## Usage\n *\n * ```ts\n * class TodosCollection extends NativeCollection<Todo> {\n * protected readonly storageKey = 'todos';\n * }\n * ```\n *\n * ## Per-class override (edge cases)\n *\n * ```ts\n * class SecureCollection extends NativeCollection<Secret> {\n * protected readonly storageKey = 'secrets';\n * protected async getItem(key: string) { return SecureStore.getItem(key); }\n * protected async setItem(key: string, value: string) { await SecureStore.setItem(key, value); }\n * protected async removeItem(key: string) { await SecureStore.removeItem(key); }\n * }\n * ```\n */\nexport abstract class NativeCollection<\n T extends { id: string | number },\n> extends PersistentCollection<T> {\n /**\n * Configure the default storage adapter for all NativeCollection subclasses.\n * Call once at app startup. Per-class method overrides take priority.\n */\n static configure(adapter: StorageAdapter): void {\n _adapter = adapter;\n }\n\n /** Reset the configured adapter (for testing). */\n static resetAdapter(): void {\n _adapter = null;\n }\n\n // ── Per-class override points ──\n\n /** Read a value from the storage adapter. Override for custom storage backends. @protected */\n protected getItem(key: string): Promise<string | null> {\n if (_adapter) return _adapter.getItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Write a value to the storage adapter. Override for custom storage backends. @protected */\n protected setItem(key: string, value: string): Promise<void> {\n if (_adapter) return _adapter.setItem(key, value);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n /** Remove a value from the storage adapter. Override for custom storage backends. @protected */\n protected removeItem(key: string): Promise<void> {\n if (_adapter) return _adapter.removeItem(key);\n if (__DEV__) {\n throw new Error(\n `[mvc-kit] No storage adapter configured for \"${this.constructor.name}\". ` +\n `Call NativeCollection.configure() at app startup, or override getItem/setItem/removeItem.`,\n );\n }\n throw new Error('[mvc-kit] No storage adapter configured.');\n }\n\n // ── Persist interface (blob strategy) ──\n\n protected async persistGetAll(): Promise<T[]> {\n const raw = await this.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 async persistGet(id: T['id']): Promise<T | null> {\n const all = await this.persistGetAll();\n return all.find((i) => i.id === id) ?? null;\n }\n\n protected async persistSet(_items: T[]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistRemove(_ids: T['id'][]): Promise<void> {\n await this.setItem(this.storageKey, this.serialize([...this.items]));\n }\n\n protected async persistClear(): Promise<void> {\n await this.removeItem(this.storageKey);\n }\n}\n"],"mappings":";;AAEA,IAAM,UAAU,OAAO,oBAAoB,eAAe;AAQ1D,IAAI,WAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCtC,IAAsB,mBAAtB,cAEU,qBAAwB;;;;;CAKhC,OAAO,UAAU,SAA+B;AAC9C,aAAW;;;CAIb,OAAO,eAAqB;AAC1B,aAAW;;;CAMb,QAAkB,KAAqC;AACrD,MAAI,SAAU,QAAO,SAAS,QAAQ,IAAI;AAC1C,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;;CAI7D,QAAkB,KAAa,OAA8B;AAC3D,MAAI,SAAU,QAAO,SAAS,QAAQ,KAAK,MAAM;AACjD,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;;CAI7D,WAAqB,KAA4B;AAC/C,MAAI,SAAU,QAAO,SAAS,WAAW,IAAI;AAC7C,MAAI,QACF,OAAM,IAAI,MACR,gDAAgD,KAAK,YAAY,KAAK,8FAEvE;AAEH,QAAM,IAAI,MAAM,2CAA2C;;CAK7D,MAAgB,gBAA8B;EAC5C,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,WAAW;AAC/C,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,MAAgB,WAAW,IAAgC;AAEzD,UADY,MAAM,KAAK,eAAe,EAC3B,MAAM,MAAM,EAAE,OAAO,GAAG,IAAI;;CAGzC,MAAgB,WAAW,QAA4B;AACrD,QAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;;CAGtE,MAAgB,cAAc,MAAgC;AAC5D,QAAM,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU,CAAC,GAAG,KAAK,MAAM,CAAC,CAAC;;CAGtE,MAAgB,eAA8B;AAC5C,QAAM,KAAK,WAAW,KAAK,WAAW"}
@@ -1,5 +1,3 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const NativeCollection = require("./react-native/NativeCollection.cjs");
4
- exports.NativeCollection = NativeCollection.NativeCollection;
5
- //# sourceMappingURL=react-native.cjs.map
2
+ const require_NativeCollection = require("./react-native/NativeCollection.cjs");
3
+ exports.NativeCollection = require_NativeCollection.NativeCollection;
@@ -1,5 +1,2 @@
1
1
  import { NativeCollection } from "./react-native/NativeCollection.js";
2
- export {
3
- NativeCollection
4
- };
5
- //# sourceMappingURL=react-native.js.map
2
+ export { NativeCollection };
package/dist/react.cjs CHANGED
@@ -1,27 +1,25 @@
1
- "use strict";
2
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const useInstance = require("./react/use-instance.cjs");
4
- const useLocal = require("./react/use-local.cjs");
5
- const useSingleton = require("./react/use-singleton.cjs");
6
- const useModel = require("./react/use-model.cjs");
7
- const useEventBus = require("./react/use-event-bus.cjs");
8
- const useTeardown = require("./react/use-teardown.cjs");
9
- const provider = require("./react/provider.cjs");
10
- const DataTable = require("./react/components/DataTable.cjs");
11
- const CardList = require("./react/components/CardList.cjs");
12
- const InfiniteScroll = require("./react/components/InfiniteScroll.cjs");
13
- exports.useInstance = useInstance.useInstance;
14
- exports.useLocal = useLocal.useLocal;
15
- exports.useSingleton = useSingleton.useSingleton;
16
- exports.useField = useModel.useField;
17
- exports.useModel = useModel.useModel;
18
- exports.useModelRef = useModel.useModelRef;
19
- exports.useEmit = useEventBus.useEmit;
20
- exports.useEvent = useEventBus.useEvent;
21
- exports.useTeardown = useTeardown.useTeardown;
22
- exports.Provider = provider.Provider;
23
- exports.useResolve = provider.useResolve;
24
- exports.DataTable = DataTable.DataTable;
25
- exports.CardList = CardList.CardList;
26
- exports.InfiniteScroll = InfiniteScroll.InfiniteScroll;
27
- //# sourceMappingURL=react.cjs.map
2
+ const require_use_instance = require("./react/use-instance.cjs");
3
+ const require_use_local = require("./react/use-local.cjs");
4
+ const require_use_singleton = require("./react/use-singleton.cjs");
5
+ const require_use_model = require("./react/use-model.cjs");
6
+ const require_use_event_bus = require("./react/use-event-bus.cjs");
7
+ const require_use_teardown = require("./react/use-teardown.cjs");
8
+ const require_provider = require("./react/provider.cjs");
9
+ const require_DataTable = require("./react/components/DataTable.cjs");
10
+ const require_CardList = require("./react/components/CardList.cjs");
11
+ const require_InfiniteScroll = require("./react/components/InfiniteScroll.cjs");
12
+ exports.CardList = require_CardList.CardList;
13
+ exports.DataTable = require_DataTable.DataTable;
14
+ exports.InfiniteScroll = require_InfiniteScroll.InfiniteScroll;
15
+ exports.Provider = require_provider.Provider;
16
+ exports.useEmit = require_use_event_bus.useEmit;
17
+ exports.useEvent = require_use_event_bus.useEvent;
18
+ exports.useField = require_use_model.useField;
19
+ exports.useInstance = require_use_instance.useInstance;
20
+ exports.useLocal = require_use_local.useLocal;
21
+ exports.useModel = require_use_model.useModel;
22
+ exports.useModelRef = require_use_model.useModelRef;
23
+ exports.useResolve = require_provider.useResolve;
24
+ exports.useSingleton = require_use_singleton.useSingleton;
25
+ exports.useTeardown = require_use_teardown.useTeardown;
package/dist/react.js CHANGED
@@ -8,20 +8,4 @@ import { Provider, useResolve } from "./react/provider.js";
8
8
  import { DataTable } from "./react/components/DataTable.js";
9
9
  import { CardList } from "./react/components/CardList.js";
10
10
  import { InfiniteScroll } from "./react/components/InfiniteScroll.js";
11
- export {
12
- CardList,
13
- DataTable,
14
- InfiniteScroll,
15
- Provider,
16
- useEmit,
17
- useEvent,
18
- useField,
19
- useInstance,
20
- useLocal,
21
- useModel,
22
- useModelRef,
23
- useResolve,
24
- useSingleton,
25
- useTeardown
26
- };
27
- //# sourceMappingURL=react.js.map
11
+ export { CardList, DataTable, InfiniteScroll, Provider, useEmit, useEvent, useField, useInstance, useLocal, useModel, useModelRef, useResolve, useSingleton, useTeardown };