@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
@@ -0,0 +1,1229 @@
1
+ import "reflect-metadata";
2
+ import { S as z } from "./SchemaService-C_pkh-vI.js";
3
+ import { singleton as T, injectable as C, inject as I } from "tsyringe";
4
+ import { makeObservable as M, action as v, observable as g, computed as f, runInAction as u } from "mobx";
5
+ import { b as q, A as $, a as P, M as x } from "./relationships-DvSi8fVN.js";
6
+ import { e as F, p as _, R as N } from "./RestAdapter-DYUoyV5h.js";
7
+ import { M as R } from "./MdqlMemoryExecutor-BWMP31zG.js";
8
+ import { J as j } from "./JsonSerializer-CFqo6GjC.js";
9
+ class L {
10
+ constructor() {
11
+ this._buckets = /* @__PURE__ */ new Map(), M(this, {
12
+ _buckets: g.shallow,
13
+ set: v,
14
+ delete: v,
15
+ clear: v
16
+ });
17
+ }
18
+ /**
19
+ * Returns the bucket for `modelName`, optionally creating it when absent.
20
+ * Internal helper — not part of the public API.
21
+ */
22
+ bucket(t, s = !1) {
23
+ let i = this._buckets.get(t);
24
+ return !i && s && (i = g.map({}, { deep: !1 }), this._buckets.set(t, i)), i;
25
+ }
26
+ /** Adds or replaces the record with the given `id` under `modelName`. */
27
+ set(t, s, i) {
28
+ this.bucket(t, !0).set(s, i);
29
+ }
30
+ /**
31
+ * Returns the record for `modelName` + `id`, or `null` when not found.
32
+ */
33
+ get(t, s) {
34
+ var i;
35
+ return ((i = this.bucket(t)) == null ? void 0 : i.get(s)) ?? null;
36
+ }
37
+ /** Returns `true` when a record exists for `modelName` + `id`. */
38
+ has(t, s) {
39
+ var i;
40
+ return ((i = this.bucket(t)) == null ? void 0 : i.has(s)) ?? !1;
41
+ }
42
+ /**
43
+ * Removes the record for `modelName` + `id`.
44
+ * @returns `true` when the record existed and was deleted.
45
+ */
46
+ delete(t, s) {
47
+ var i;
48
+ return ((i = this.bucket(t)) == null ? void 0 : i.delete(s)) ?? !1;
49
+ }
50
+ /** Returns all records stored under `modelName` as an array. */
51
+ all(t) {
52
+ const s = this.bucket(t);
53
+ return s ? Array.from(s.values()) : [];
54
+ }
55
+ /**
56
+ * Clears all records for `modelName`, or all records across all types when
57
+ * `modelName` is omitted.
58
+ */
59
+ clear(t) {
60
+ var s;
61
+ if (t)
62
+ (s = this.bucket(t)) == null || s.clear();
63
+ else
64
+ for (const i of this._buckets.values())
65
+ i.clear();
66
+ }
67
+ /**
68
+ * Returns the number of records stored for `modelName`, or the total across
69
+ * all types when `modelName` is omitted.
70
+ */
71
+ size(t) {
72
+ var i;
73
+ if (t)
74
+ return ((i = this.bucket(t)) == null ? void 0 : i.size) ?? 0;
75
+ let s = 0;
76
+ for (const r of this._buckets.values())
77
+ s += r.size;
78
+ return s;
79
+ }
80
+ }
81
+ class A {
82
+ constructor(t) {
83
+ this.updating = !1, this.opts = t, M(this, {
84
+ resolved: t.keepAlive ? f({ keepAlive: !0 }) : f,
85
+ updating: g,
86
+ length: f,
87
+ modelName: f
88
+ });
89
+ }
90
+ /** Current record list, derived from the injected `source` function. */
91
+ get resolved() {
92
+ return this.opts.source();
93
+ }
94
+ /** `true` while a background `update()` call is in progress. */
95
+ get isLoading() {
96
+ return this.updating;
97
+ }
98
+ /** Alias for `isLoading`. */
99
+ get isUpdating() {
100
+ return this.updating;
101
+ }
102
+ /** Number of records in the array. */
103
+ get length() {
104
+ return this.resolved.length;
105
+ }
106
+ /** The registered model name for the records in this array. */
107
+ get modelName() {
108
+ return this.opts.modelName;
109
+ }
110
+ /** Returns the record at `index`, or `undefined`. */
111
+ at(t) {
112
+ return this.resolved[t];
113
+ }
114
+ /** Returns a plain array snapshot of all records. */
115
+ toArray() {
116
+ return [...this.resolved];
117
+ }
118
+ /** Maps over records. */
119
+ map(t) {
120
+ return this.resolved.map(t);
121
+ }
122
+ /** Filters records. */
123
+ filter(t) {
124
+ return this.resolved.filter(t);
125
+ }
126
+ /** Iterates records. */
127
+ forEach(t) {
128
+ this.resolved.forEach(t);
129
+ }
130
+ /** Returns `true` when `record` is in the array. */
131
+ includes(t) {
132
+ return this.resolved.includes(t);
133
+ }
134
+ /**
135
+ * Triggers the `update` callback (if any) to refresh the array from the
136
+ * adapter. Sets `isLoading` while the request is in flight.
137
+ */
138
+ async update() {
139
+ if (!this.opts.update)
140
+ return this;
141
+ this.updating = !0;
142
+ try {
143
+ await this.opts.update();
144
+ } finally {
145
+ this.updating = !1;
146
+ }
147
+ return this;
148
+ }
149
+ [Symbol.iterator]() {
150
+ return this.resolved[Symbol.iterator]();
151
+ }
152
+ }
153
+ class Q extends A {
154
+ constructor(t) {
155
+ super(t), this.queryParams = t.query, this.metaData = t.meta ?? {}, this.linksData = t.links ?? {}, M(this, {
156
+ metaData: g.ref,
157
+ linksData: g.ref,
158
+ meta: f,
159
+ links: f,
160
+ query: f
161
+ });
162
+ }
163
+ /** Server-side metadata attached to the last response (e.g. pagination). */
164
+ get meta() {
165
+ return this.metaData;
166
+ }
167
+ /** Links attached to the last response. */
168
+ get links() {
169
+ return this.linksData;
170
+ }
171
+ /** The query parameters that produced this array. */
172
+ get query() {
173
+ return this.queryParams;
174
+ }
175
+ /** Called by the store to update `meta` after a successful query. */
176
+ _setMeta(t) {
177
+ this.metaData = t;
178
+ }
179
+ /** Called by the store to update `links` after a successful query. */
180
+ _setLinks(t) {
181
+ this.linksData = t;
182
+ }
183
+ }
184
+ const S = [
185
+ "equals",
186
+ "notEquals",
187
+ "in",
188
+ "notIn",
189
+ "isNull",
190
+ "isNotNull"
191
+ ], U = [
192
+ ...S,
193
+ "contains",
194
+ "startsWith",
195
+ "endsWith"
196
+ ], O = [
197
+ ...S,
198
+ "greaterThan",
199
+ "greaterThanOrEquals",
200
+ "lessThan",
201
+ "lessThanOrEquals",
202
+ "between"
203
+ ], G = {
204
+ string: new Set(U),
205
+ number: new Set(O),
206
+ date: new Set(O),
207
+ boolean: /* @__PURE__ */ new Set(["equals", "notEquals", "isNull", "isNotNull"])
208
+ }, E = /* @__PURE__ */ new Set([
209
+ "equals",
210
+ "notEquals",
211
+ "in",
212
+ "notIn",
213
+ "isNull",
214
+ "isNotNull",
215
+ "contains",
216
+ "startsWith",
217
+ "endsWith",
218
+ "greaterThan",
219
+ "greaterThanOrEquals",
220
+ "lessThan",
221
+ "lessThanOrEquals",
222
+ "between"
223
+ ]);
224
+ class B extends Error {
225
+ constructor(t) {
226
+ const s = t.map((i) => `${i.path}: ${i.message}`);
227
+ super(`MDQL validation failed: ${s.join("; ")}`), this.name = "MdqlValidationException", this.errors = t;
228
+ }
229
+ }
230
+ class p {
231
+ static validate(t, s) {
232
+ const i = p.validateQuiet(t, s);
233
+ if (i.length > 0)
234
+ throw new B(i);
235
+ }
236
+ static validateQuiet(t, s) {
237
+ const i = [];
238
+ if (!s.doesTypeExist(t.modelName))
239
+ return i.push({
240
+ path: "modelName",
241
+ message: `Unknown model type "${t.modelName}".`
242
+ }), i;
243
+ const r = s.attributesDefinitionFor(t.modelName), n = s.relationshipsDefinitionFor(t.modelName);
244
+ p.validateFilterNode(
245
+ t.filters,
246
+ "filters",
247
+ i,
248
+ s,
249
+ t.modelName
250
+ );
251
+ for (let o = 0; o < t.orderBy.length; o++) {
252
+ const a = t.orderBy[o];
253
+ a.field.includes(".") ? p.resolveFieldAttribute(a.field, t.modelName, s) || i.push({
254
+ path: `orderBy[${o}]`,
255
+ message: `Unknown attribute path "${a.field}".`
256
+ }) : a.field !== "id" && !r.has(a.field) && i.push({
257
+ path: `orderBy[${o}]`,
258
+ message: `Unknown attribute "${a.field}" on "${t.modelName}".`
259
+ });
260
+ }
261
+ for (const o of t.includes)
262
+ n.has(o) || i.push({
263
+ path: "includes",
264
+ message: `Unknown relationship "${o}" on "${t.modelName}".`
265
+ });
266
+ return t.limit !== null && (!Number.isInteger(t.limit) || t.limit < 1) && i.push({
267
+ path: "limit",
268
+ message: "Limit must be a positive integer."
269
+ }), t.offset !== null && (!Number.isInteger(t.offset) || t.offset < 0) && i.push({
270
+ path: "offset",
271
+ message: "Offset must be a non-negative integer."
272
+ }), i;
273
+ }
274
+ static resolveFieldAttribute(t, s, i) {
275
+ const r = t.split(".");
276
+ if (r.length === 1)
277
+ return t === "id" ? { name: "id", type: "string" } : i.attributesDefinitionFor(s).get(t) ?? null;
278
+ let n = s;
279
+ for (let l = 0; l < r.length - 1; l++) {
280
+ const c = i.relationshipsDefinitionFor(n).get(r[l]);
281
+ if (!c || (n = c.type, !i.doesTypeExist(n))) return null;
282
+ }
283
+ const o = r[r.length - 1];
284
+ return o === "id" ? { name: "id", type: "string" } : i.attributesDefinitionFor(n).get(o) ?? null;
285
+ }
286
+ static validateFilterNode(t, s, i, r, n) {
287
+ if (t.kind === "condition") {
288
+ const o = p.resolveFieldAttribute(
289
+ t.field,
290
+ n,
291
+ r
292
+ );
293
+ if (!o) {
294
+ const l = t.field.includes(".") ? `Unknown attribute path "${t.field}".` : `Unknown attribute "${t.field}".`;
295
+ i.push({ path: s, message: l });
296
+ return;
297
+ }
298
+ (o.type ? G[o.type] ?? E : E).has(t.operator) || i.push({
299
+ path: s,
300
+ message: `Operator "${t.operator}" is not valid for type "${o.type}".`
301
+ }), t.operator === "between" && (!Array.isArray(t.value) || t.value.length !== 2) && i.push({
302
+ path: s,
303
+ message: 'Operator "between" requires a value of [min, max].'
304
+ }), (t.operator === "in" || t.operator === "notIn") && (Array.isArray(t.value) || i.push({
305
+ path: s,
306
+ message: `Operator "${t.operator}" requires an array value.`
307
+ }));
308
+ return;
309
+ }
310
+ for (let o = 0; o < t.children.length; o++)
311
+ p.validateFilterNode(
312
+ t.children[o],
313
+ `${s}.${t.kind}[${o}]`,
314
+ i,
315
+ r,
316
+ n
317
+ );
318
+ }
319
+ }
320
+ class w {
321
+ constructor(t, s) {
322
+ this.store = t, this.queryModelName = s, this.rootGroup = { kind: "and", children: [] }, this.orderByClauses = [], this.limitValue = null, this.offsetValue = null, this.includesList = [];
323
+ }
324
+ where(t, s, i) {
325
+ const r = {
326
+ kind: "condition",
327
+ field: t,
328
+ operator: s,
329
+ value: i
330
+ };
331
+ return this.rootGroup.children.push(r), this;
332
+ }
333
+ whereEquals(t, s) {
334
+ return this.where(t, "equals", s);
335
+ }
336
+ whereContains(t, s) {
337
+ return this.where(t, "contains", s);
338
+ }
339
+ and(t) {
340
+ const s = new w(this.store, this.queryModelName);
341
+ t(s);
342
+ const i = { kind: "and", children: [...s.rootGroup.children] };
343
+ return this.rootGroup.children.push(i), this;
344
+ }
345
+ or(t) {
346
+ const s = new w(this.store, this.queryModelName);
347
+ t(s);
348
+ const i = { kind: "or", children: [...s.rootGroup.children] };
349
+ return this.rootGroup.children.push(i), this;
350
+ }
351
+ not(t) {
352
+ const s = new w(this.store, this.queryModelName);
353
+ t(s);
354
+ const i = { kind: "not", children: [...s.rootGroup.children] };
355
+ return this.rootGroup.children.push(i), this;
356
+ }
357
+ orderBy(t, s = "asc") {
358
+ return this.orderByClauses.push({ field: t, direction: s }), this;
359
+ }
360
+ limit(t) {
361
+ return this.limitValue = t, this;
362
+ }
363
+ offset(t) {
364
+ return this.offsetValue = t, this;
365
+ }
366
+ include(t) {
367
+ return this.includesList.includes(t) || this.includesList.push(t), this;
368
+ }
369
+ toQueryObject() {
370
+ return {
371
+ modelName: this.queryModelName,
372
+ filters: { kind: "and", children: [...this.rootGroup.children] },
373
+ orderBy: [...this.orderByClauses],
374
+ limit: this.limitValue,
375
+ offset: this.offsetValue,
376
+ includes: [...this.includesList]
377
+ };
378
+ }
379
+ async toArray() {
380
+ const t = this.toQueryObject();
381
+ p.validate(t, this.store.schema);
382
+ const s = this.store.peekAll(this.queryModelName).toArray();
383
+ return R.executeMany(s, t);
384
+ }
385
+ async first() {
386
+ const t = this.toQueryObject();
387
+ p.validate(t, this.store.schema);
388
+ const s = this.store.peekAll(this.queryModelName).toArray();
389
+ return R.executeOne(s, t);
390
+ }
391
+ async count() {
392
+ const t = this.toQueryObject();
393
+ p.validate(t, this.store.schema);
394
+ const s = this.store.peekAll(this.queryModelName).toArray();
395
+ return R.count(s, t);
396
+ }
397
+ async exists() {
398
+ const t = this.toQueryObject();
399
+ p.validate(t, this.store.schema);
400
+ const s = this.store.peekAll(this.queryModelName).toArray();
401
+ return R.exists(s, t);
402
+ }
403
+ toLiveArray() {
404
+ const t = this.toQueryObject();
405
+ p.validate(t, this.store.schema);
406
+ const s = R.compilePredicate(t);
407
+ return this.store.liveQuery(this.queryModelName, s);
408
+ }
409
+ }
410
+ var W = Object.getOwnPropertyDescriptor, H = (e, t, s, i) => {
411
+ for (var r = i > 1 ? void 0 : i ? W(t, s) : t, n = e.length - 1, o; n >= 0; n--)
412
+ (o = e[n]) && (r = o(r) || r);
413
+ return r;
414
+ }, V = (e, t) => (s, i) => t(s, i, e);
415
+ let y = class {
416
+ constructor(e) {
417
+ this.identityMap = new L(), 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 = e;
418
+ }
419
+ static refEquals(e, t) {
420
+ return e.id === t.id && e.type === t.type;
421
+ }
422
+ // --- registration ---
423
+ /** Registers an adapter for a given model name (or `'application'` as a fallback). */
424
+ registerAdapter(e, t) {
425
+ this.adapters.set(e, t);
426
+ }
427
+ /** Registers a serializer for a given model name (or `'application'` as a fallback). */
428
+ registerSerializer(e, t) {
429
+ this.serializers.set(e, t);
430
+ }
431
+ /** Registers a persistent cache layer (e.g. IndexedDB) for offline-first reads. */
432
+ registerCache(e) {
433
+ this._cache = e;
434
+ }
435
+ /**
436
+ * Returns the adapter for `modelName`, falling back to `'application'`.
437
+ * @throws when no adapter is registered.
438
+ */
439
+ adapterFor(e) {
440
+ const t = this.adapters.get(e) ?? this.adapters.get("application");
441
+ if (!t)
442
+ throw new Error(`No adapter registered for "${e}"`);
443
+ return t;
444
+ }
445
+ /**
446
+ * Returns the serializer for `modelName`, falling back to `'application'`.
447
+ * @throws when no serializer is registered.
448
+ */
449
+ serializerFor(e) {
450
+ const t = this.serializers.get(e) ?? this.serializers.get("application");
451
+ if (!t)
452
+ throw new Error(`No serializer registered for "${e}"`);
453
+ return t;
454
+ }
455
+ // --- creating ---
456
+ /**
457
+ * Creates a new (unsaved) record of the given type with optional initial data.
458
+ * The record is tracked in `newRecords` until it is saved or rolled back.
459
+ *
460
+ * @throws when `modelName` has not been registered with `SchemaService`.
461
+ */
462
+ createRecord(e, t = {}) {
463
+ if (!this.schema.doesTypeExist(e))
464
+ throw new Error(`Unknown model type: "${e}"`);
465
+ const s = this.schema.modelFor(e), i = new s({ id: null, data: t, store: this });
466
+ return this.trackNewRecord(e, i), i;
467
+ }
468
+ trackNewRecord(e, t) {
469
+ let s = this.newRecords.get(e);
470
+ s || (s = /* @__PURE__ */ new Set(), this.newRecords.set(e, s)), s.add(t), this.newRecordTypes.set(t, e);
471
+ }
472
+ untrackNewRecord(e) {
473
+ var s;
474
+ const t = this.newRecordTypes.get(e);
475
+ t && ((s = this.newRecords.get(t)) == null || s.delete(e), this.newRecordTypes.delete(e));
476
+ }
477
+ // --- peeking ---
478
+ /**
479
+ * Synchronously returns a record from the identity map, or `null` when not
480
+ * found. Does not trigger a network request.
481
+ */
482
+ peekRecord(e, t) {
483
+ const s = t == null ? null : String(t);
484
+ if (s === null)
485
+ return null;
486
+ const i = this.identityMap.get(e, s);
487
+ if (i) return i;
488
+ const r = this.schema.polymorphicRootFor(e);
489
+ if (r) {
490
+ const n = this.identityMap.get(r, s);
491
+ if (n && n instanceof this.schema.modelFor(e))
492
+ return n;
493
+ }
494
+ return null;
495
+ }
496
+ /**
497
+ * Returns a live `RecordArray` backed by the identity map for `modelName`.
498
+ * New (unsaved) records are included at the end.
499
+ * Does not trigger a network request.
500
+ */
501
+ peekAll(e) {
502
+ return new A({
503
+ modelName: e,
504
+ source: () => {
505
+ const t = this.identityMap.all(e), s = this.newRecords.get(e);
506
+ return !s || s.size === 0 ? t : [...t, ...s];
507
+ }
508
+ });
509
+ }
510
+ // --- push / normalize ---
511
+ /**
512
+ * Pushes a normalized document into the identity map.
513
+ * Side-loaded (`included`) records are pushed first.
514
+ *
515
+ * @returns The primary record(s), or `null` for empty payloads.
516
+ */
517
+ push(e) {
518
+ const t = e;
519
+ if (t.included)
520
+ for (const s of t.included)
521
+ this.pushResource(s);
522
+ return t.data === null || t.data === void 0 ? null : Array.isArray(t.data) ? t.data.map((s) => this.pushResource(s)) : this.pushResource(t.data);
523
+ }
524
+ /**
525
+ * Normalizes a raw payload via the registered serializer and pushes the
526
+ * result. `modelName` is optional; when omitted the payload is pushed
527
+ * directly without normalization.
528
+ */
529
+ pushPayload(e, t) {
530
+ let s, i;
531
+ typeof e == "string" ? (s = e, i = t) : (s = null, i = e);
532
+ const r = s ? this.serializerFor(s).normalizeResponse(
533
+ this,
534
+ this.schema.modelFor(s),
535
+ i,
536
+ null,
537
+ "pushPayload"
538
+ ) : i;
539
+ this.push(r);
540
+ }
541
+ /**
542
+ * Normalizes a raw payload for `modelName` via the registered serializer
543
+ * and returns the `NormalizedDocument` without pushing it.
544
+ */
545
+ normalize(e, t) {
546
+ return this.serializerFor(e).normalizeResponse(
547
+ this,
548
+ this.schema.modelFor(e),
549
+ t,
550
+ null,
551
+ "normalize"
552
+ );
553
+ }
554
+ /**
555
+ * Inserts or merges a single normalized resource into the identity map.
556
+ * - Existing record → calls `_applyServerData` to merge attributes and
557
+ * relationships in place (preserving the live reference).
558
+ * - New record → instantiates via `Model.push` and sets it in the map.
559
+ *
560
+ * @throws when `type` has not been registered or `id` is `null`.
561
+ */
562
+ pushResource(e) {
563
+ const { type: t, id: s } = e;
564
+ if (!this.schema.doesTypeExist(t))
565
+ throw new Error(`Unknown model type: "${t}"`);
566
+ if (s === null)
567
+ throw new Error(`Cannot push a resource of type "${t}" without an id`);
568
+ let i = t, r = this.schema.modelFor(t);
569
+ const n = this.schema.resolveConcreteModel(
570
+ t,
571
+ e.attributes ?? {}
572
+ );
573
+ n && (r = n.modelClass, i = t);
574
+ const o = this.schema.polymorphicRootFor(t);
575
+ o && (i = o);
576
+ const a = this.identityMap.get(i, s);
577
+ if (a)
578
+ return u(() => {
579
+ a._applyServerData(null, e.attributes ?? {}, e.relationships);
580
+ }), this.trackInverseForResource(a, e), a;
581
+ const l = r, h = q.push.call(l, {
582
+ id: s,
583
+ data: e.attributes ?? {},
584
+ relationships: e.relationships,
585
+ store: this
586
+ });
587
+ return this.identityMap.set(i, s, h), this.trackInverseForResource(h, e), h;
588
+ }
589
+ /**
590
+ * After pushing a resource, updates the inverse side of every declared
591
+ * inverse relationship so both sides stay consistent.
592
+ */
593
+ trackInverseForResource(e, t) {
594
+ if (t.relationships)
595
+ for (const [s, i] of Object.entries(t.relationships)) {
596
+ const r = this.schema.relationshipsDefinitionFor(e.modelName).get(s);
597
+ if (!r || !r.options.inverse || !i.data)
598
+ continue;
599
+ const n = Array.isArray(i.data) ? i.data : [i.data];
600
+ for (const o of n)
601
+ this.addInverse(o.type, o.id, r.options.inverse, e);
602
+ }
603
+ }
604
+ /**
605
+ * Adds `inverseRecord` to the inverse relationship on `targetType:targetId`.
606
+ * No-ops when the target record is not in the identity map.
607
+ */
608
+ addInverse(e, t, s, i) {
609
+ const r = this.identityMap.get(e, t);
610
+ if (!r)
611
+ return;
612
+ const o = this.schema.relationshipsDefinitionFor(e).get(s);
613
+ if (!o)
614
+ return;
615
+ const a = r._getRelationshipRef(s), l = { type: i.modelName, id: i.id };
616
+ u(() => {
617
+ if (o.kind === "hasMany") {
618
+ const h = a != null && a.data && Array.isArray(a.data) ? a.data : [];
619
+ h.some((c) => y.refEquals(c, l)) || r._setRelationshipRef(s, { data: [...h, l] });
620
+ } else
621
+ r._setRelationshipRef(s, { data: l });
622
+ });
623
+ }
624
+ /**
625
+ * Removes `inverseRecord` from the inverse relationship on `targetType:targetId`.
626
+ * No-ops when the target record is not in the identity map.
627
+ */
628
+ removeInverse(e, t, s, i) {
629
+ const r = this.identityMap.get(e, t);
630
+ if (!r)
631
+ return;
632
+ const o = this.schema.relationshipsDefinitionFor(e).get(s);
633
+ if (!o)
634
+ return;
635
+ const a = r._getRelationshipRef(s);
636
+ u(() => {
637
+ if (o.kind === "hasMany") {
638
+ const h = (a != null && a.data && Array.isArray(a.data) ? a.data : []).filter((c) => !(c.id === i.id && c.type === i.modelName));
639
+ r._setRelationshipRef(s, { data: h });
640
+ } else
641
+ r._setRelationshipRef(s, { data: null });
642
+ });
643
+ }
644
+ // --- unload ---
645
+ /**
646
+ * Removes a record from the identity map and clears its relationship cache.
647
+ * Called by `record.unloadRecord()` and internally after `deleteRecord`.
648
+ */
649
+ unloadRecord(e) {
650
+ e.id !== null && this.identityMap.delete(e.modelName, e.id), this.untrackNewRecord(e), this.relationshipCache.delete(e);
651
+ }
652
+ /**
653
+ * Unloads all records for `modelName`, or all records across all types when
654
+ * `modelName` is omitted.
655
+ */
656
+ unloadAll(e) {
657
+ var t;
658
+ if (e) {
659
+ for (const s of this.identityMap.all(e))
660
+ this.relationshipCache.delete(s);
661
+ this.identityMap.clear(e), (t = this.newRecords.get(e)) == null || t.clear();
662
+ } else
663
+ this.identityMap.clear(), this.newRecords.clear();
664
+ }
665
+ // --- find ---
666
+ /**
667
+ * Finds a single record by id. Returns the cached record immediately when
668
+ * `options.reload` is not set; otherwise re-fetches.
669
+ *
670
+ * When the adapter has `coalesceFindRequests: true` and `findMany` is
671
+ * implemented, multiple concurrent `findRecord` calls for the same type
672
+ * are batched into a single `findMany` network request.
673
+ */
674
+ async findRecord(e, t, s = {}) {
675
+ const i = this.peekRecord(e, t);
676
+ if (i && !s.reload && !s.include)
677
+ return i;
678
+ if (!s.reload && !s.include && this._cache) {
679
+ const d = await this._cache.get(e, t);
680
+ if (d)
681
+ return this.push({
682
+ data: {
683
+ type: d.modelName,
684
+ id: d.id,
685
+ attributes: d.attributes,
686
+ relationships: d.relationships
687
+ }
688
+ });
689
+ }
690
+ const r = this.adapterFor(e);
691
+ if (r.coalesceFindRequests && r.findMany && !s.include)
692
+ return this.scheduleCoalescedFind(e, t);
693
+ const n = i ? this.createSnapshot(i) : this.createEmptySnapshot(e, t), o = s.include ? { include: s.include, adapterOptions: s.adapterOptions } : s.adapterOptions ? { adapterOptions: s.adapterOptions } : void 0, a = await r.findRecord(this, e, t, n, o), l = F(a), h = this.serializerFor(e).normalizeResponse(
694
+ this,
695
+ this.schema.modelFor(e),
696
+ a,
697
+ t,
698
+ "findRecord"
699
+ ), c = this.push(h);
700
+ if (this._cache) {
701
+ const d = l ? _(l) : null;
702
+ d !== 0 && this.cacheNormalizedDocument(h, d ?? void 0);
703
+ }
704
+ return c;
705
+ }
706
+ /**
707
+ * Fetches all records of `modelName` from the server and returns a
708
+ * `RecordArray` backed by the identity map.
709
+ */
710
+ async findAll(e, t = {}) {
711
+ const s = this.adapterFor(e), i = t.include ? { include: t.include, adapterOptions: t.adapterOptions } : t.adapterOptions ? { adapterOptions: t.adapterOptions } : void 0, r = await s.findAll(this, e, null, [], i), n = F(r), o = this.serializerFor(e).normalizeResponse(
712
+ this,
713
+ this.schema.modelFor(e),
714
+ r,
715
+ null,
716
+ "findAll"
717
+ );
718
+ if (this.push(o), this._cache) {
719
+ const a = n ? _(n) : null;
720
+ a !== 0 && this.cacheNormalizedDocument(o, a ?? void 0);
721
+ }
722
+ return this.peekAll(e);
723
+ }
724
+ /**
725
+ * Executes an adapter query and returns an `AdapterPopulatedRecordArray`
726
+ * whose `update()` method re-issues the same query.
727
+ */
728
+ async query(e, t) {
729
+ const s = [], i = new Q({
730
+ modelName: e,
731
+ query: t,
732
+ source: () => s.map((r) => this.peekRecord(e, r)).filter((r) => r !== null),
733
+ update: async () => {
734
+ await this.runQuery(e, t, i, s);
735
+ }
736
+ });
737
+ return await this.runQuery(e, t, i, s), i;
738
+ }
739
+ async runQuery(e, t, s, i) {
740
+ const n = await this.adapterFor(e).query(this, e, t, s), o = this.serializerFor(e).normalizeResponse(
741
+ this,
742
+ this.schema.modelFor(e),
743
+ n,
744
+ null,
745
+ "query"
746
+ );
747
+ if (this.push(o), i.length = 0, Array.isArray(o.data))
748
+ for (const a of o.data)
749
+ a.id && i.push(a.id);
750
+ o.meta && s._setMeta(o.meta), o.links && s._setLinks(o.links);
751
+ }
752
+ /**
753
+ * Executes an adapter query that returns at most one record.
754
+ * Returns `null` when the adapter returns an empty payload.
755
+ */
756
+ async queryRecord(e, t) {
757
+ const i = await this.adapterFor(e).queryRecord(this, e, t), r = this.serializerFor(e).normalizeResponse(
758
+ this,
759
+ this.schema.modelFor(e),
760
+ i,
761
+ null,
762
+ "queryRecord"
763
+ ), n = this.push(r);
764
+ return Array.isArray(n) ? n[0] ?? null : n ?? null;
765
+ }
766
+ // --- save / delete / reload from Model ---
767
+ /**
768
+ * Persists a record to the server.
769
+ * - New records → `adapter.createRecord` (POST)
770
+ * - Existing dirty records → `adapter.updateRecord` (PUT) by default
771
+ * - With `{ patch: true }` → `adapter.patchRecord` (PATCH, partial payload)
772
+ *
773
+ * After the response is received the server data is applied back to the
774
+ * record via `_applyServerData` so it transitions to `saved`.
775
+ */
776
+ async saveRecord(e, t = {}) {
777
+ const s = this.adapterFor(e.modelName), { isNew: i } = e;
778
+ i && this.schema.hasClientGeneratedIds(e.modelName) && e.id === null && (e.id = e._clientId);
779
+ const r = this.createSnapshot(e);
780
+ let n;
781
+ i ? n = await s.createRecord(this, e.modelName, r) : t.patch && s.patchRecord ? n = await s.patchRecord(this, e.modelName, r) : n = await s.updateRecord(this, e.modelName, r);
782
+ const o = this.serializerFor(e.modelName).normalizeResponse(
783
+ this,
784
+ this.schema.modelFor(e.modelName),
785
+ n,
786
+ e.id,
787
+ i ? "createRecord" : "updateRecord"
788
+ ), a = o.data;
789
+ if (a) {
790
+ const l = a.id ?? e.id;
791
+ u(() => {
792
+ e._applyServerData(l, a.attributes ?? {}, a.relationships);
793
+ }), i && l && (this.untrackNewRecord(e), this.identityMap.set(e.modelName, l, e));
794
+ }
795
+ if (o.included)
796
+ for (const l of o.included)
797
+ this.pushResource(l);
798
+ if (this._cache && e.id) {
799
+ const l = e, h = {};
800
+ for (const [c, d] of l._relationships)
801
+ h[c] = d;
802
+ this._cache.set(e.modelName, e.id, { ...l._data }, {
803
+ relationships: Object.keys(h).length > 0 ? h : void 0
804
+ });
805
+ }
806
+ return e;
807
+ }
808
+ /**
809
+ * Issues a DELETE request and unloads the record from the identity map.
810
+ */
811
+ async deleteRecord(e) {
812
+ const t = this.adapterFor(e.modelName), s = this.createSnapshot(e);
813
+ return await t.deleteRecord(this, e.modelName, s), this._cache && e.id && this._cache.invalidate(e.modelName, e.id), this.unloadRecord(e), e;
814
+ }
815
+ /**
816
+ * Re-fetches a record from the server and merges the response into the
817
+ * existing instance.
818
+ */
819
+ async reloadRecord(e) {
820
+ if (!e.id)
821
+ throw new Error("Cannot reload a record without an id");
822
+ const t = this.adapterFor(e.modelName), s = this.createSnapshot(e), i = await t.findRecord(this, e.modelName, e.id, s), r = this.serializerFor(e.modelName).normalizeResponse(
823
+ this,
824
+ this.schema.modelFor(e.modelName),
825
+ i,
826
+ e.id,
827
+ "findRecord"
828
+ );
829
+ return this.push(r), e;
830
+ }
831
+ // --- snapshot ---
832
+ /**
833
+ * Creates a `Snapshot` for a live record.
834
+ * The snapshot reads directly from the record's internal state so it
835
+ * reflects the current (possibly dirty) values.
836
+ */
837
+ createSnapshot(e) {
838
+ const { modelName: t } = e, s = this.schema.attributesDefinitionFor(t), i = this.schema.relationshipsDefinitionFor(t), r = e;
839
+ return {
840
+ id: e.id,
841
+ clientId: e._clientId,
842
+ modelName: t,
843
+ record: e,
844
+ attr: (n) => r._data[n],
845
+ belongsTo: (n, o) => {
846
+ const a = r._getRelationshipRef(n);
847
+ return !(a != null && a.data) || Array.isArray(a.data) ? null : o != null && o.id ? a.data.id : this.peekRecord(a.data.type, a.data.id);
848
+ },
849
+ hasMany: (n, o) => {
850
+ const a = r._getRelationshipRef(n), l = a != null && a.data && Array.isArray(a.data) ? a.data : [];
851
+ return o != null && o.ids ? l.map((h) => h.id) : l.map((h) => this.peekRecord(h.type, h.id)).filter((h) => h !== null);
852
+ },
853
+ changedAttributes: () => r.changedAttributes(),
854
+ eachAttribute: (n) => {
855
+ for (const [o, a] of s)
856
+ n(o, a);
857
+ },
858
+ eachRelationship: (n) => {
859
+ for (const [o, a] of i)
860
+ n(o, a);
861
+ }
862
+ };
863
+ }
864
+ /**
865
+ * Creates a placeholder `Snapshot` for a record that is not yet in the
866
+ * identity map (used when fetching a record that isn't cached).
867
+ */
868
+ createEmptySnapshot(e, t) {
869
+ const s = this.schema.attributesDefinitionFor(e), i = this.schema.relationshipsDefinitionFor(e);
870
+ return {
871
+ id: t,
872
+ clientId: "",
873
+ modelName: e,
874
+ record: null,
875
+ attr: () => {
876
+ },
877
+ belongsTo: () => null,
878
+ hasMany: () => [],
879
+ changedAttributes: () => ({}),
880
+ eachAttribute: (r) => {
881
+ for (const [n, o] of s)
882
+ r(n, o);
883
+ },
884
+ eachRelationship: (r) => {
885
+ for (const [n, o] of i)
886
+ r(n, o);
887
+ }
888
+ };
889
+ }
890
+ // --- relationship resolution (called by Model) ---
891
+ getRelationshipCache(e, t) {
892
+ var s;
893
+ return (s = this.relationshipCache.get(e)) == null ? void 0 : s.get(t);
894
+ }
895
+ setRelationshipCache(e, t, s) {
896
+ let i = this.relationshipCache.get(e);
897
+ i || (i = /* @__PURE__ */ new Map(), this.relationshipCache.set(e, i)), i.set(t, s);
898
+ }
899
+ /**
900
+ * Called by the `Model` relationship getter to resolve a relationship.
901
+ *
902
+ * - **Async** `belongsTo` → returns an `AsyncBelongsTo` wrapper.
903
+ * - **Async** `hasMany` → returns an `AsyncHasMany` wrapper.
904
+ * - **Sync** `belongsTo` → peeks the related record from the identity map.
905
+ * - **Sync** `hasMany` → returns a `ManyArray` backed by the store.
906
+ *
907
+ * Results are cached per record + name so the same proxy is returned on
908
+ * repeated accesses (important for MobX observability).
909
+ */
910
+ resolveRelationship(e, t, s) {
911
+ const i = s.options.async === !0, r = this.getRelationshipCache(e, t);
912
+ if (r)
913
+ return r;
914
+ const n = {
915
+ parent: e,
916
+ name: t,
917
+ meta: s,
918
+ store: this
919
+ };
920
+ if (i) {
921
+ if (s.kind === "belongsTo") {
922
+ const l = new $(n);
923
+ return this.setRelationshipCache(e, t, l), l;
924
+ }
925
+ const a = new P(n);
926
+ return this.setRelationshipCache(e, t, a), a;
927
+ }
928
+ if (s.kind === "belongsTo") {
929
+ const a = e._getRelationshipRef(t);
930
+ return !(a != null && a.data) || Array.isArray(a.data) ? null : this.peekRecord(a.data.type, a.data.id);
931
+ }
932
+ const o = new x(n);
933
+ return this.setRelationshipCache(e, t, o), o;
934
+ }
935
+ /**
936
+ * Called by the `Model` `belongsTo` setter to update a relationship ref
937
+ * and keep its inverse in sync.
938
+ */
939
+ setRelationshipValue(e, t, s, i) {
940
+ if (s.kind !== "belongsTo")
941
+ return;
942
+ const r = e._getRelationshipRef(t), n = r != null && r.data && !Array.isArray(r.data) ? r.data : null;
943
+ if (i == null) {
944
+ u(() => {
945
+ e._setRelationshipRef(t, { data: null });
946
+ }), n && s.options.inverse && this.removeInverse(n.type, n.id, s.options.inverse, e);
947
+ return;
948
+ }
949
+ const o = i, a = { type: o.modelName, id: o.id };
950
+ u(() => {
951
+ e._setRelationshipRef(t, { data: a });
952
+ }), s.options.inverse && (n && !y.refEquals(n, a) && this.removeInverse(n.type, n.id, s.options.inverse, e), this.addInverse(a.type, a.id, s.options.inverse, e));
953
+ }
954
+ // --- hooks used by ManyArray ---
955
+ /** Returns the raw relationship ref stored on `record` for `name`. */
956
+ _getRelationshipRefFor(e, t) {
957
+ return e._getRelationshipRef(t);
958
+ }
959
+ /** Returns any pending (unsaved) members for a `hasMany` relationship. */
960
+ _getPendingMembers(e, t) {
961
+ var s;
962
+ return ((s = this.pendingMembers.get(e)) == null ? void 0 : s.get(t)) ?? [];
963
+ }
964
+ addPendingMember(e, t, s) {
965
+ let i = this.pendingMembers.get(e);
966
+ i || (i = /* @__PURE__ */ new Map(), this.pendingMembers.set(e, i));
967
+ let r = i.get(t);
968
+ r || (r = g.set(), i.set(t, r)), r.add(s);
969
+ }
970
+ removePendingMember(e, t, s) {
971
+ var i, r;
972
+ (r = (i = this.pendingMembers.get(e)) == null ? void 0 : i.get(t)) == null || r.delete(s);
973
+ }
974
+ /**
975
+ * Appends `value` to the `hasMany` relationship ref on `record` and syncs
976
+ * the inverse. Unsaved records (`value.id === null`) are tracked as
977
+ * "pending members" until they are persisted.
978
+ */
979
+ _hasManyAppend(e, t, s, i) {
980
+ if (i.id === null) {
981
+ if (this.addPendingMember(e, t, i), s.options.inverse) {
982
+ const a = this.schema.relationshipsDefinitionFor(i.modelName).get(s.options.inverse);
983
+ (a == null ? void 0 : a.kind) === "belongsTo" && u(() => {
984
+ i._setRelationshipRef(s.options.inverse, {
985
+ data: { type: e.modelName, id: e.id }
986
+ });
987
+ });
988
+ }
989
+ return;
990
+ }
991
+ const r = this._getRelationshipRefFor(e, t), n = r != null && r.data && Array.isArray(r.data) ? r.data : [], o = { type: i.modelName, id: i.id };
992
+ n.some((a) => y.refEquals(a, o)) || u(() => {
993
+ e._setRelationshipRef(t, { data: [...n, o] });
994
+ }), s.options.inverse && this.addInverse(i.modelName, i.id, s.options.inverse, e);
995
+ }
996
+ /**
997
+ * Removes `value` from the `hasMany` relationship ref on `record` and syncs
998
+ * the inverse. Pending members are removed from the pending set.
999
+ */
1000
+ _hasManyRemove(e, t, s, i) {
1001
+ if (i.id === null) {
1002
+ this.removePendingMember(e, t, i);
1003
+ return;
1004
+ }
1005
+ const r = this._getRelationshipRefFor(e, t), o = (r != null && r.data && Array.isArray(r.data) ? r.data : []).filter(
1006
+ (a) => !(a.id === i.id && a.type === i.modelName)
1007
+ );
1008
+ u(() => {
1009
+ e._setRelationshipRef(t, { data: o });
1010
+ }), s.options.inverse && this.removeInverse(i.modelName, i.id, s.options.inverse, e);
1011
+ }
1012
+ // --- persistent cache helpers ---
1013
+ cacheNormalizedDocument(e, t) {
1014
+ const s = [];
1015
+ e.data && (Array.isArray(e.data) ? s.push(...e.data) : s.push(e.data)), e.included && s.push(...e.included);
1016
+ for (const i of s)
1017
+ i.id && this._cache.set(i.type, i.id, i.attributes ?? {}, {
1018
+ relationships: i.relationships,
1019
+ ttl: t
1020
+ });
1021
+ }
1022
+ scheduleCoalescedFind(e, t) {
1023
+ return new Promise((s, i) => {
1024
+ let r = this.coalescePending.get(e);
1025
+ r || (r = /* @__PURE__ */ new Map(), this.coalescePending.set(e, r));
1026
+ let n = r.get(t);
1027
+ n || (n = [], r.set(t, n)), n.push({ resolve: s, reject: i }), this.coalesceScheduled.has(e) || (this.coalesceScheduled.add(e), queueMicrotask(() => this.flushCoalescedFind(e)));
1028
+ });
1029
+ }
1030
+ async flushCoalescedFind(e) {
1031
+ this.coalesceScheduled.delete(e);
1032
+ const t = this.coalescePending.get(e), s = new Map(t);
1033
+ t.clear();
1034
+ const i = Array.from(s.keys()), r = this.adapterFor(e);
1035
+ try {
1036
+ const n = i.map((l) => {
1037
+ const h = this.peekRecord(e, l);
1038
+ return h ? this.createSnapshot(h) : this.createEmptySnapshot(e, l);
1039
+ }), o = await r.findMany(this, e, i, n), a = this.serializerFor(e).normalizeResponse(
1040
+ this,
1041
+ this.schema.modelFor(e),
1042
+ o,
1043
+ null,
1044
+ "findMany"
1045
+ );
1046
+ this.push(a);
1047
+ for (const l of i) {
1048
+ const h = this.peekRecord(e, l), c = s.get(l);
1049
+ if (c)
1050
+ for (const d of c)
1051
+ h ? d.resolve(h) : d.reject(new Error(`Record not found after findMany: ${e}:${l}`));
1052
+ }
1053
+ } catch (n) {
1054
+ for (const o of s.values())
1055
+ for (const a of o)
1056
+ a.reject(n);
1057
+ }
1058
+ }
1059
+ // --- liveQuery ---
1060
+ /**
1061
+ * Returns a reactive `RecordArray` that auto-updates whenever records matching
1062
+ * the predicate are added, removed, or mutated in the identity map.
1063
+ *
1064
+ * The underlying computed uses `keepAlive: true` so it remains cached even
1065
+ * without active MobX observers — useful for long-lived filtered views.
1066
+ *
1067
+ * @param modelName - The registered model type to query.
1068
+ * @param predicate - Filter function applied to each record of `modelName`.
1069
+ * @returns A live `RecordArray` containing only records that satisfy `predicate`.
1070
+ */
1071
+ liveQuery(e, t) {
1072
+ return new A({
1073
+ modelName: e,
1074
+ keepAlive: !0,
1075
+ source: () => {
1076
+ const s = this.identityMap.all(e), i = this.newRecords.get(e);
1077
+ return (i && i.size > 0 ? [...s, ...i] : s).filter(t);
1078
+ }
1079
+ });
1080
+ }
1081
+ // --- select (MDQL) ---
1082
+ select(e) {
1083
+ if (!this.schema.doesTypeExist(e))
1084
+ throw new Error(`Unknown model type: "${e}"`);
1085
+ return new w(this, e);
1086
+ }
1087
+ // --- optimisticUpdate ---
1088
+ /**
1089
+ * Applies attribute changes to a record immediately (optimistically), then
1090
+ * executes `persistFn`. If `persistFn` throws, the record is automatically
1091
+ * rolled back to its state before the optimistic update.
1092
+ *
1093
+ * @param record - The record to update optimistically.
1094
+ * @param optimisticAttributes - Attributes to apply before persistence.
1095
+ * @param persistFn - Async function that persists the change (e.g. `record.save()`).
1096
+ * @returns The record on success.
1097
+ * @throws Re-throws the error from `persistFn` after rollback.
1098
+ */
1099
+ async optimisticUpdate(e, t, s) {
1100
+ const i = e, r = { ...i._data };
1101
+ u(() => {
1102
+ for (const n of Object.keys(t))
1103
+ n === "__proto__" || n === "constructor" || n === "prototype" || (i._data[n] = t[n]);
1104
+ });
1105
+ try {
1106
+ return await s(), e;
1107
+ } catch (n) {
1108
+ throw u(() => {
1109
+ for (const [o, a] of Object.entries(r))
1110
+ i._data[o] = a;
1111
+ }), n;
1112
+ }
1113
+ }
1114
+ // --- runInTransaction ---
1115
+ /**
1116
+ * Executes multiple store mutations as a single MobX action, guaranteeing
1117
+ * that observers (and therefore UI renders) react only once — after all
1118
+ * mutations have been applied.
1119
+ *
1120
+ * @param callback - Synchronous function containing one or more store mutations.
1121
+ */
1122
+ runInTransaction(e) {
1123
+ u(e);
1124
+ }
1125
+ // --- SSR: serialize / hydrate ---
1126
+ /**
1127
+ * Produces a JSON-serializable snapshot of all records in the identity map.
1128
+ * Designed for server-side rendering: serialize on the server, transfer as
1129
+ * JSON, then `hydrate()` on the client to restore the full store state
1130
+ * without network requests.
1131
+ *
1132
+ * @param options.exclude - Per-model-type list of attribute keys to omit
1133
+ * (e.g. `{ user: ['password', 'token'] }`) to prevent leaking sensitive
1134
+ * data in SSR payloads.
1135
+ * @returns A snapshot object safe to pass through `JSON.stringify`.
1136
+ */
1137
+ serialize(e = {}) {
1138
+ var i;
1139
+ const t = {}, s = this.identityMap._buckets;
1140
+ for (const [r, n] of s) {
1141
+ const o = (i = e.exclude) == null ? void 0 : i[r], a = [];
1142
+ for (const [l, h] of n) {
1143
+ const c = h;
1144
+ let d;
1145
+ if (o && o.length > 0) {
1146
+ d = {};
1147
+ for (const [m, k] of Object.entries(c._data))
1148
+ o.includes(m) || (d[m] = k);
1149
+ } else
1150
+ d = { ...c._data };
1151
+ const b = {
1152
+ id: l,
1153
+ attributes: d
1154
+ };
1155
+ if (c._relationships && c._relationships.size > 0) {
1156
+ const m = {};
1157
+ for (const [k, D] of c._relationships)
1158
+ m[k] = D;
1159
+ b.relationships = m;
1160
+ }
1161
+ a.push(b);
1162
+ }
1163
+ a.length > 0 && (t[r] = a);
1164
+ }
1165
+ return { records: t };
1166
+ }
1167
+ /**
1168
+ * Restores records from a snapshot produced by `serialize()` into this store
1169
+ * instance. All records are pushed into the identity map in `loaded.saved`
1170
+ * state — no network requests are issued.
1171
+ *
1172
+ * @param snapshot - A snapshot object previously returned by `serialize()`.
1173
+ */
1174
+ hydrate(e) {
1175
+ u(() => {
1176
+ for (const [t, s] of Object.entries(e.records))
1177
+ for (const i of s)
1178
+ this.pushResource({
1179
+ type: t,
1180
+ id: i.id,
1181
+ attributes: i.attributes,
1182
+ relationships: i.relationships
1183
+ });
1184
+ });
1185
+ }
1186
+ /**
1187
+ * Factory method that creates a new `Store` and immediately hydrates it from
1188
+ * the given snapshot. Convenience for SSR client-side bootstrap.
1189
+ *
1190
+ * @param schema - SchemaService with all model types registered.
1191
+ * @param snapshot - A snapshot object previously returned by `serialize()`.
1192
+ * @returns A fully populated `Store` instance ready for use.
1193
+ */
1194
+ static hydrate(e, t) {
1195
+ const s = new y(e);
1196
+ return s.hydrate(t), s;
1197
+ }
1198
+ };
1199
+ y = H([
1200
+ T(),
1201
+ C(),
1202
+ V(0, I(z))
1203
+ ], y);
1204
+ function it(e) {
1205
+ if (typeof Reflect.getMetadata != "function")
1206
+ throw new Error(
1207
+ 'mobx-data requires reflect-metadata. Did you forget to import "reflect-metadata" at the top of your entry point?'
1208
+ );
1209
+ const t = new z();
1210
+ for (const n of e.models)
1211
+ t.registerModel(n.modelName, n);
1212
+ const s = new y(t), i = e.adapter ?? new N(), r = e.serializer ?? new j();
1213
+ for (const n of e.models)
1214
+ s.registerAdapter(n.modelName, i), s.registerSerializer(n.modelName, r);
1215
+ return s.registerAdapter("application", i), s.registerSerializer("application", r), s;
1216
+ }
1217
+ export {
1218
+ Q as A,
1219
+ L as I,
1220
+ w as M,
1221
+ G as O,
1222
+ A as R,
1223
+ y as S,
1224
+ E as a,
1225
+ B as b,
1226
+ it as c,
1227
+ p as d
1228
+ };
1229
+ //# sourceMappingURL=createStore-BfmRfZ_2.js.map