@iamjulianacosta/mobx-data 1.1.0 → 1.4.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 (203) hide show
  1. package/README.md +273 -102
  2. package/dist/{CacheHandler-BTU_rYkv.js → CacheHandler-BhfbVHed.js} +17 -20
  3. package/dist/CacheHandler-BhfbVHed.js.map +1 -0
  4. package/dist/{CacheHandler-CXgY9IJo.cjs → CacheHandler-Q5VXOgh9.cjs} +2 -2
  5. package/dist/CacheHandler-Q5VXOgh9.cjs.map +1 -0
  6. package/dist/EmbeddedRecordsMixin-6mSCXsJ3.js +173 -0
  7. package/dist/EmbeddedRecordsMixin-6mSCXsJ3.js.map +1 -0
  8. package/dist/EmbeddedRecordsMixin-BkF7MdbY.cjs +2 -0
  9. package/dist/EmbeddedRecordsMixin-BkF7MdbY.cjs.map +1 -0
  10. package/dist/{JsonApiSerializer-BLoE046A.js → JsonApiSerializer-BV61cFAZ.js} +3 -3
  11. package/dist/JsonApiSerializer-BV61cFAZ.js.map +1 -0
  12. package/dist/{JsonApiSerializer-DKemcyw-.cjs → JsonApiSerializer-Dt_Y_FIo.cjs} +2 -2
  13. package/dist/JsonApiSerializer-Dt_Y_FIo.cjs.map +1 -0
  14. package/dist/JsonSerializer-BzUCyUSf.cjs +2 -0
  15. package/dist/JsonSerializer-BzUCyUSf.cjs.map +1 -0
  16. package/dist/JsonSerializer-CFqo6GjC.js +98 -0
  17. package/dist/JsonSerializer-CFqo6GjC.js.map +1 -0
  18. package/dist/MdqlMemoryExecutor-BUlsalKm.cjs +2 -0
  19. package/dist/MdqlMemoryExecutor-BUlsalKm.cjs.map +1 -0
  20. package/dist/MdqlMemoryExecutor-BWMP31zG.js +127 -0
  21. package/dist/MdqlMemoryExecutor-BWMP31zG.js.map +1 -0
  22. package/dist/{MemoryAdapter-Bp-BGHH3.js → MemoryAdapter-BW1HKixm.js} +2 -2
  23. package/dist/{MemoryAdapter-Bp-BGHH3.js.map → MemoryAdapter-BW1HKixm.js.map} +1 -1
  24. package/dist/{MemoryAdapter-DH-gzSSl.cjs → MemoryAdapter-C8iXAa2v.cjs} +2 -2
  25. package/dist/{MemoryAdapter-DH-gzSSl.cjs.map → MemoryAdapter-C8iXAa2v.cjs.map} +1 -1
  26. package/dist/{ODataAdapter-RQUjVTcf.js → ODataAdapter-CeBJblLQ.js} +25 -22
  27. package/dist/ODataAdapter-CeBJblLQ.js.map +1 -0
  28. package/dist/{ODataAdapter-CrDFvBEZ.cjs → ODataAdapter-DdE6MWkG.cjs} +2 -2
  29. package/dist/ODataAdapter-DdE6MWkG.cjs.map +1 -0
  30. package/dist/RestAdapter-D7GSrsJo.cjs +2 -0
  31. package/dist/RestAdapter-D7GSrsJo.cjs.map +1 -0
  32. package/dist/{RestAdapter-D6bGIHZT.js → RestAdapter-DYUoyV5h.js} +112 -77
  33. package/dist/RestAdapter-DYUoyV5h.js.map +1 -0
  34. package/dist/SchemaService-C_pkh-vI.js +180 -0
  35. package/dist/SchemaService-C_pkh-vI.js.map +1 -0
  36. package/dist/SchemaService-DbJLoYb9.cjs +2 -0
  37. package/dist/SchemaService-DbJLoYb9.cjs.map +1 -0
  38. package/dist/Serializer-Bap9U-kR.cjs +2 -0
  39. package/dist/Serializer-Bap9U-kR.cjs.map +1 -0
  40. package/dist/{Serializer-FxJbsZ50.js → Serializer-Ca6w_QNQ.js} +63 -49
  41. package/dist/Serializer-Ca6w_QNQ.js.map +1 -0
  42. package/dist/adapter/index.cjs +1 -1
  43. package/dist/adapter/index.js +2 -2
  44. package/dist/createStore-7PecKT54.cjs +2 -0
  45. package/dist/createStore-7PecKT54.cjs.map +1 -0
  46. package/dist/createStore-BfmRfZ_2.js +1229 -0
  47. package/dist/createStore-BfmRfZ_2.js.map +1 -0
  48. package/dist/date-Bj4O2W1F.js.map +1 -1
  49. package/dist/date-CRCe-9gf.cjs.map +1 -1
  50. package/dist/decorators-CKneHgoF.js +56 -0
  51. package/dist/decorators-CKneHgoF.js.map +1 -0
  52. package/dist/decorators-DCVYKzrL.cjs +2 -0
  53. package/dist/decorators-DCVYKzrL.cjs.map +1 -0
  54. package/dist/index.cjs +1 -1
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.ts +2 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +100 -90
  59. package/dist/index.js.map +1 -1
  60. package/dist/inspector/ConsoleInspector.d.ts +49 -0
  61. package/dist/inspector/ConsoleInspector.d.ts.map +1 -0
  62. package/dist/inspector/DevToolsBridge.d.ts +21 -0
  63. package/dist/inspector/DevToolsBridge.d.ts.map +1 -0
  64. package/dist/inspector/QueryParser.d.ts +21 -0
  65. package/dist/inspector/QueryParser.d.ts.map +1 -0
  66. package/dist/inspector/StoreInspector.d.ts +31 -0
  67. package/dist/inspector/StoreInspector.d.ts.map +1 -0
  68. package/dist/inspector/index.cjs +17 -0
  69. package/dist/inspector/index.cjs.map +1 -0
  70. package/dist/inspector/index.d.ts +9 -0
  71. package/dist/inspector/index.d.ts.map +1 -0
  72. package/dist/inspector/index.js +896 -0
  73. package/dist/inspector/index.js.map +1 -0
  74. package/dist/inspector/integration.d.ts +15 -0
  75. package/dist/inspector/integration.d.ts.map +1 -0
  76. package/dist/inspector/serialization.d.ts +7 -0
  77. package/dist/inspector/serialization.d.ts.map +1 -0
  78. package/dist/inspector/types.d.ts +139 -0
  79. package/dist/inspector/types.d.ts.map +1 -0
  80. package/dist/json-api/index.cjs +1 -1
  81. package/dist/json-api/index.js +1 -1
  82. package/dist/mdql/MdqlMemoryExecutor.d.ts +17 -0
  83. package/dist/mdql/MdqlMemoryExecutor.d.ts.map +1 -0
  84. package/dist/mdql/MdqlQueryBuilder.d.ts +38 -0
  85. package/dist/mdql/MdqlQueryBuilder.d.ts.map +1 -0
  86. package/dist/mdql/MdqlValidator.d.ts +13 -0
  87. package/dist/mdql/MdqlValidator.d.ts.map +1 -0
  88. package/dist/mdql/index.d.ts +6 -0
  89. package/dist/mdql/index.d.ts.map +1 -0
  90. package/dist/mdql/types.d.ts +48 -0
  91. package/dist/mdql/types.d.ts.map +1 -0
  92. package/dist/model/Model.d.ts +4 -0
  93. package/dist/model/Model.d.ts.map +1 -1
  94. package/dist/model/Snapshot.d.ts +2 -0
  95. package/dist/model/Snapshot.d.ts.map +1 -1
  96. package/dist/model/index.cjs +1 -1
  97. package/dist/model/index.js +1 -1
  98. package/dist/odata/ODataAdapter.d.ts.map +1 -1
  99. package/dist/odata/index.cjs +1 -1
  100. package/dist/odata/index.js +1 -1
  101. package/dist/relationships-BgM0NKdb.cjs +2 -0
  102. package/dist/relationships-BgM0NKdb.cjs.map +1 -0
  103. package/dist/{relationships-BEXANmWg.js → relationships-DvSi8fVN.js} +37 -28
  104. package/dist/relationships-DvSi8fVN.js.map +1 -0
  105. package/dist/request/CacheHandler.d.ts.map +1 -1
  106. package/dist/request/index.cjs +1 -1
  107. package/dist/request/index.js +1 -1
  108. package/dist/schema/SchemaService.d.ts +38 -1
  109. package/dist/schema/SchemaService.d.ts.map +1 -1
  110. package/dist/schema/decorators.d.ts +20 -1
  111. package/dist/schema/decorators.d.ts.map +1 -1
  112. package/dist/schema/index.cjs +1 -1
  113. package/dist/schema/index.d.ts +1 -1
  114. package/dist/schema/index.d.ts.map +1 -1
  115. package/dist/schema/index.js +10 -8
  116. package/dist/schema/types.d.ts +31 -0
  117. package/dist/schema/types.d.ts.map +1 -1
  118. package/dist/serializer/JsonSerializer.d.ts +2 -0
  119. package/dist/serializer/JsonSerializer.d.ts.map +1 -1
  120. package/dist/serializer/Serializer.d.ts +9 -0
  121. package/dist/serializer/Serializer.d.ts.map +1 -1
  122. package/dist/serializer/index.cjs +1 -1
  123. package/dist/serializer/index.js +6 -5
  124. package/dist/serializer/index.js.map +1 -1
  125. package/dist/store/Store.d.ts +3 -0
  126. package/dist/store/Store.d.ts.map +1 -1
  127. package/dist/store/createStore.d.ts +12 -0
  128. package/dist/store/createStore.d.ts.map +1 -0
  129. package/dist/store/index.cjs +1 -1
  130. package/dist/store/index.d.ts +1 -0
  131. package/dist/store/index.d.ts.map +1 -1
  132. package/dist/store/index.js +5 -4
  133. package/dist/types-CC2fG3FP.js +8 -0
  134. package/dist/types-CC2fG3FP.js.map +1 -0
  135. package/dist/types-DCLy5XYj.cjs +2 -0
  136. package/dist/types-DCLy5XYj.cjs.map +1 -0
  137. package/package.json +7 -1
  138. package/src/index.ts +3 -0
  139. package/src/inspector/ConsoleInspector.ts +470 -0
  140. package/src/inspector/DevToolsBridge.ts +214 -0
  141. package/src/inspector/QueryParser.ts +343 -0
  142. package/src/inspector/StoreInspector.ts +162 -0
  143. package/src/inspector/index.ts +20 -0
  144. package/src/inspector/integration.ts +56 -0
  145. package/src/inspector/serialization.ts +100 -0
  146. package/src/inspector/types.ts +161 -0
  147. package/src/mdql/MdqlMemoryExecutor.ts +229 -0
  148. package/src/mdql/MdqlQueryBuilder.ts +170 -0
  149. package/src/mdql/MdqlValidator.ts +193 -0
  150. package/src/mdql/index.ts +21 -0
  151. package/src/mdql/types.ts +107 -0
  152. package/src/model/Model.ts +15 -0
  153. package/src/model/Snapshot.ts +3 -0
  154. package/src/odata/ODataAdapter.ts +4 -1
  155. package/src/request/CacheHandler.ts +2 -6
  156. package/src/schema/SchemaService.ts +123 -1
  157. package/src/schema/decorators.ts +29 -0
  158. package/src/schema/index.ts +1 -1
  159. package/src/schema/types.ts +34 -0
  160. package/src/serializer/JsonSerializer.ts +14 -2
  161. package/src/serializer/Serializer.ts +24 -1
  162. package/src/store/Store.ts +57 -14
  163. package/src/store/createStore.ts +39 -0
  164. package/src/store/index.ts +1 -0
  165. package/dist/CacheHandler-BTU_rYkv.js.map +0 -1
  166. package/dist/CacheHandler-CXgY9IJo.cjs.map +0 -1
  167. package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs +0 -2
  168. package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs.map +0 -1
  169. package/dist/EmbeddedRecordsMixin-VoHluHCT.js +0 -261
  170. package/dist/EmbeddedRecordsMixin-VoHluHCT.js.map +0 -1
  171. package/dist/JsonApiSerializer-BLoE046A.js.map +0 -1
  172. package/dist/JsonApiSerializer-DKemcyw-.cjs.map +0 -1
  173. package/dist/ODataAdapter-CrDFvBEZ.cjs.map +0 -1
  174. package/dist/ODataAdapter-RQUjVTcf.js.map +0 -1
  175. package/dist/RestAdapter-CSoJg7D2.cjs +0 -2
  176. package/dist/RestAdapter-CSoJg7D2.cjs.map +0 -1
  177. package/dist/RestAdapter-D6bGIHZT.js.map +0 -1
  178. package/dist/SchemaService-DZwkFgZu.js +0 -102
  179. package/dist/SchemaService-DZwkFgZu.js.map +0 -1
  180. package/dist/SchemaService-Di_yjVzU.cjs +0 -2
  181. package/dist/SchemaService-Di_yjVzU.cjs.map +0 -1
  182. package/dist/Serializer-95gi5edy.cjs +0 -2
  183. package/dist/Serializer-95gi5edy.cjs.map +0 -1
  184. package/dist/Serializer-FxJbsZ50.js.map +0 -1
  185. package/dist/Store-Bm5JivTc.js +0 -957
  186. package/dist/Store-Bm5JivTc.js.map +0 -1
  187. package/dist/Store-DX9D0Mmy.cjs +0 -2
  188. package/dist/Store-DX9D0Mmy.cjs.map +0 -1
  189. package/dist/cache-utils-B2wFhisx.js +0 -39
  190. package/dist/cache-utils-B2wFhisx.js.map +0 -1
  191. package/dist/cache-utils-CSwsqOi3.cjs +0 -2
  192. package/dist/cache-utils-CSwsqOi3.cjs.map +0 -1
  193. package/dist/decorators-HQ1KnRdh.cjs +0 -2
  194. package/dist/decorators-HQ1KnRdh.cjs.map +0 -1
  195. package/dist/decorators-Zr35qr6A.js +0 -50
  196. package/dist/decorators-Zr35qr6A.js.map +0 -1
  197. package/dist/relationships-B55LBaCW.cjs +0 -2
  198. package/dist/relationships-B55LBaCW.cjs.map +0 -1
  199. package/dist/relationships-BEXANmWg.js.map +0 -1
  200. package/dist/types-C9NB2gRj.js +0 -7
  201. package/dist/types-C9NB2gRj.js.map +0 -1
  202. package/dist/types-uWOXMPWW.cjs +0 -2
  203. package/dist/types-uWOXMPWW.cjs.map +0 -1
@@ -1,957 +0,0 @@
1
- import { singleton as M, injectable as F, inject as z } from "tsyringe";
2
- import { makeObservable as _, action as b, observable as y, computed as u, runInAction as p } from "mobx";
3
- import { S as D } from "./SchemaService-DZwkFgZu.js";
4
- import { b as S, A as C, a as E, M as O } from "./relationships-BEXANmWg.js";
5
- import { e as m, p as v } from "./cache-utils-B2wFhisx.js";
6
- class q {
7
- constructor() {
8
- this._buckets = /* @__PURE__ */ new Map(), _(this, {
9
- _buckets: y.shallow,
10
- set: b,
11
- delete: b,
12
- clear: b
13
- });
14
- }
15
- /**
16
- * Returns the bucket for `modelName`, optionally creating it when absent.
17
- * Internal helper — not part of the public API.
18
- */
19
- bucket(e, s = !1) {
20
- let i = this._buckets.get(e);
21
- return !i && s && (i = y.map({}, { deep: !1 }), this._buckets.set(e, i)), i;
22
- }
23
- /** Adds or replaces the record with the given `id` under `modelName`. */
24
- set(e, s, i) {
25
- this.bucket(e, !0).set(s, i);
26
- }
27
- /**
28
- * Returns the record for `modelName` + `id`, or `null` when not found.
29
- */
30
- get(e, s) {
31
- var i;
32
- return ((i = this.bucket(e)) == null ? void 0 : i.get(s)) ?? null;
33
- }
34
- /** Returns `true` when a record exists for `modelName` + `id`. */
35
- has(e, s) {
36
- var i;
37
- return ((i = this.bucket(e)) == null ? void 0 : i.has(s)) ?? !1;
38
- }
39
- /**
40
- * Removes the record for `modelName` + `id`.
41
- * @returns `true` when the record existed and was deleted.
42
- */
43
- delete(e, s) {
44
- var i;
45
- return ((i = this.bucket(e)) == null ? void 0 : i.delete(s)) ?? !1;
46
- }
47
- /** Returns all records stored under `modelName` as an array. */
48
- all(e) {
49
- const s = this.bucket(e);
50
- return s ? Array.from(s.values()) : [];
51
- }
52
- /**
53
- * Clears all records for `modelName`, or all records across all types when
54
- * `modelName` is omitted.
55
- */
56
- clear(e) {
57
- var s;
58
- if (e)
59
- (s = this.bucket(e)) == null || s.clear();
60
- else
61
- for (const i of this._buckets.values())
62
- i.clear();
63
- }
64
- /**
65
- * Returns the number of records stored for `modelName`, or the total across
66
- * all types when `modelName` is omitted.
67
- */
68
- size(e) {
69
- var i;
70
- if (e)
71
- return ((i = this.bucket(e)) == null ? void 0 : i.size) ?? 0;
72
- let s = 0;
73
- for (const a of this._buckets.values())
74
- s += a.size;
75
- return s;
76
- }
77
- }
78
- class k {
79
- constructor(e) {
80
- this.updating = !1, this.opts = e, _(this, {
81
- resolved: e.keepAlive ? u({ keepAlive: !0 }) : u,
82
- updating: y,
83
- length: u,
84
- modelName: u
85
- });
86
- }
87
- /** Current record list, derived from the injected `source` function. */
88
- get resolved() {
89
- return this.opts.source();
90
- }
91
- /** `true` while a background `update()` call is in progress. */
92
- get isLoading() {
93
- return this.updating;
94
- }
95
- /** Alias for `isLoading`. */
96
- get isUpdating() {
97
- return this.updating;
98
- }
99
- /** Number of records in the array. */
100
- get length() {
101
- return this.resolved.length;
102
- }
103
- /** The registered model name for the records in this array. */
104
- get modelName() {
105
- return this.opts.modelName;
106
- }
107
- /** Returns the record at `index`, or `undefined`. */
108
- at(e) {
109
- return this.resolved[e];
110
- }
111
- /** Returns a plain array snapshot of all records. */
112
- toArray() {
113
- return [...this.resolved];
114
- }
115
- /** Maps over records. */
116
- map(e) {
117
- return this.resolved.map(e);
118
- }
119
- /** Filters records. */
120
- filter(e) {
121
- return this.resolved.filter(e);
122
- }
123
- /** Iterates records. */
124
- forEach(e) {
125
- this.resolved.forEach(e);
126
- }
127
- /** Returns `true` when `record` is in the array. */
128
- includes(e) {
129
- return this.resolved.includes(e);
130
- }
131
- /**
132
- * Triggers the `update` callback (if any) to refresh the array from the
133
- * adapter. Sets `isLoading` while the request is in flight.
134
- */
135
- async update() {
136
- if (!this.opts.update)
137
- return this;
138
- this.updating = !0;
139
- try {
140
- await this.opts.update();
141
- } finally {
142
- this.updating = !1;
143
- }
144
- return this;
145
- }
146
- [Symbol.iterator]() {
147
- return this.resolved[Symbol.iterator]();
148
- }
149
- }
150
- class I extends k {
151
- constructor(e) {
152
- super(e), this.queryParams = e.query, this.metaData = e.meta ?? {}, this.linksData = e.links ?? {}, _(this, {
153
- metaData: y.ref,
154
- linksData: y.ref,
155
- meta: u,
156
- links: u,
157
- query: u
158
- });
159
- }
160
- /** Server-side metadata attached to the last response (e.g. pagination). */
161
- get meta() {
162
- return this.metaData;
163
- }
164
- /** Links attached to the last response. */
165
- get links() {
166
- return this.linksData;
167
- }
168
- /** The query parameters that produced this array. */
169
- get query() {
170
- return this.queryParams;
171
- }
172
- /** Called by the store to update `meta` after a successful query. */
173
- _setMeta(e) {
174
- this.metaData = e;
175
- }
176
- /** Called by the store to update `links` after a successful query. */
177
- _setLinks(e) {
178
- this.linksData = e;
179
- }
180
- }
181
- var T = Object.getOwnPropertyDescriptor, P = (t, e, s, i) => {
182
- for (var a = i > 1 ? void 0 : i ? T(e, s) : e, r = t.length - 1, o; r >= 0; r--)
183
- (o = t[r]) && (a = o(a) || a);
184
- return a;
185
- }, j = (t, e) => (s, i) => e(s, i, t);
186
- let f = class {
187
- constructor(t) {
188
- this.identityMap = new q(), this.adapters = /* @__PURE__ */ new Map(), this.serializers = /* @__PURE__ */ new Map(), this.newRecords = /* @__PURE__ */ new Map(), this.newRecordTypes = /* @__PURE__ */ new WeakMap(), this.relationshipCache = /* @__PURE__ */ new WeakMap(), this.pendingMembers = /* @__PURE__ */ new WeakMap(), this._cache = null, this.coalescePending = /* @__PURE__ */ new Map(), this.coalesceScheduled = /* @__PURE__ */ new Set(), this.schema = t;
189
- }
190
- static refEquals(t, e) {
191
- return t.id === e.id && t.type === e.type;
192
- }
193
- // --- registration ---
194
- /** Registers an adapter for a given model name (or `'application'` as a fallback). */
195
- registerAdapter(t, e) {
196
- this.adapters.set(t, e);
197
- }
198
- /** Registers a serializer for a given model name (or `'application'` as a fallback). */
199
- registerSerializer(t, e) {
200
- this.serializers.set(t, e);
201
- }
202
- /** Registers a persistent cache layer (e.g. IndexedDB) for offline-first reads. */
203
- registerCache(t) {
204
- this._cache = t;
205
- }
206
- /**
207
- * Returns the adapter for `modelName`, falling back to `'application'`.
208
- * @throws when no adapter is registered.
209
- */
210
- adapterFor(t) {
211
- const e = this.adapters.get(t) ?? this.adapters.get("application");
212
- if (!e)
213
- throw new Error(`No adapter registered for "${t}"`);
214
- return e;
215
- }
216
- /**
217
- * Returns the serializer for `modelName`, falling back to `'application'`.
218
- * @throws when no serializer is registered.
219
- */
220
- serializerFor(t) {
221
- const e = this.serializers.get(t) ?? this.serializers.get("application");
222
- if (!e)
223
- throw new Error(`No serializer registered for "${t}"`);
224
- return e;
225
- }
226
- // --- creating ---
227
- /**
228
- * Creates a new (unsaved) record of the given type with optional initial data.
229
- * The record is tracked in `newRecords` until it is saved or rolled back.
230
- *
231
- * @throws when `modelName` has not been registered with `SchemaService`.
232
- */
233
- createRecord(t, e = {}) {
234
- if (!this.schema.doesTypeExist(t))
235
- throw new Error(`Unknown model type: "${t}"`);
236
- const s = this.schema.modelFor(t), i = new s({ id: null, data: e, store: this });
237
- return this.trackNewRecord(t, i), i;
238
- }
239
- trackNewRecord(t, e) {
240
- let s = this.newRecords.get(t);
241
- s || (s = /* @__PURE__ */ new Set(), this.newRecords.set(t, s)), s.add(e), this.newRecordTypes.set(e, t);
242
- }
243
- untrackNewRecord(t) {
244
- var s;
245
- const e = this.newRecordTypes.get(t);
246
- e && ((s = this.newRecords.get(e)) == null || s.delete(t), this.newRecordTypes.delete(t));
247
- }
248
- // --- peeking ---
249
- /**
250
- * Synchronously returns a record from the identity map, or `null` when not
251
- * found. Does not trigger a network request.
252
- */
253
- peekRecord(t, e) {
254
- const s = e == null ? null : String(e);
255
- return s === null ? null : this.identityMap.get(t, s) ?? null;
256
- }
257
- /**
258
- * Returns a live `RecordArray` backed by the identity map for `modelName`.
259
- * New (unsaved) records are included at the end.
260
- * Does not trigger a network request.
261
- */
262
- peekAll(t) {
263
- return new k({
264
- modelName: t,
265
- source: () => {
266
- const e = this.identityMap.all(t), s = this.newRecords.get(t);
267
- return !s || s.size === 0 ? e : [...e, ...s];
268
- }
269
- });
270
- }
271
- // --- push / normalize ---
272
- /**
273
- * Pushes a normalized document into the identity map.
274
- * Side-loaded (`included`) records are pushed first.
275
- *
276
- * @returns The primary record(s), or `null` for empty payloads.
277
- */
278
- push(t) {
279
- const e = t;
280
- if (e.included)
281
- for (const s of e.included)
282
- this.pushResource(s);
283
- return e.data === null || e.data === void 0 ? null : Array.isArray(e.data) ? e.data.map((s) => this.pushResource(s)) : this.pushResource(e.data);
284
- }
285
- /**
286
- * Normalizes a raw payload via the registered serializer and pushes the
287
- * result. `modelName` is optional; when omitted the payload is pushed
288
- * directly without normalization.
289
- */
290
- pushPayload(t, e) {
291
- let s, i;
292
- typeof t == "string" ? (s = t, i = e) : (s = null, i = t);
293
- const a = s ? this.serializerFor(s).normalizeResponse(
294
- this,
295
- this.schema.modelFor(s),
296
- i,
297
- null,
298
- "pushPayload"
299
- ) : i;
300
- this.push(a);
301
- }
302
- /**
303
- * Normalizes a raw payload for `modelName` via the registered serializer
304
- * and returns the `NormalizedDocument` without pushing it.
305
- */
306
- normalize(t, e) {
307
- return this.serializerFor(t).normalizeResponse(
308
- this,
309
- this.schema.modelFor(t),
310
- e,
311
- null,
312
- "normalize"
313
- );
314
- }
315
- /**
316
- * Inserts or merges a single normalized resource into the identity map.
317
- * - Existing record → calls `_applyServerData` to merge attributes and
318
- * relationships in place (preserving the live reference).
319
- * - New record → instantiates via `Model.push` and sets it in the map.
320
- *
321
- * @throws when `type` has not been registered or `id` is `null`.
322
- */
323
- pushResource(t) {
324
- const { type: e, id: s } = t;
325
- if (!this.schema.doesTypeExist(e))
326
- throw new Error(`Unknown model type: "${e}"`);
327
- if (s === null)
328
- throw new Error(`Cannot push a resource of type "${e}" without an id`);
329
- const i = this.identityMap.get(e, s);
330
- if (i)
331
- return p(() => {
332
- i._applyServerData(null, t.attributes ?? {}, t.relationships);
333
- }), this.trackInverseForResource(i, t), i;
334
- const a = this.schema.modelFor(e), r = S.push.call(a, {
335
- id: s,
336
- data: t.attributes ?? {},
337
- relationships: t.relationships,
338
- store: this
339
- });
340
- return this.identityMap.set(e, s, r), this.trackInverseForResource(r, t), r;
341
- }
342
- /**
343
- * After pushing a resource, updates the inverse side of every declared
344
- * inverse relationship so both sides stay consistent.
345
- */
346
- trackInverseForResource(t, e) {
347
- if (e.relationships)
348
- for (const [s, i] of Object.entries(e.relationships)) {
349
- const a = this.schema.relationshipsDefinitionFor(t.modelName).get(s);
350
- if (!a || !a.options.inverse || !i.data)
351
- continue;
352
- const r = Array.isArray(i.data) ? i.data : [i.data];
353
- for (const o of r)
354
- this.addInverse(o.type, o.id, a.options.inverse, t);
355
- }
356
- }
357
- /**
358
- * Adds `inverseRecord` to the inverse relationship on `targetType:targetId`.
359
- * No-ops when the target record is not in the identity map.
360
- */
361
- addInverse(t, e, s, i) {
362
- const a = this.identityMap.get(t, e);
363
- if (!a)
364
- return;
365
- const o = this.schema.relationshipsDefinitionFor(t).get(s);
366
- if (!o)
367
- return;
368
- const n = a._getRelationshipRef(s), h = { type: i.modelName, id: i.id };
369
- p(() => {
370
- if (o.kind === "hasMany") {
371
- const c = n != null && n.data && Array.isArray(n.data) ? n.data : [];
372
- c.some((d) => f.refEquals(d, h)) || a._setRelationshipRef(s, { data: [...c, h] });
373
- } else
374
- a._setRelationshipRef(s, { data: h });
375
- });
376
- }
377
- /**
378
- * Removes `inverseRecord` from the inverse relationship on `targetType:targetId`.
379
- * No-ops when the target record is not in the identity map.
380
- */
381
- removeInverse(t, e, s, i) {
382
- const a = this.identityMap.get(t, e);
383
- if (!a)
384
- return;
385
- const o = this.schema.relationshipsDefinitionFor(t).get(s);
386
- if (!o)
387
- return;
388
- const n = a._getRelationshipRef(s);
389
- p(() => {
390
- if (o.kind === "hasMany") {
391
- const c = (n != null && n.data && Array.isArray(n.data) ? n.data : []).filter((d) => !(d.id === i.id && d.type === i.modelName));
392
- a._setRelationshipRef(s, { data: c });
393
- } else
394
- a._setRelationshipRef(s, { data: null });
395
- });
396
- }
397
- // --- unload ---
398
- /**
399
- * Removes a record from the identity map and clears its relationship cache.
400
- * Called by `record.unloadRecord()` and internally after `deleteRecord`.
401
- */
402
- unloadRecord(t) {
403
- t.id !== null && this.identityMap.delete(t.modelName, t.id), this.untrackNewRecord(t), this.relationshipCache.delete(t);
404
- }
405
- /**
406
- * Unloads all records for `modelName`, or all records across all types when
407
- * `modelName` is omitted.
408
- */
409
- unloadAll(t) {
410
- var e;
411
- if (t) {
412
- for (const s of this.identityMap.all(t))
413
- this.relationshipCache.delete(s);
414
- this.identityMap.clear(t), (e = this.newRecords.get(t)) == null || e.clear();
415
- } else
416
- this.identityMap.clear(), this.newRecords.clear();
417
- }
418
- // --- find ---
419
- /**
420
- * Finds a single record by id. Returns the cached record immediately when
421
- * `options.reload` is not set; otherwise re-fetches.
422
- *
423
- * When the adapter has `coalesceFindRequests: true` and `findMany` is
424
- * implemented, multiple concurrent `findRecord` calls for the same type
425
- * are batched into a single `findMany` network request.
426
- */
427
- async findRecord(t, e, s = {}) {
428
- const i = this.peekRecord(t, e);
429
- if (i && !s.reload && !s.include)
430
- return i;
431
- if (!s.reload && !s.include && this._cache) {
432
- const l = await this._cache.get(t, e);
433
- if (l)
434
- return this.push({
435
- data: {
436
- type: l.modelName,
437
- id: l.id,
438
- attributes: l.attributes,
439
- relationships: l.relationships
440
- }
441
- });
442
- }
443
- const a = this.adapterFor(t);
444
- if (a.coalesceFindRequests && a.findMany && !s.include)
445
- return this.scheduleCoalescedFind(t, e);
446
- const r = i ? this.createSnapshot(i) : this.createEmptySnapshot(t, e), o = s.include ? { include: s.include, adapterOptions: s.adapterOptions } : s.adapterOptions ? { adapterOptions: s.adapterOptions } : void 0, n = await a.findRecord(this, t, e, r, o), h = m(n), c = this.serializerFor(t).normalizeResponse(
447
- this,
448
- this.schema.modelFor(t),
449
- n,
450
- e,
451
- "findRecord"
452
- ), d = this.push(c);
453
- if (this._cache) {
454
- const l = h ? v(h) : null;
455
- l !== 0 && this.cacheNormalizedDocument(c, l ?? void 0);
456
- }
457
- return d;
458
- }
459
- /**
460
- * Fetches all records of `modelName` from the server and returns a
461
- * `RecordArray` backed by the identity map.
462
- */
463
- async findAll(t, e = {}) {
464
- const s = this.adapterFor(t), i = e.include ? { include: e.include, adapterOptions: e.adapterOptions } : e.adapterOptions ? { adapterOptions: e.adapterOptions } : void 0, a = await s.findAll(this, t, null, [], i), r = m(a), o = this.serializerFor(t).normalizeResponse(
465
- this,
466
- this.schema.modelFor(t),
467
- a,
468
- null,
469
- "findAll"
470
- );
471
- if (this.push(o), this._cache) {
472
- const n = r ? v(r) : null;
473
- n !== 0 && this.cacheNormalizedDocument(o, n ?? void 0);
474
- }
475
- return this.peekAll(t);
476
- }
477
- /**
478
- * Executes an adapter query and returns an `AdapterPopulatedRecordArray`
479
- * whose `update()` method re-issues the same query.
480
- */
481
- async query(t, e) {
482
- const s = [], i = new I({
483
- modelName: t,
484
- query: e,
485
- source: () => s.map((a) => this.peekRecord(t, a)).filter((a) => a !== null),
486
- update: async () => {
487
- await this.runQuery(t, e, i, s);
488
- }
489
- });
490
- return await this.runQuery(t, e, i, s), i;
491
- }
492
- async runQuery(t, e, s, i) {
493
- const r = await this.adapterFor(t).query(this, t, e, s), o = this.serializerFor(t).normalizeResponse(
494
- this,
495
- this.schema.modelFor(t),
496
- r,
497
- null,
498
- "query"
499
- );
500
- if (this.push(o), i.length = 0, Array.isArray(o.data))
501
- for (const n of o.data)
502
- n.id && i.push(n.id);
503
- o.meta && s._setMeta(o.meta), o.links && s._setLinks(o.links);
504
- }
505
- /**
506
- * Executes an adapter query that returns at most one record.
507
- * Returns `null` when the adapter returns an empty payload.
508
- */
509
- async queryRecord(t, e) {
510
- const i = await this.adapterFor(t).queryRecord(this, t, e), a = this.serializerFor(t).normalizeResponse(
511
- this,
512
- this.schema.modelFor(t),
513
- i,
514
- null,
515
- "queryRecord"
516
- ), r = this.push(a);
517
- return Array.isArray(r) ? r[0] ?? null : r ?? null;
518
- }
519
- // --- save / delete / reload from Model ---
520
- /**
521
- * Persists a record to the server.
522
- * - New records → `adapter.createRecord` (POST)
523
- * - Existing dirty records → `adapter.updateRecord` (PUT) by default
524
- * - With `{ patch: true }` → `adapter.patchRecord` (PATCH, partial payload)
525
- *
526
- * After the response is received the server data is applied back to the
527
- * record via `_applyServerData` so it transitions to `saved`.
528
- */
529
- async saveRecord(t, e = {}) {
530
- const s = this.adapterFor(t.modelName), i = this.createSnapshot(t), { isNew: a } = t;
531
- let r;
532
- a ? r = await s.createRecord(this, t.modelName, i) : e.patch && s.patchRecord ? r = await s.patchRecord(this, t.modelName, i) : r = await s.updateRecord(this, t.modelName, i);
533
- const o = this.serializerFor(t.modelName).normalizeResponse(
534
- this,
535
- this.schema.modelFor(t.modelName),
536
- r,
537
- t.id,
538
- a ? "createRecord" : "updateRecord"
539
- ), n = o.data;
540
- if (n) {
541
- const h = n.id ?? t.id;
542
- p(() => {
543
- t._applyServerData(h, n.attributes ?? {}, n.relationships);
544
- }), a && h && (this.untrackNewRecord(t), this.identityMap.set(t.modelName, h, t));
545
- }
546
- if (o.included)
547
- for (const h of o.included)
548
- this.pushResource(h);
549
- if (this._cache && t.id) {
550
- const h = t, c = {};
551
- for (const [d, l] of h._relationships)
552
- c[d] = l;
553
- this._cache.set(t.modelName, t.id, { ...h._data }, {
554
- relationships: Object.keys(c).length > 0 ? c : void 0
555
- });
556
- }
557
- return t;
558
- }
559
- /**
560
- * Issues a DELETE request and unloads the record from the identity map.
561
- */
562
- async deleteRecord(t) {
563
- const e = this.adapterFor(t.modelName), s = this.createSnapshot(t);
564
- return await e.deleteRecord(this, t.modelName, s), this._cache && t.id && this._cache.invalidate(t.modelName, t.id), this.unloadRecord(t), t;
565
- }
566
- /**
567
- * Re-fetches a record from the server and merges the response into the
568
- * existing instance.
569
- */
570
- async reloadRecord(t) {
571
- if (!t.id)
572
- throw new Error("Cannot reload a record without an id");
573
- const e = this.adapterFor(t.modelName), s = this.createSnapshot(t), i = await e.findRecord(this, t.modelName, t.id, s), a = this.serializerFor(t.modelName).normalizeResponse(
574
- this,
575
- this.schema.modelFor(t.modelName),
576
- i,
577
- t.id,
578
- "findRecord"
579
- );
580
- return this.push(a), t;
581
- }
582
- // --- snapshot ---
583
- /**
584
- * Creates a `Snapshot` for a live record.
585
- * The snapshot reads directly from the record's internal state so it
586
- * reflects the current (possibly dirty) values.
587
- */
588
- createSnapshot(t) {
589
- const { modelName: e } = t, s = this.schema.attributesDefinitionFor(e), i = this.schema.relationshipsDefinitionFor(e), a = t;
590
- return {
591
- id: t.id,
592
- modelName: e,
593
- record: t,
594
- attr: (r) => a._data[r],
595
- belongsTo: (r, o) => {
596
- const n = a._getRelationshipRef(r);
597
- return !(n != null && n.data) || Array.isArray(n.data) ? null : o != null && o.id ? n.data.id : this.peekRecord(n.data.type, n.data.id);
598
- },
599
- hasMany: (r, o) => {
600
- const n = a._getRelationshipRef(r), h = n != null && n.data && Array.isArray(n.data) ? n.data : [];
601
- return o != null && o.ids ? h.map((c) => c.id) : h.map((c) => this.peekRecord(c.type, c.id)).filter((c) => c !== null);
602
- },
603
- changedAttributes: () => a.changedAttributes(),
604
- eachAttribute: (r) => {
605
- for (const [o, n] of s)
606
- r(o, n);
607
- },
608
- eachRelationship: (r) => {
609
- for (const [o, n] of i)
610
- r(o, n);
611
- }
612
- };
613
- }
614
- /**
615
- * Creates a placeholder `Snapshot` for a record that is not yet in the
616
- * identity map (used when fetching a record that isn't cached).
617
- */
618
- createEmptySnapshot(t, e) {
619
- const s = this.schema.attributesDefinitionFor(t), i = this.schema.relationshipsDefinitionFor(t);
620
- return {
621
- id: e,
622
- modelName: t,
623
- record: null,
624
- attr: () => {
625
- },
626
- belongsTo: () => null,
627
- hasMany: () => [],
628
- changedAttributes: () => ({}),
629
- eachAttribute: (a) => {
630
- for (const [r, o] of s)
631
- a(r, o);
632
- },
633
- eachRelationship: (a) => {
634
- for (const [r, o] of i)
635
- a(r, o);
636
- }
637
- };
638
- }
639
- // --- relationship resolution (called by Model) ---
640
- getRelationshipCache(t, e) {
641
- var s;
642
- return (s = this.relationshipCache.get(t)) == null ? void 0 : s.get(e);
643
- }
644
- setRelationshipCache(t, e, s) {
645
- let i = this.relationshipCache.get(t);
646
- i || (i = /* @__PURE__ */ new Map(), this.relationshipCache.set(t, i)), i.set(e, s);
647
- }
648
- /**
649
- * Called by the `Model` relationship getter to resolve a relationship.
650
- *
651
- * - **Async** `belongsTo` → returns an `AsyncBelongsTo` wrapper.
652
- * - **Async** `hasMany` → returns an `AsyncHasMany` wrapper.
653
- * - **Sync** `belongsTo` → peeks the related record from the identity map.
654
- * - **Sync** `hasMany` → returns a `ManyArray` backed by the store.
655
- *
656
- * Results are cached per record + name so the same proxy is returned on
657
- * repeated accesses (important for MobX observability).
658
- */
659
- resolveRelationship(t, e, s) {
660
- const i = s.options.async === !0, a = this.getRelationshipCache(t, e);
661
- if (a)
662
- return a;
663
- const r = {
664
- parent: t,
665
- name: e,
666
- meta: s,
667
- store: this
668
- };
669
- if (i) {
670
- if (s.kind === "belongsTo") {
671
- const h = new C(r);
672
- return this.setRelationshipCache(t, e, h), h;
673
- }
674
- const n = new E(r);
675
- return this.setRelationshipCache(t, e, n), n;
676
- }
677
- if (s.kind === "belongsTo") {
678
- const n = t._getRelationshipRef(e);
679
- return !(n != null && n.data) || Array.isArray(n.data) ? null : this.peekRecord(n.data.type, n.data.id);
680
- }
681
- const o = new O(r);
682
- return this.setRelationshipCache(t, e, o), o;
683
- }
684
- /**
685
- * Called by the `Model` `belongsTo` setter to update a relationship ref
686
- * and keep its inverse in sync.
687
- */
688
- setRelationshipValue(t, e, s, i) {
689
- if (s.kind !== "belongsTo")
690
- return;
691
- const a = t._getRelationshipRef(e), r = a != null && a.data && !Array.isArray(a.data) ? a.data : null;
692
- if (i == null) {
693
- p(() => {
694
- t._setRelationshipRef(e, { data: null });
695
- }), r && s.options.inverse && this.removeInverse(r.type, r.id, s.options.inverse, t);
696
- return;
697
- }
698
- const o = i, n = { type: o.modelName, id: o.id };
699
- p(() => {
700
- t._setRelationshipRef(e, { data: n });
701
- }), s.options.inverse && (r && !f.refEquals(r, n) && this.removeInverse(r.type, r.id, s.options.inverse, t), this.addInverse(n.type, n.id, s.options.inverse, t));
702
- }
703
- // --- hooks used by ManyArray ---
704
- /** Returns the raw relationship ref stored on `record` for `name`. */
705
- _getRelationshipRefFor(t, e) {
706
- return t._getRelationshipRef(e);
707
- }
708
- /** Returns any pending (unsaved) members for a `hasMany` relationship. */
709
- _getPendingMembers(t, e) {
710
- var s;
711
- return ((s = this.pendingMembers.get(t)) == null ? void 0 : s.get(e)) ?? [];
712
- }
713
- addPendingMember(t, e, s) {
714
- let i = this.pendingMembers.get(t);
715
- i || (i = /* @__PURE__ */ new Map(), this.pendingMembers.set(t, i));
716
- let a = i.get(e);
717
- a || (a = y.set(), i.set(e, a)), a.add(s);
718
- }
719
- removePendingMember(t, e, s) {
720
- var i, a;
721
- (a = (i = this.pendingMembers.get(t)) == null ? void 0 : i.get(e)) == null || a.delete(s);
722
- }
723
- /**
724
- * Appends `value` to the `hasMany` relationship ref on `record` and syncs
725
- * the inverse. Unsaved records (`value.id === null`) are tracked as
726
- * "pending members" until they are persisted.
727
- */
728
- _hasManyAppend(t, e, s, i) {
729
- if (i.id === null) {
730
- if (this.addPendingMember(t, e, i), s.options.inverse) {
731
- const n = this.schema.relationshipsDefinitionFor(i.modelName).get(s.options.inverse);
732
- (n == null ? void 0 : n.kind) === "belongsTo" && p(() => {
733
- i._setRelationshipRef(s.options.inverse, {
734
- data: { type: t.modelName, id: t.id }
735
- });
736
- });
737
- }
738
- return;
739
- }
740
- const a = this._getRelationshipRefFor(t, e), r = a != null && a.data && Array.isArray(a.data) ? a.data : [], o = { type: i.modelName, id: i.id };
741
- r.some((n) => f.refEquals(n, o)) || p(() => {
742
- t._setRelationshipRef(e, { data: [...r, o] });
743
- }), s.options.inverse && this.addInverse(i.modelName, i.id, s.options.inverse, t);
744
- }
745
- /**
746
- * Removes `value` from the `hasMany` relationship ref on `record` and syncs
747
- * the inverse. Pending members are removed from the pending set.
748
- */
749
- _hasManyRemove(t, e, s, i) {
750
- if (i.id === null) {
751
- this.removePendingMember(t, e, i);
752
- return;
753
- }
754
- const a = this._getRelationshipRefFor(t, e), o = (a != null && a.data && Array.isArray(a.data) ? a.data : []).filter(
755
- (n) => !(n.id === i.id && n.type === i.modelName)
756
- );
757
- p(() => {
758
- t._setRelationshipRef(e, { data: o });
759
- }), s.options.inverse && this.removeInverse(i.modelName, i.id, s.options.inverse, t);
760
- }
761
- // --- persistent cache helpers ---
762
- cacheNormalizedDocument(t, e) {
763
- if (!this._cache)
764
- return;
765
- const s = [];
766
- t.data && (Array.isArray(t.data) ? s.push(...t.data) : s.push(t.data)), t.included && s.push(...t.included);
767
- for (const i of s)
768
- i.id && this._cache.set(i.type, i.id, i.attributes ?? {}, {
769
- relationships: i.relationships,
770
- ttl: e
771
- });
772
- }
773
- scheduleCoalescedFind(t, e) {
774
- return new Promise((s, i) => {
775
- let a = this.coalescePending.get(t);
776
- a || (a = /* @__PURE__ */ new Map(), this.coalescePending.set(t, a));
777
- let r = a.get(e);
778
- r || (r = [], a.set(e, r)), r.push({ resolve: s, reject: i }), this.coalesceScheduled.has(t) || (this.coalesceScheduled.add(t), queueMicrotask(() => this.flushCoalescedFind(t)));
779
- });
780
- }
781
- async flushCoalescedFind(t) {
782
- this.coalesceScheduled.delete(t);
783
- const e = this.coalescePending.get(t);
784
- if (!e || e.size === 0)
785
- return;
786
- const s = new Map(e);
787
- e.clear();
788
- const i = Array.from(s.keys()), a = this.adapterFor(t);
789
- try {
790
- const r = i.map((h) => {
791
- const c = this.peekRecord(t, h);
792
- return c ? this.createSnapshot(c) : this.createEmptySnapshot(t, h);
793
- }), o = await a.findMany(this, t, i, r), n = this.serializerFor(t).normalizeResponse(
794
- this,
795
- this.schema.modelFor(t),
796
- o,
797
- null,
798
- "findMany"
799
- );
800
- this.push(n);
801
- for (const h of i) {
802
- const c = this.peekRecord(t, h), d = s.get(h);
803
- if (d)
804
- for (const l of d)
805
- c ? l.resolve(c) : l.reject(new Error(`Record not found after findMany: ${t}:${h}`));
806
- }
807
- } catch (r) {
808
- for (const o of s.values())
809
- for (const n of o)
810
- n.reject(r);
811
- }
812
- }
813
- // --- liveQuery ---
814
- /**
815
- * Returns a reactive `RecordArray` that auto-updates whenever records matching
816
- * the predicate are added, removed, or mutated in the identity map.
817
- *
818
- * The underlying computed uses `keepAlive: true` so it remains cached even
819
- * without active MobX observers — useful for long-lived filtered views.
820
- *
821
- * @param modelName - The registered model type to query.
822
- * @param predicate - Filter function applied to each record of `modelName`.
823
- * @returns A live `RecordArray` containing only records that satisfy `predicate`.
824
- */
825
- liveQuery(t, e) {
826
- return new k({
827
- modelName: t,
828
- keepAlive: !0,
829
- source: () => {
830
- const s = this.identityMap.all(t), i = this.newRecords.get(t);
831
- return (i && i.size > 0 ? [...s, ...i] : s).filter(e);
832
- }
833
- });
834
- }
835
- // --- optimisticUpdate ---
836
- /**
837
- * Applies attribute changes to a record immediately (optimistically), then
838
- * executes `persistFn`. If `persistFn` throws, the record is automatically
839
- * rolled back to its state before the optimistic update.
840
- *
841
- * @param record - The record to update optimistically.
842
- * @param optimisticAttributes - Attributes to apply before persistence.
843
- * @param persistFn - Async function that persists the change (e.g. `record.save()`).
844
- * @returns The record on success.
845
- * @throws Re-throws the error from `persistFn` after rollback.
846
- */
847
- async optimisticUpdate(t, e, s) {
848
- const i = t, a = { ...i._data };
849
- p(() => {
850
- Object.assign(i._data, e);
851
- });
852
- try {
853
- return await s(), t;
854
- } catch (r) {
855
- throw p(() => {
856
- for (const [o, n] of Object.entries(a))
857
- i._data[o] = n;
858
- }), r;
859
- }
860
- }
861
- // --- runInTransaction ---
862
- /**
863
- * Executes multiple store mutations as a single MobX action, guaranteeing
864
- * that observers (and therefore UI renders) react only once — after all
865
- * mutations have been applied.
866
- *
867
- * @param callback - Synchronous function containing one or more store mutations.
868
- */
869
- runInTransaction(t) {
870
- p(t);
871
- }
872
- // --- SSR: serialize / hydrate ---
873
- /**
874
- * Produces a JSON-serializable snapshot of all records in the identity map.
875
- * Designed for server-side rendering: serialize on the server, transfer as
876
- * JSON, then `hydrate()` on the client to restore the full store state
877
- * without network requests.
878
- *
879
- * @param options.exclude - Per-model-type list of attribute keys to omit
880
- * (e.g. `{ user: ['password', 'token'] }`) to prevent leaking sensitive
881
- * data in SSR payloads.
882
- * @returns A snapshot object safe to pass through `JSON.stringify`.
883
- */
884
- serialize(t = {}) {
885
- var i;
886
- const e = {}, s = this.identityMap._buckets;
887
- for (const [a, r] of s) {
888
- const o = (i = t.exclude) == null ? void 0 : i[a], n = [];
889
- for (const [h, c] of r) {
890
- const d = c;
891
- let l;
892
- if (o && o.length > 0) {
893
- l = {};
894
- for (const [R, w] of Object.entries(d._data))
895
- o.includes(R) || (l[R] = w);
896
- } else
897
- l = { ...d._data };
898
- const g = {
899
- id: h,
900
- attributes: l
901
- };
902
- if (d._relationships && d._relationships.size > 0) {
903
- const R = {};
904
- for (const [w, A] of d._relationships)
905
- R[w] = A;
906
- g.relationships = R;
907
- }
908
- n.push(g);
909
- }
910
- n.length > 0 && (e[a] = n);
911
- }
912
- return { records: e };
913
- }
914
- /**
915
- * Restores records from a snapshot produced by `serialize()` into this store
916
- * instance. All records are pushed into the identity map in `loaded.saved`
917
- * state — no network requests are issued.
918
- *
919
- * @param snapshot - A snapshot object previously returned by `serialize()`.
920
- */
921
- hydrate(t) {
922
- p(() => {
923
- for (const [e, s] of Object.entries(t.records))
924
- for (const i of s)
925
- this.pushResource({
926
- type: e,
927
- id: i.id,
928
- attributes: i.attributes,
929
- relationships: i.relationships
930
- });
931
- });
932
- }
933
- /**
934
- * Factory method that creates a new `Store` and immediately hydrates it from
935
- * the given snapshot. Convenience for SSR client-side bootstrap.
936
- *
937
- * @param schema - SchemaService with all model types registered.
938
- * @param snapshot - A snapshot object previously returned by `serialize()`.
939
- * @returns A fully populated `Store` instance ready for use.
940
- */
941
- static hydrate(t, e) {
942
- const s = new f(t);
943
- return s.hydrate(e), s;
944
- }
945
- };
946
- f = P([
947
- M(),
948
- F(),
949
- j(0, z(D))
950
- ], f);
951
- export {
952
- I as A,
953
- q as I,
954
- k as R,
955
- f as S
956
- };
957
- //# sourceMappingURL=Store-Bm5JivTc.js.map