@iamjulianacosta/mobx-data 1.0.1

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 (215) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +366 -0
  3. package/dist/CacheHandler-BTU_rYkv.js +208 -0
  4. package/dist/CacheHandler-BTU_rYkv.js.map +1 -0
  5. package/dist/CacheHandler-CXgY9IJo.cjs +2 -0
  6. package/dist/CacheHandler-CXgY9IJo.cjs.map +1 -0
  7. package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs +2 -0
  8. package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs.map +1 -0
  9. package/dist/EmbeddedRecordsMixin-VoHluHCT.js +261 -0
  10. package/dist/EmbeddedRecordsMixin-VoHluHCT.js.map +1 -0
  11. package/dist/JsonApiSerializer-CC5HXp4b.js +194 -0
  12. package/dist/JsonApiSerializer-CC5HXp4b.js.map +1 -0
  13. package/dist/JsonApiSerializer-CKB02AgP.cjs +2 -0
  14. package/dist/JsonApiSerializer-CKB02AgP.cjs.map +1 -0
  15. package/dist/MemoryAdapter-Bx1e7ndV.js +123 -0
  16. package/dist/MemoryAdapter-Bx1e7ndV.js.map +1 -0
  17. package/dist/MemoryAdapter-D1cTyydm.cjs +2 -0
  18. package/dist/MemoryAdapter-D1cTyydm.cjs.map +1 -0
  19. package/dist/ODataAdapter-C4IHK4BK.js +157 -0
  20. package/dist/ODataAdapter-C4IHK4BK.js.map +1 -0
  21. package/dist/ODataAdapter-DyyF1sdA.cjs +2 -0
  22. package/dist/ODataAdapter-DyyF1sdA.cjs.map +1 -0
  23. package/dist/RestAdapter-B4aRvs4m.js +355 -0
  24. package/dist/RestAdapter-B4aRvs4m.js.map +1 -0
  25. package/dist/RestAdapter-CJOwTsKK.cjs +2 -0
  26. package/dist/RestAdapter-CJOwTsKK.cjs.map +1 -0
  27. package/dist/SchemaService-DZwkFgZu.js +102 -0
  28. package/dist/SchemaService-DZwkFgZu.js.map +1 -0
  29. package/dist/SchemaService-Di_yjVzU.cjs +2 -0
  30. package/dist/SchemaService-Di_yjVzU.cjs.map +1 -0
  31. package/dist/Serializer-95gi5edy.cjs +2 -0
  32. package/dist/Serializer-95gi5edy.cjs.map +1 -0
  33. package/dist/Serializer-FxJbsZ50.js +139 -0
  34. package/dist/Serializer-FxJbsZ50.js.map +1 -0
  35. package/dist/Store-BdwMrbDi.cjs +2 -0
  36. package/dist/Store-BdwMrbDi.cjs.map +1 -0
  37. package/dist/Store-CZ7Z-Nme.js +912 -0
  38. package/dist/Store-CZ7Z-Nme.js.map +1 -0
  39. package/dist/adapter/Adapter.d.ts +146 -0
  40. package/dist/adapter/Adapter.d.ts.map +1 -0
  41. package/dist/adapter/MemoryAdapter.d.ts +44 -0
  42. package/dist/adapter/MemoryAdapter.d.ts.map +1 -0
  43. package/dist/adapter/RestAdapter.d.ts +57 -0
  44. package/dist/adapter/RestAdapter.d.ts.map +1 -0
  45. package/dist/adapter/index.cjs +2 -0
  46. package/dist/adapter/index.cjs.map +1 -0
  47. package/dist/adapter/index.d.ts +4 -0
  48. package/dist/adapter/index.d.ts.map +1 -0
  49. package/dist/adapter/index.js +8 -0
  50. package/dist/adapter/index.js.map +1 -0
  51. package/dist/date-Bj4O2W1F.js +107 -0
  52. package/dist/date-Bj4O2W1F.js.map +1 -0
  53. package/dist/date-CRCe-9gf.cjs +2 -0
  54. package/dist/date-CRCe-9gf.cjs.map +1 -0
  55. package/dist/decorators-HQ1KnRdh.cjs +2 -0
  56. package/dist/decorators-HQ1KnRdh.cjs.map +1 -0
  57. package/dist/decorators-Zr35qr6A.js +50 -0
  58. package/dist/decorators-Zr35qr6A.js.map +1 -0
  59. package/dist/index.cjs +2 -0
  60. package/dist/index.cjs.map +1 -0
  61. package/dist/index.d.ts +10 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +52 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/json-api/JsonApiAdapter.d.ts +38 -0
  66. package/dist/json-api/JsonApiAdapter.d.ts.map +1 -0
  67. package/dist/json-api/JsonApiSerializer.d.ts +73 -0
  68. package/dist/json-api/JsonApiSerializer.d.ts.map +1 -0
  69. package/dist/json-api/index.cjs +2 -0
  70. package/dist/json-api/index.cjs.map +1 -0
  71. package/dist/json-api/index.d.ts +3 -0
  72. package/dist/json-api/index.d.ts.map +1 -0
  73. package/dist/json-api/index.js +6 -0
  74. package/dist/json-api/index.js.map +1 -0
  75. package/dist/model/Errors.d.ts +46 -0
  76. package/dist/model/Errors.d.ts.map +1 -0
  77. package/dist/model/Model.d.ts +226 -0
  78. package/dist/model/Model.d.ts.map +1 -0
  79. package/dist/model/Snapshot.d.ts +72 -0
  80. package/dist/model/Snapshot.d.ts.map +1 -0
  81. package/dist/model/StateMachine.d.ts +45 -0
  82. package/dist/model/StateMachine.d.ts.map +1 -0
  83. package/dist/model/index.cjs +2 -0
  84. package/dist/model/index.cjs.map +1 -0
  85. package/dist/model/index.d.ts +6 -0
  86. package/dist/model/index.d.ts.map +1 -0
  87. package/dist/model/index.js +11 -0
  88. package/dist/model/index.js.map +1 -0
  89. package/dist/model/relationships.d.ts +182 -0
  90. package/dist/model/relationships.d.ts.map +1 -0
  91. package/dist/odata/ODataAdapter.d.ts +67 -0
  92. package/dist/odata/ODataAdapter.d.ts.map +1 -0
  93. package/dist/odata/index.cjs +2 -0
  94. package/dist/odata/index.cjs.map +1 -0
  95. package/dist/odata/index.d.ts +2 -0
  96. package/dist/odata/index.d.ts.map +1 -0
  97. package/dist/odata/index.js +5 -0
  98. package/dist/odata/index.js.map +1 -0
  99. package/dist/relationships-B55LBaCW.cjs +2 -0
  100. package/dist/relationships-B55LBaCW.cjs.map +1 -0
  101. package/dist/relationships-BEXANmWg.js +821 -0
  102. package/dist/relationships-BEXANmWg.js.map +1 -0
  103. package/dist/request/CacheHandler.d.ts +50 -0
  104. package/dist/request/CacheHandler.d.ts.map +1 -0
  105. package/dist/request/FetchHandler.d.ts +41 -0
  106. package/dist/request/FetchHandler.d.ts.map +1 -0
  107. package/dist/request/RequestManager.d.ts +52 -0
  108. package/dist/request/RequestManager.d.ts.map +1 -0
  109. package/dist/request/index.cjs +2 -0
  110. package/dist/request/index.cjs.map +1 -0
  111. package/dist/request/index.d.ts +5 -0
  112. package/dist/request/index.d.ts.map +1 -0
  113. package/dist/request/index.js +7 -0
  114. package/dist/request/index.js.map +1 -0
  115. package/dist/request/types.d.ts +111 -0
  116. package/dist/request/types.d.ts.map +1 -0
  117. package/dist/schema/SchemaService.d.ts +58 -0
  118. package/dist/schema/SchemaService.d.ts.map +1 -0
  119. package/dist/schema/decorators.d.ts +50 -0
  120. package/dist/schema/decorators.d.ts.map +1 -0
  121. package/dist/schema/index.cjs +2 -0
  122. package/dist/schema/index.cjs.map +1 -0
  123. package/dist/schema/index.d.ts +4 -0
  124. package/dist/schema/index.d.ts.map +1 -0
  125. package/dist/schema/index.js +13 -0
  126. package/dist/schema/index.js.map +1 -0
  127. package/dist/schema/types.d.ts +61 -0
  128. package/dist/schema/types.d.ts.map +1 -0
  129. package/dist/serializer/EmbeddedRecordsMixin.d.ts +80 -0
  130. package/dist/serializer/EmbeddedRecordsMixin.d.ts.map +1 -0
  131. package/dist/serializer/JsonSerializer.d.ts +52 -0
  132. package/dist/serializer/JsonSerializer.d.ts.map +1 -0
  133. package/dist/serializer/RestSerializer.d.ts +43 -0
  134. package/dist/serializer/RestSerializer.d.ts.map +1 -0
  135. package/dist/serializer/Serializer.d.ts +202 -0
  136. package/dist/serializer/Serializer.d.ts.map +1 -0
  137. package/dist/serializer/index.cjs +2 -0
  138. package/dist/serializer/index.cjs.map +1 -0
  139. package/dist/serializer/index.d.ts +5 -0
  140. package/dist/serializer/index.d.ts.map +1 -0
  141. package/dist/serializer/index.js +9 -0
  142. package/dist/serializer/index.js.map +1 -0
  143. package/dist/store/IdentityMap.d.ts +53 -0
  144. package/dist/store/IdentityMap.d.ts.map +1 -0
  145. package/dist/store/RecordArray.d.ts +114 -0
  146. package/dist/store/RecordArray.d.ts.map +1 -0
  147. package/dist/store/Store.d.ts +395 -0
  148. package/dist/store/Store.d.ts.map +1 -0
  149. package/dist/store/index.cjs +2 -0
  150. package/dist/store/index.cjs.map +1 -0
  151. package/dist/store/index.d.ts +5 -0
  152. package/dist/store/index.d.ts.map +1 -0
  153. package/dist/store/index.js +8 -0
  154. package/dist/store/index.js.map +1 -0
  155. package/dist/transforms/Transform.d.ts +49 -0
  156. package/dist/transforms/Transform.d.ts.map +1 -0
  157. package/dist/transforms/boolean.d.ts +26 -0
  158. package/dist/transforms/boolean.d.ts.map +1 -0
  159. package/dist/transforms/date.d.ts +22 -0
  160. package/dist/transforms/date.d.ts.map +1 -0
  161. package/dist/transforms/index.cjs +2 -0
  162. package/dist/transforms/index.cjs.map +1 -0
  163. package/dist/transforms/index.d.ts +6 -0
  164. package/dist/transforms/index.d.ts.map +1 -0
  165. package/dist/transforms/index.js +9 -0
  166. package/dist/transforms/index.js.map +1 -0
  167. package/dist/transforms/number.d.ts +17 -0
  168. package/dist/transforms/number.d.ts.map +1 -0
  169. package/dist/transforms/string.d.ts +18 -0
  170. package/dist/transforms/string.d.ts.map +1 -0
  171. package/dist/types-C9NB2gRj.js +7 -0
  172. package/dist/types-C9NB2gRj.js.map +1 -0
  173. package/dist/types-uWOXMPWW.cjs +2 -0
  174. package/dist/types-uWOXMPWW.cjs.map +1 -0
  175. package/package.json +140 -0
  176. package/src/adapter/Adapter.ts +320 -0
  177. package/src/adapter/MemoryAdapter.ts +216 -0
  178. package/src/adapter/RestAdapter.ts +248 -0
  179. package/src/adapter/index.ts +7 -0
  180. package/src/index.ts +17 -0
  181. package/src/json-api/JsonApiAdapter.ts +93 -0
  182. package/src/json-api/JsonApiSerializer.ts +245 -0
  183. package/src/json-api/index.ts +2 -0
  184. package/src/model/Errors.ts +100 -0
  185. package/src/model/Model.ts +683 -0
  186. package/src/model/Snapshot.ts +162 -0
  187. package/src/model/StateMachine.ts +149 -0
  188. package/src/model/index.ts +20 -0
  189. package/src/model/relationships.ts +484 -0
  190. package/src/odata/ODataAdapter.ts +245 -0
  191. package/src/odata/index.ts +1 -0
  192. package/src/request/CacheHandler.ts +125 -0
  193. package/src/request/FetchHandler.ts +119 -0
  194. package/src/request/RequestManager.ts +112 -0
  195. package/src/request/index.ts +4 -0
  196. package/src/request/types.ts +139 -0
  197. package/src/schema/SchemaService.ts +161 -0
  198. package/src/schema/decorators.ts +162 -0
  199. package/src/schema/index.ts +3 -0
  200. package/src/schema/types.ts +66 -0
  201. package/src/serializer/EmbeddedRecordsMixin.ts +257 -0
  202. package/src/serializer/JsonSerializer.ts +173 -0
  203. package/src/serializer/RestSerializer.ts +138 -0
  204. package/src/serializer/Serializer.ts +397 -0
  205. package/src/serializer/index.ts +15 -0
  206. package/src/store/IdentityMap.ts +110 -0
  207. package/src/store/RecordArray.ts +210 -0
  208. package/src/store/Store.ts +1391 -0
  209. package/src/store/index.ts +11 -0
  210. package/src/transforms/Transform.ts +52 -0
  211. package/src/transforms/boolean.ts +57 -0
  212. package/src/transforms/date.ts +48 -0
  213. package/src/transforms/index.ts +5 -0
  214. package/src/transforms/number.ts +42 -0
  215. package/src/transforms/string.ts +35 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Store-CZ7Z-Nme.js","sources":["../src/store/IdentityMap.ts","../src/store/RecordArray.ts","../src/store/Store.ts"],"sourcesContent":["/**\n * Two-level observable map that serves as the store's record cache.\n *\n * Records are stored in per-type buckets:\n * ```\n * buckets: Map<modelName, Map<id, Model>>\n * ```\n *\n * The outer map is MobX-observable (shallow) so derived views like `peekAll`\n * react when new type buckets are added. Each inner bucket is an observable\n * map so computed properties that iterate records within a type react to\n * additions and deletions.\n *\n * All mutating methods (`set`, `delete`, `clear`) are MobX `action`s so they\n * batch observable updates correctly.\n */\n\nimport { makeObservable, observable, action } from 'mobx';\nimport type { Model } from '@mobx-data/model';\n\nexport class IdentityMap {\n /** @internal */\n readonly _buckets: Map<string, Map<string, Model>> = new Map();\n\n constructor() {\n makeObservable<this, '_buckets'>(this, {\n _buckets: observable.shallow,\n set: action,\n delete: action,\n clear: action,\n });\n }\n\n /**\n * Returns the bucket for `modelName`, optionally creating it when absent.\n * Internal helper — not part of the public API.\n */\n private bucket(modelName: string, create = false): Map<string, Model> | undefined {\n let existing = this._buckets.get(modelName);\n if (!existing && create) {\n existing = observable.map<string, Model>({}, { deep: false });\n this._buckets.set(modelName, existing);\n }\n return existing;\n }\n\n /** Adds or replaces the record with the given `id` under `modelName`. */\n set(modelName: string, id: string, record: Model): void {\n const bucket = this.bucket(modelName, true)!;\n bucket.set(id, record);\n }\n\n /**\n * Returns the record for `modelName` + `id`, or `null` when not found.\n */\n get(modelName: string, id: string): Model | null {\n return this.bucket(modelName)?.get(id) ?? null;\n }\n\n /** Returns `true` when a record exists for `modelName` + `id`. */\n has(modelName: string, id: string): boolean {\n return this.bucket(modelName)?.has(id) ?? false;\n }\n\n /**\n * Removes the record for `modelName` + `id`.\n * @returns `true` when the record existed and was deleted.\n */\n delete(modelName: string, id: string): boolean {\n return this.bucket(modelName)?.delete(id) ?? false;\n }\n\n /** Returns all records stored under `modelName` as an array. */\n all(modelName: string): Model[] {\n const bucket = this.bucket(modelName);\n if (!bucket) {\n return [];\n }\n return Array.from(bucket.values());\n }\n\n /**\n * Clears all records for `modelName`, or all records across all types when\n * `modelName` is omitted.\n */\n clear(modelName?: string): void {\n if (modelName) {\n this.bucket(modelName)?.clear();\n } else {\n for (const bucket of this._buckets.values()) {\n bucket.clear();\n }\n }\n }\n\n /**\n * Returns the number of records stored for `modelName`, or the total across\n * all types when `modelName` is omitted.\n */\n size(modelName?: string): number {\n if (modelName) {\n return this.bucket(modelName)?.size ?? 0;\n }\n let total = 0;\n for (const bucket of this._buckets.values()) {\n total += bucket.size;\n }\n return total;\n }\n}\n","/**\n * Observable array proxies for store query results.\n *\n * Two classes are provided:\n *\n * ## `RecordArray<T>`\n * A live, read-only view of all records of a given type in the store's\n * identity map. The contents are derived via an injected `source` function\n * so they stay in sync automatically with the identity map.\n *\n * Supports `update()` to trigger a background re-fetch if an `update` callback\n * is provided.\n *\n * ## `AdapterPopulatedRecordArray<T>`\n * A subclass used for the results of `store.query()`. Unlike `RecordArray`,\n * its contents are determined by the last adapter response (order preserved,\n * no auto-sync with new pushes).\n *\n * Adds `meta`, `links`, and `query` properties that are set by the store after\n * each adapter call.\n */\n\nimport { makeObservable, computed, observable } from 'mobx';\nimport type { Model } from '@mobx-data/model';\n\n/** Constructor options for `RecordArray`. */\nexport interface RecordArrayOptions<T extends Model> {\n /** Registered model name. */\n modelName: string;\n /** Function that returns the current record list (called on each access). */\n source: () => T[];\n /** Optional async callback invoked by `update()`. */\n update?: () => Promise<void>;\n /**\n * When `true`, the internal MobX computed retains its cached value even when\n * no observers are actively subscribed. Prevents expensive recomputation\n * for long-lived filtered views (e.g. `liveQuery` results).\n */\n keepAlive?: boolean;\n}\n\n/**\n * Live, read-only view of all records of a given type.\n *\n * The `source` function is called on each observable access so the array\n * always reflects the current store state. MobX tracks the `source` call\n * as part of `resolved`, so any computed prop that reads from this array\n * will re-run when the underlying identity map changes.\n */\nexport class RecordArray<T extends Model = Model> implements Iterable<T> {\n private readonly opts: RecordArrayOptions<T>;\n\n /** `true` while `update()` is in progress. */\n protected updating: boolean = false;\n\n constructor(opts: RecordArrayOptions<T>) {\n this.opts = opts;\n makeObservable<this, 'resolved' | 'updating'>(this, {\n resolved: opts.keepAlive ? computed({ keepAlive: true }) : computed,\n updating: observable,\n length: computed,\n modelName: computed,\n });\n }\n\n /** Current record list, derived from the injected `source` function. */\n protected get resolved(): T[] {\n return this.opts.source();\n }\n\n /** `true` while a background `update()` call is in progress. */\n get isLoading(): boolean {\n return this.updating;\n }\n\n /** Alias for `isLoading`. */\n get isUpdating(): boolean {\n return this.updating;\n }\n\n /** Number of records in the array. */\n get length(): number {\n return this.resolved.length;\n }\n\n /** The registered model name for the records in this array. */\n get modelName(): string {\n return this.opts.modelName;\n }\n\n /** Returns the record at `index`, or `undefined`. */\n at(index: number): T | undefined {\n return this.resolved[index];\n }\n\n /** Returns a plain array snapshot of all records. */\n toArray(): T[] {\n return [...this.resolved];\n }\n\n /** Maps over records. */\n map<R>(callback: (record: T, i: number) => R): R[] {\n return this.resolved.map(callback);\n }\n\n /** Filters records. */\n filter(predicate: (record: T, i: number) => boolean): T[] {\n return this.resolved.filter(predicate);\n }\n\n /** Iterates records. */\n forEach(callback: (record: T, i: number) => void): void {\n this.resolved.forEach(callback);\n }\n\n /** Returns `true` when `record` is in the array. */\n includes(record: T): boolean {\n return this.resolved.includes(record);\n }\n\n /**\n * Triggers the `update` callback (if any) to refresh the array from the\n * adapter. Sets `isLoading` while the request is in flight.\n */\n async update(): Promise<this> {\n if (!this.opts.update) {\n return this;\n }\n this.updating = true;\n try {\n await this.opts.update();\n } finally {\n this.updating = false;\n }\n return this;\n }\n\n [Symbol.iterator](): Iterator<T> {\n return this.resolved[Symbol.iterator]();\n }\n}\n\n/** Constructor options for `AdapterPopulatedRecordArray`. */\nexport interface AdapterPopulatedRecordArrayOptions<T extends Model>\n extends RecordArrayOptions<T> {\n /** Query parameters that produced this result set. */\n query: Record<string, unknown>;\n /** Server-side metadata (pagination, total counts, etc.). */\n meta?: Record<string, unknown>;\n /** Pagination or related links. */\n links?: Record<string, string>;\n}\n\n/**\n * Record array populated by an adapter query response.\n *\n * The store creates one of these for each `store.query()` call. Its contents\n * are driven by the id list returned from the last adapter call, not by live\n * identity map iteration.\n *\n * Call `.update()` to re-issue the original query and refresh the contents.\n */\nexport class AdapterPopulatedRecordArray<\n T extends Model = Model,\n> extends RecordArray<T> {\n private queryParams: Record<string, unknown>;\n\n private metaData: Record<string, unknown>;\n\n private linksData: Record<string, string>;\n\n constructor(opts: AdapterPopulatedRecordArrayOptions<T>) {\n super(opts);\n this.queryParams = opts.query;\n this.metaData = opts.meta ?? {};\n this.linksData = opts.links ?? {};\n makeObservable<this, 'metaData' | 'linksData'>(this, {\n metaData: observable.ref,\n linksData: observable.ref,\n meta: computed,\n links: computed,\n query: computed,\n });\n }\n\n /** Server-side metadata attached to the last response (e.g. pagination). */\n get meta(): Record<string, unknown> {\n return this.metaData;\n }\n\n /** Links attached to the last response. */\n get links(): Record<string, string> {\n return this.linksData;\n }\n\n /** The query parameters that produced this array. */\n get query(): Record<string, unknown> {\n return this.queryParams;\n }\n\n /** Called by the store to update `meta` after a successful query. */\n _setMeta(meta: Record<string, unknown>): void {\n this.metaData = meta;\n }\n\n /** Called by the store to update `links` after a successful query. */\n _setLinks(links: Record<string, string>): void {\n this.linksData = links;\n }\n}\n","/**\n * Central store — the top-level coordinator for the mobx-data runtime.\n *\n * `Store` orchestrates every aspect of the data layer:\n *\n * - **Identity Map** — a two-level `IdentityMap` keyed by `modelName → id`.\n * Records are merged in-place on repeated `push` calls so live references\n * always reflect the latest server state.\n *\n * - **Finding records** — `findRecord`, `findAll`, `query`, `queryRecord`\n * delegate to the registered adapter, then pass the raw response through the\n * registered serializer before pushing normalized data into the identity map.\n *\n * - **Saving records** — `saveRecord` calls `adapter.createRecord` or\n * `adapter.updateRecord` depending on `record.isNew`, then applies the\n * server response back onto the record via `_applyServerData`.\n *\n * - **Relationships** — `resolveRelationship` returns sync (`ManyArray`) or\n * async (`AsyncBelongsTo` / `AsyncHasMany`) proxy objects backed by the\n * store. `setRelationshipValue` updates `belongsTo` refs and keeps their\n * inverses in sync. `_hasManyAppend` / `_hasManyRemove` manage `hasMany`\n * refs and their inverses.\n *\n * - **Inverse tracking** — `addInverse` / `removeInverse` keep both sides of\n * a declared `inverse` relationship consistent when either side is mutated.\n *\n * ## Registration\n *\n * ```ts\n * store.registerAdapter('application', new RestAdapter());\n * store.registerSerializer('application', new JsonSerializer());\n * ```\n *\n * Adapters and serializers are looked up first by exact model name, then by\n * the special `'application'` fallback.\n */\n\nimport {\n singleton, inject, injectable,\n} from 'tsyringe';\nimport { runInAction, observable, computed, makeObservable } from 'mobx';\nimport {\n SchemaService,\n type RelationshipDef,\n type AttributeDef,\n} from '@mobx-data/schema';\nimport {\n Model,\n ManyArray,\n AsyncBelongsTo,\n AsyncHasMany,\n type RelationshipRef,\n type ModelStoreLike,\n type SaveOptions,\n} from '@mobx-data/model';\nimport { IdentityMap } from './IdentityMap.js';\nimport {\n RecordArray,\n AdapterPopulatedRecordArray,\n} from './RecordArray.js';\n\n/** Options forwarded from the Store to adapter fetch methods. */\nexport interface AdapterFetchOptions {\n include?: string;\n adapterOptions?: Record<string, unknown>;\n}\n\n/** Minimal adapter interface the Store depends on. */\nexport interface AdapterLike {\n findRecord(\n store: Store,\n modelName: string,\n id: string,\n snapshot: unknown,\n options?: AdapterFetchOptions,\n ): Promise<unknown>;\n findAll(\n store: Store,\n modelName: string,\n sinceToken: string | null,\n snapshotArray: unknown,\n options?: AdapterFetchOptions,\n ): Promise<unknown>;\n findMany?(\n store: Store,\n modelName: string,\n ids: string[],\n snapshots: unknown,\n ): Promise<unknown>;\n query(\n store: Store,\n modelName: string,\n query: Record<string, unknown>,\n recordArray: AdapterPopulatedRecordArray,\n ): Promise<unknown>;\n queryRecord(\n store: Store,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown>;\n createRecord(\n store: Store,\n modelName: string,\n snapshot: unknown,\n ): Promise<unknown>;\n updateRecord(\n store: Store,\n modelName: string,\n snapshot: unknown,\n ): Promise<unknown>;\n patchRecord?(\n store: Store,\n modelName: string,\n snapshot: unknown,\n ): Promise<unknown>;\n deleteRecord(\n store: Store,\n modelName: string,\n snapshot: unknown,\n ): Promise<unknown>;\n /** When `true` the store coalesces multiple `findRecord` calls into one `findMany`. */\n coalesceFindRequests?: boolean;\n}\n\n/** Minimal serializer interface the Store depends on. */\nexport interface SerializerLike {\n normalize(\n store: Store,\n modelClass: unknown,\n payload: unknown,\n prop?: string,\n ): unknown;\n normalizeResponse(\n store: Store,\n modelClass: unknown,\n payload: unknown,\n id: string | null,\n requestType: string,\n ): unknown;\n serialize(snapshot: unknown, options?: Record<string, unknown>): unknown;\n extractErrors?(\n store: Store,\n modelClass: unknown,\n payload: unknown,\n id: string | null,\n ): Record<string, string[]>;\n}\n\n/** Options for `findRecord` and `findAll`. */\nexport interface FindOptions {\n /** When `true`, bypass the cache and always hit the network. */\n reload?: boolean;\n /** When `true`, return the cached value and refetch in the background. */\n backgroundReload?: boolean;\n /** Adapter-specific options forwarded to the adapter method. */\n adapterOptions?: Record<string, unknown>;\n /** Comma-separated relationship paths to include (e.g. `'author,comments'`). */\n include?: string;\n}\n\n/** Normalized resource shape consumed internally by the store. */\nexport interface NormalizedResource {\n type: string;\n id: string | null;\n attributes?: Record<string, unknown>;\n relationships?: Record<string, RelationshipRef>;\n}\n\n/** Normalized document containing primary data and optional side-loaded records. */\nexport interface NormalizedDocument {\n data: NormalizedResource | NormalizedResource[] | null;\n included?: NormalizedResource[];\n meta?: Record<string, unknown>;\n links?: Record<string, string>;\n}\n\n/** Internal snapshot interface created and consumed by the store. */\ninterface Snapshot {\n id: string | null;\n modelName: string;\n record: Model;\n attr(key: string): unknown;\n belongsTo(key: string, options?: { id?: boolean }): unknown;\n hasMany(key: string, options?: { ids?: boolean }): unknown;\n changedAttributes(): Record<string, [unknown, unknown]>;\n eachAttribute(fn: (key: string, meta: AttributeDef) => void): void;\n eachRelationship(fn: (key: string, meta: RelationshipDef) => void): void;\n}\n\n@singleton()\n@injectable()\nexport class Store implements ModelStoreLike {\n static refEquals(\n a: { type: string; id: string },\n b: { type: string; id: string },\n ): boolean {\n return a.id === b.id && a.type === b.type;\n }\n\n /** Schema registry used to look up model classes and their metadata. */\n readonly schema: SchemaService;\n\n /** Two-level identity map: `modelName → id → record`. */\n readonly identityMap: IdentityMap = new IdentityMap();\n\n private adapters: Map<string, AdapterLike> = new Map();\n\n private serializers: Map<string, SerializerLike> = new Map();\n\n /** Tracks unsaved (new) records by model name. */\n private newRecords: Map<string, Set<Model>> = new Map();\n\n /** Reverse index: record → modelName for O(1) untrackNewRecord. */\n private newRecordTypes: WeakMap<Model, string> = new WeakMap();\n\n /** Per-record cache of relationship proxy objects (ManyArray / AsyncBelongsTo / AsyncHasMany). */\n private relationshipCache: WeakMap<\n Model,\n Map<string, ManyArray | AsyncBelongsTo | AsyncHasMany>\n > = new WeakMap();\n\n /** Tracks new records that have been appended to a hasMany but not yet saved. */\n private pendingMembers: WeakMap<Model, Map<string, Set<Model>>> = new WeakMap();\n\n constructor(@inject(SchemaService) schema: SchemaService) {\n this.schema = schema;\n }\n\n // --- registration ---\n\n /** Registers an adapter for a given model name (or `'application'` as a fallback). */\n registerAdapter(modelName: string, adapter: AdapterLike): void {\n this.adapters.set(modelName, adapter);\n }\n\n /** Registers a serializer for a given model name (or `'application'` as a fallback). */\n registerSerializer(modelName: string, serializer: SerializerLike): void {\n this.serializers.set(modelName, serializer);\n }\n\n /**\n * Returns the adapter for `modelName`, falling back to `'application'`.\n * @throws when no adapter is registered.\n */\n adapterFor(modelName: string): AdapterLike {\n const adapter = this.adapters.get(modelName) ?? this.adapters.get('application');\n if (!adapter) {\n throw new Error(`No adapter registered for \"${modelName}\"`);\n }\n return adapter;\n }\n\n /**\n * Returns the serializer for `modelName`, falling back to `'application'`.\n * @throws when no serializer is registered.\n */\n serializerFor(modelName: string): SerializerLike {\n const serializer = this.serializers.get(modelName)\n ?? this.serializers.get('application');\n if (!serializer) {\n throw new Error(`No serializer registered for \"${modelName}\"`);\n }\n return serializer;\n }\n\n // --- creating ---\n\n /**\n * Creates a new (unsaved) record of the given type with optional initial data.\n * The record is tracked in `newRecords` until it is saved or rolled back.\n *\n * @throws when `modelName` has not been registered with `SchemaService`.\n */\n createRecord<T extends Model = Model>(\n modelName: string,\n data: Record<string, unknown> = {},\n ): T {\n if (!this.schema.doesTypeExist(modelName)) {\n throw new Error(`Unknown model type: \"${modelName}\"`);\n }\n const Klass = this.schema.modelFor(modelName) as unknown as new (\n opts: { id: null; data: Record<string, unknown>; store: Store },\n ) => Model;\n const record = new Klass({ id: null, data, store: this });\n this.trackNewRecord(modelName, record);\n return record as T;\n }\n\n private trackNewRecord(modelName: string, record: Model): void {\n let set = this.newRecords.get(modelName);\n if (!set) {\n set = new Set();\n this.newRecords.set(modelName, set);\n }\n set.add(record);\n this.newRecordTypes.set(record, modelName);\n }\n\n private untrackNewRecord(record: Model): void {\n const modelName = this.newRecordTypes.get(record);\n if (modelName) {\n this.newRecords.get(modelName)?.delete(record);\n this.newRecordTypes.delete(record);\n }\n }\n\n // --- peeking ---\n\n /**\n * Synchronously returns a record from the identity map, or `null` when not\n * found. Does not trigger a network request.\n */\n peekRecord<T extends Model = Model>(modelName: string, id: string): T | null {\n const key = id === null || id === undefined ? null : String(id);\n if (key === null) {\n return null;\n }\n return (this.identityMap.get(modelName, key) as T | null) ?? null;\n }\n\n /**\n * Returns a live `RecordArray` backed by the identity map for `modelName`.\n * New (unsaved) records are included at the end.\n * Does not trigger a network request.\n */\n peekAll<T extends Model = Model>(modelName: string): RecordArray<T> {\n return new RecordArray<T>({\n modelName,\n source: () => {\n const persisted = this.identityMap.all(modelName) as T[];\n const newRecordsForType = this.newRecords.get(modelName);\n if (!newRecordsForType || newRecordsForType.size === 0) {\n return persisted;\n }\n return [...persisted, ...(newRecordsForType as unknown as Set<T>)];\n },\n });\n }\n\n // --- push / normalize ---\n\n /**\n * Pushes a normalized document into the identity map.\n * Side-loaded (`included`) records are pushed first.\n *\n * @returns The primary record(s), or `null` for empty payloads.\n */\n push(doc: unknown): Model | Model[] | null {\n const document = doc as NormalizedDocument;\n if (document.included) {\n for (const resource of document.included) {\n this.pushResource(resource);\n }\n }\n if (document.data === null || document.data === undefined) {\n return null;\n }\n if (Array.isArray(document.data)) {\n return document.data.map((resource) => this.pushResource(resource));\n }\n return this.pushResource(document.data);\n }\n\n /**\n * Normalizes a raw payload via the registered serializer and pushes the\n * result. `modelName` is optional; when omitted the payload is pushed\n * directly without normalization.\n */\n pushPayload(modelNameOrPayload: string | unknown, payload?: unknown): void {\n let modelName: string | null;\n let body: unknown;\n if (typeof modelNameOrPayload === 'string') {\n modelName = modelNameOrPayload;\n body = payload;\n } else {\n modelName = null;\n body = modelNameOrPayload;\n }\n const normalized = modelName\n ? this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n body,\n null,\n 'pushPayload',\n )\n : body;\n this.push(normalized);\n }\n\n /**\n * Normalizes a raw payload for `modelName` via the registered serializer\n * and returns the `NormalizedDocument` without pushing it.\n */\n normalize(modelName: string, payload: unknown): NormalizedDocument {\n return this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n payload,\n null,\n 'normalize',\n ) as NormalizedDocument;\n }\n\n /**\n * Inserts or merges a single normalized resource into the identity map.\n * - Existing record → calls `_applyServerData` to merge attributes and\n * relationships in place (preserving the live reference).\n * - New record → instantiates via `Model.push` and sets it in the map.\n *\n * @throws when `type` has not been registered or `id` is `null`.\n */\n private pushResource(resource: NormalizedResource): Model {\n const { type, id } = resource;\n if (!this.schema.doesTypeExist(type)) {\n throw new Error(`Unknown model type: \"${type}\"`);\n }\n if (id === null) {\n throw new Error(`Cannot push a resource of type \"${type}\" without an id`);\n }\n const existing = this.identityMap.get(type, id);\n if (existing) {\n runInAction(() => {\n (existing as unknown as {\n _applyServerData(\n id: string | null,\n data: Record<string, unknown>,\n relationships?: Record<string, RelationshipRef>,\n ): void;\n })._applyServerData(null, resource.attributes ?? {}, resource.relationships);\n });\n this.trackInverseForResource(existing, resource);\n return existing;\n }\n const Klass = this.schema.modelFor(type) as unknown as new (\n opts: {\n id: string;\n data: Record<string, unknown>;\n relationships?: Record<string, RelationshipRef>;\n store: Store;\n },\n ) => Model;\n const record = Model.push.call(Klass as unknown as typeof Model, {\n id,\n data: resource.attributes ?? {},\n relationships: resource.relationships,\n store: this,\n }) as Model;\n this.identityMap.set(type, id, record);\n this.trackInverseForResource(record, resource);\n return record;\n }\n\n /**\n * After pushing a resource, updates the inverse side of every declared\n * inverse relationship so both sides stay consistent.\n */\n private trackInverseForResource(record: Model, resource: NormalizedResource): void {\n if (!resource.relationships) {\n return;\n }\n for (const [name, ref] of Object.entries(resource.relationships)) {\n const meta = this.schema.relationshipsDefinitionFor(record.modelName).get(name);\n if (!meta) {\n continue;\n }\n if (!meta.options.inverse) {\n continue;\n }\n if (!ref.data) {\n continue;\n }\n const items = Array.isArray(ref.data) ? ref.data : [ref.data];\n for (const item of items) {\n this.addInverse(item.type, item.id, meta.options.inverse, record);\n }\n }\n }\n\n /**\n * Adds `inverseRecord` to the inverse relationship on `targetType:targetId`.\n * No-ops when the target record is not in the identity map.\n */\n private addInverse(\n targetType: string,\n targetId: string,\n inverseName: string,\n inverseRecord: Model,\n ): void {\n const target = this.identityMap.get(targetType, targetId);\n if (!target) {\n return;\n }\n const targetRelationships = this.schema.relationshipsDefinitionFor(targetType);\n const inverseMeta = targetRelationships.get(inverseName);\n if (!inverseMeta) {\n return;\n }\n const existing = (target as unknown as {\n _getRelationshipRef(name: string): RelationshipRef | null;\n })._getRelationshipRef(inverseName);\n const inverseEntry = { type: inverseRecord.modelName, id: inverseRecord.id! };\n runInAction(() => {\n if (inverseMeta.kind === 'hasMany') {\n const currentData = existing?.data && Array.isArray(existing.data)\n ? existing.data : [];\n if (!currentData.some((reference) => Store.refEquals(reference, inverseEntry))) {\n (target as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(inverseName, { data: [...currentData, inverseEntry] });\n }\n } else {\n (target as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(inverseName, { data: inverseEntry });\n }\n });\n }\n\n /**\n * Removes `inverseRecord` from the inverse relationship on `targetType:targetId`.\n * No-ops when the target record is not in the identity map.\n */\n private removeInverse(\n targetType: string,\n targetId: string,\n inverseName: string,\n inverseRecord: Model,\n ): void {\n const target = this.identityMap.get(targetType, targetId);\n if (!target) {\n return;\n }\n const targetRelationships = this.schema.relationshipsDefinitionFor(targetType);\n const inverseMeta = targetRelationships.get(inverseName);\n if (!inverseMeta) {\n return;\n }\n const existing = (target as unknown as {\n _getRelationshipRef(name: string): RelationshipRef | null;\n })._getRelationshipRef(inverseName);\n runInAction(() => {\n if (inverseMeta.kind === 'hasMany') {\n const currentData = existing?.data && Array.isArray(existing.data)\n ? existing.data : [];\n const items = currentData.filter((reference) => !(\n reference.id === inverseRecord.id\n && reference.type === inverseRecord.modelName\n ));\n (target as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(inverseName, { data: items });\n } else {\n (target as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(inverseName, { data: null });\n }\n });\n }\n\n // --- unload ---\n\n /**\n * Removes a record from the identity map and clears its relationship cache.\n * Called by `record.unloadRecord()` and internally after `deleteRecord`.\n */\n unloadRecord(record: Model): void {\n if (record.id !== null) {\n this.identityMap.delete(record.modelName, record.id);\n }\n this.untrackNewRecord(record);\n this.relationshipCache.delete(record);\n }\n\n /**\n * Unloads all records for `modelName`, or all records across all types when\n * `modelName` is omitted.\n */\n unloadAll(modelName?: string): void {\n if (modelName) {\n for (const record of this.identityMap.all(modelName)) {\n this.relationshipCache.delete(record);\n }\n this.identityMap.clear(modelName);\n this.newRecords.get(modelName)?.clear();\n } else {\n this.identityMap.clear();\n this.newRecords.clear();\n }\n }\n\n // --- find ---\n\n /**\n * Finds a single record by id. Returns the cached record immediately when\n * `options.reload` is not set; otherwise re-fetches.\n *\n * When the adapter has `coalesceFindRequests: true` and `findMany` is\n * implemented, multiple concurrent `findRecord` calls for the same type\n * are batched into a single `findMany` network request.\n */\n async findRecord<T extends Model = Model>(\n modelName: string,\n id: string,\n options: FindOptions = {},\n ): Promise<T> {\n const cached = this.peekRecord<T>(modelName, id);\n if (cached && !options.reload && !options.include) {\n return cached;\n }\n const adapter = this.adapterFor(modelName);\n\n if (adapter.coalesceFindRequests && adapter.findMany && !options.include) {\n return this.scheduleCoalescedFind(modelName, id) as Promise<T>;\n }\n\n const snapshot = cached ? this.createSnapshot(cached) : this.createEmptySnapshot(modelName, id);\n const adapterOptions: AdapterFetchOptions | undefined = options.include\n ? { include: options.include, adapterOptions: options.adapterOptions }\n : options.adapterOptions ? { adapterOptions: options.adapterOptions } : undefined;\n const response = await adapter.findRecord(this, modelName, id, snapshot, adapterOptions);\n const doc = this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n response,\n id,\n 'findRecord',\n ) as NormalizedDocument;\n const record = this.push(doc);\n return record as T;\n }\n\n /**\n * Fetches all records of `modelName` from the server and returns a\n * `RecordArray` backed by the identity map.\n */\n async findAll<T extends Model = Model>(\n modelName: string,\n options: FindOptions = {},\n ): Promise<RecordArray<T>> {\n const adapter = this.adapterFor(modelName);\n const adapterOptions: AdapterFetchOptions | undefined = options.include\n ? { include: options.include, adapterOptions: options.adapterOptions }\n : options.adapterOptions ? { adapterOptions: options.adapterOptions } : undefined;\n const response = await adapter.findAll(this, modelName, null, [], adapterOptions);\n const doc = this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n response,\n null,\n 'findAll',\n ) as NormalizedDocument;\n this.push(doc);\n return this.peekAll<T>(modelName);\n }\n\n /**\n * Executes an adapter query and returns an `AdapterPopulatedRecordArray`\n * whose `update()` method re-issues the same query.\n */\n async query<T extends Model = Model>(\n modelName: string,\n params: Record<string, unknown>,\n ): Promise<AdapterPopulatedRecordArray<T>> {\n const ids: string[] = [];\n const array = new AdapterPopulatedRecordArray<T>({\n modelName,\n query: params,\n source: () => ids\n .map((id) => this.peekRecord<T>(modelName, id))\n .filter((r): r is T => r !== null),\n update: async () => {\n await this.runQuery(modelName, params, array, ids);\n },\n });\n await this.runQuery(modelName, params, array, ids);\n return array;\n }\n\n private async runQuery<T extends Model>(\n modelName: string,\n params: Record<string, unknown>,\n array: AdapterPopulatedRecordArray<T>,\n ids: string[],\n ): Promise<void> {\n const adapter = this.adapterFor(modelName);\n const response = await adapter.query(this, modelName, params, array);\n const doc = this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n response,\n null,\n 'query',\n ) as NormalizedDocument;\n this.push(doc);\n ids.length = 0;\n if (Array.isArray(doc.data)) {\n for (const resource of doc.data) {\n if (resource.id) {\n ids.push(resource.id);\n }\n }\n }\n if (doc.meta) {\n array._setMeta(doc.meta);\n }\n if (doc.links) {\n array._setLinks(doc.links);\n }\n }\n\n /**\n * Executes an adapter query that returns at most one record.\n * Returns `null` when the adapter returns an empty payload.\n */\n async queryRecord<T extends Model = Model>(\n modelName: string,\n params: Record<string, unknown>,\n ): Promise<T | null> {\n const adapter = this.adapterFor(modelName);\n const response = await adapter.queryRecord(this, modelName, params);\n const doc = this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n response,\n null,\n 'queryRecord',\n ) as NormalizedDocument;\n const result = this.push(doc);\n if (Array.isArray(result)) {\n return (result[0] ?? null) as T | null;\n }\n return (result as T | null) ?? null;\n }\n\n // --- save / delete / reload from Model ---\n\n /**\n * Persists a record to the server.\n * - New records → `adapter.createRecord` (POST)\n * - Existing dirty records → `adapter.updateRecord` (PUT) by default\n * - With `{ patch: true }` → `adapter.patchRecord` (PATCH, partial payload)\n *\n * After the response is received the server data is applied back to the\n * record via `_applyServerData` so it transitions to `saved`.\n */\n async saveRecord<T extends Model>(record: T, options: SaveOptions = {}): Promise<T> {\n const adapter = this.adapterFor(record.modelName);\n const snapshot = this.createSnapshot(record);\n const { isNew } = record;\n let response: unknown;\n if (isNew) {\n response = await adapter.createRecord(this, record.modelName, snapshot);\n } else if (options.patch && adapter.patchRecord) {\n response = await adapter.patchRecord(this, record.modelName, snapshot);\n } else {\n response = await adapter.updateRecord(this, record.modelName, snapshot);\n }\n const doc = this.serializerFor(record.modelName).normalizeResponse(\n this,\n this.schema.modelFor(record.modelName),\n response,\n record.id,\n isNew ? 'createRecord' : 'updateRecord',\n ) as NormalizedDocument;\n const data = doc.data as NormalizedResource | null;\n if (data) {\n const newId = data.id ?? record.id;\n runInAction(() => {\n (record as unknown as {\n _applyServerData(\n id: string | null,\n data: Record<string, unknown>,\n relationships?: Record<string, RelationshipRef>,\n ): void;\n })._applyServerData(newId, data.attributes ?? {}, data.relationships);\n });\n if (isNew && newId) {\n this.untrackNewRecord(record);\n this.identityMap.set(record.modelName, newId, record);\n }\n }\n if (doc.included) {\n for (const resource of doc.included) {\n this.pushResource(resource);\n }\n }\n return record;\n }\n\n /**\n * Issues a DELETE request and unloads the record from the identity map.\n */\n async deleteRecord<T extends Model>(record: T): Promise<T> {\n const adapter = this.adapterFor(record.modelName);\n const snapshot = this.createSnapshot(record);\n await adapter.deleteRecord(this, record.modelName, snapshot);\n this.unloadRecord(record);\n return record;\n }\n\n /**\n * Re-fetches a record from the server and merges the response into the\n * existing instance.\n */\n async reloadRecord<T extends Model>(record: T): Promise<T> {\n if (!record.id) {\n throw new Error('Cannot reload a record without an id');\n }\n const adapter = this.adapterFor(record.modelName);\n const snapshot = this.createSnapshot(record);\n const response = await adapter.findRecord(this, record.modelName, record.id, snapshot);\n const doc = this.serializerFor(record.modelName).normalizeResponse(\n this,\n this.schema.modelFor(record.modelName),\n response,\n record.id,\n 'findRecord',\n ) as NormalizedDocument;\n this.push(doc);\n return record;\n }\n\n // --- snapshot ---\n\n /**\n * Creates a `Snapshot` for a live record.\n * The snapshot reads directly from the record's internal state so it\n * reflects the current (possibly dirty) values.\n */\n createSnapshot(record: Model): Snapshot {\n const { modelName } = record;\n const attributes = this.schema.attributesDefinitionFor(modelName);\n const relationships = this.schema.relationshipsDefinitionFor(modelName);\n const internal = record as unknown as {\n _data: Record<string, unknown>;\n _getRelationshipRef(name: string): RelationshipRef | null;\n changedAttributes(): Record<string, [unknown, unknown]>;\n };\n return {\n id: record.id,\n modelName,\n record,\n attr: (key) => internal._data[key],\n belongsTo: (key, options) => {\n const ref = internal._getRelationshipRef(key);\n if (!ref?.data || Array.isArray(ref.data)) {\n return null;\n }\n if (options?.id) {\n return ref.data.id;\n }\n return this.peekRecord(ref.data.type, ref.data.id);\n },\n hasMany: (key, options) => {\n const ref = internal._getRelationshipRef(key);\n const items: Array<{ type: string; id: string }> = ref?.data\n && Array.isArray(ref.data) ? ref.data : [];\n if (options?.ids) {\n return items.map((item) => item.id);\n }\n return items\n .map((item) => this.peekRecord(item.type, item.id))\n .filter((resolvedRecord): resolvedRecord is Model => resolvedRecord !== null);\n },\n changedAttributes: () => internal.changedAttributes(),\n eachAttribute: (callback) => {\n for (const [key, meta] of attributes) {\n callback(key, meta);\n }\n },\n eachRelationship: (callback) => {\n for (const [key, meta] of relationships) {\n callback(key, meta);\n }\n },\n };\n }\n\n /**\n * Creates a placeholder `Snapshot` for a record that is not yet in the\n * identity map (used when fetching a record that isn't cached).\n */\n private createEmptySnapshot(modelName: string, id: string): Snapshot {\n const attributes = this.schema.attributesDefinitionFor(modelName);\n const relationships = this.schema.relationshipsDefinitionFor(modelName);\n return {\n id,\n modelName,\n record: null as unknown as Model,\n attr: () => undefined,\n belongsTo: () => null,\n hasMany: () => [],\n changedAttributes: () => ({}),\n eachAttribute: (callback) => {\n for (const [key, meta] of attributes) {\n callback(key, meta);\n }\n },\n eachRelationship: (callback) => {\n for (const [key, meta] of relationships) {\n callback(key, meta);\n }\n },\n };\n }\n\n // --- relationship resolution (called by Model) ---\n\n private getRelationshipCache(\n record: Model,\n name: string,\n ): ManyArray | AsyncBelongsTo | AsyncHasMany | undefined {\n return this.relationshipCache.get(record)?.get(name);\n }\n\n private setRelationshipCache(\n record: Model,\n name: string,\n value: ManyArray | AsyncBelongsTo | AsyncHasMany,\n ): void {\n let m = this.relationshipCache.get(record);\n if (!m) {\n m = new Map();\n this.relationshipCache.set(record, m);\n }\n m.set(name, value);\n }\n\n /**\n * Called by the `Model` relationship getter to resolve a relationship.\n *\n * - **Async** `belongsTo` → returns an `AsyncBelongsTo` wrapper.\n * - **Async** `hasMany` → returns an `AsyncHasMany` wrapper.\n * - **Sync** `belongsTo` → peeks the related record from the identity map.\n * - **Sync** `hasMany` → returns a `ManyArray` backed by the store.\n *\n * Results are cached per record + name so the same proxy is returned on\n * repeated accesses (important for MobX observability).\n */\n resolveRelationship(record: Model, name: string, meta: RelationshipDef): unknown {\n const isAsync = meta.options.async === true;\n const cached = this.getRelationshipCache(record, name);\n if (cached) {\n return cached;\n }\n const hostWithStore = {\n parent: record,\n name,\n meta,\n store: this as unknown as never,\n };\n\n if (isAsync) {\n if (meta.kind === 'belongsTo') {\n const wrapper = new AsyncBelongsTo(hostWithStore as never);\n this.setRelationshipCache(record, name, wrapper);\n return wrapper;\n }\n const wrapper = new AsyncHasMany(hostWithStore as never);\n this.setRelationshipCache(record, name, wrapper);\n return wrapper;\n }\n\n if (meta.kind === 'belongsTo') {\n const ref = (record as unknown as {\n _getRelationshipRef(name: string): RelationshipRef | null;\n })._getRelationshipRef(name);\n if (!ref?.data || Array.isArray(ref.data)) {\n return null;\n }\n return this.peekRecord(ref.data.type, ref.data.id);\n }\n const arr = new ManyArray(hostWithStore as never);\n this.setRelationshipCache(record, name, arr);\n return arr;\n }\n\n /**\n * Called by the `Model` `belongsTo` setter to update a relationship ref\n * and keep its inverse in sync.\n */\n setRelationshipValue(\n record: Model,\n name: string,\n meta: RelationshipDef,\n value: unknown,\n ): void {\n if (meta.kind !== 'belongsTo') {\n return;\n }\n const ref = (record as unknown as {\n _getRelationshipRef(name: string): RelationshipRef | null;\n })._getRelationshipRef(name);\n const prev = ref?.data && !Array.isArray(ref.data) ? ref.data : null;\n\n if (value === null || value === undefined) {\n runInAction(() => {\n (record as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(name, { data: null });\n });\n if (prev && meta.options.inverse) {\n this.removeInverse(prev.type, prev.id, meta.options.inverse, record);\n }\n return;\n }\n\n const target = value as Model;\n const newRef = { type: target.modelName, id: target.id! };\n runInAction(() => {\n (record as unknown as {\n _setRelationshipRef(name: string, ref: RelationshipRef): void;\n })._setRelationshipRef(name, { data: newRef });\n });\n\n if (meta.options.inverse) {\n if (prev && !Store.refEquals(prev, newRef)) {\n this.removeInverse(prev.type, prev.id, meta.options.inverse, record);\n }\n this.addInverse(newRef.type, newRef.id, meta.options.inverse, record);\n }\n }\n\n // --- hooks used by ManyArray ---\n\n /** Returns the raw relationship ref stored on `record` for `name`. */\n _getRelationshipRefFor(record: Model, name: string): RelationshipRef | null {\n return (record as unknown as {\n _getRelationshipRef(n: string): RelationshipRef | null;\n })._getRelationshipRef(name);\n }\n\n /** Returns any pending (unsaved) members for a `hasMany` relationship. */\n _getPendingMembers(record: Model, name: string): Iterable<Model> {\n return this.pendingMembers.get(record)?.get(name) ?? [];\n }\n\n private addPendingMember(record: Model, name: string, value: Model): void {\n let byName = this.pendingMembers.get(record);\n if (!byName) {\n byName = new Map();\n this.pendingMembers.set(record, byName);\n }\n let set = byName.get(name);\n if (!set) {\n set = observable.set<Model>();\n byName.set(name, set);\n }\n set.add(value);\n }\n\n private removePendingMember(record: Model, name: string, value: Model): void {\n this.pendingMembers.get(record)?.get(name)?.delete(value);\n }\n\n /**\n * Appends `value` to the `hasMany` relationship ref on `record` and syncs\n * the inverse. Unsaved records (`value.id === null`) are tracked as\n * \"pending members\" until they are persisted.\n */\n _hasManyAppend(\n record: Model,\n name: string,\n meta: RelationshipDef,\n value: Model,\n ): void {\n if (value.id === null) {\n this.addPendingMember(record, name, value);\n if (meta.options.inverse) {\n const inverseMeta = this.schema\n .relationshipsDefinitionFor(value.modelName)\n .get(meta.options.inverse);\n if (inverseMeta?.kind === 'belongsTo') {\n runInAction(() => {\n (value as unknown as {\n _setRelationshipRef(n: string, r: RelationshipRef): void;\n })._setRelationshipRef(meta.options.inverse!, {\n data: { type: record.modelName, id: record.id! },\n });\n });\n }\n }\n return;\n }\n const ref = this._getRelationshipRefFor(record, name);\n const currentData = ref?.data && Array.isArray(ref.data) ? ref.data : [];\n const entry = { type: value.modelName, id: value.id };\n if (!currentData.some((reference) => Store.refEquals(reference, entry))) {\n runInAction(() => {\n (record as unknown as {\n _setRelationshipRef(n: string, r: RelationshipRef): void;\n })._setRelationshipRef(name, { data: [...currentData, entry] });\n });\n }\n if (meta.options.inverse) {\n this.addInverse(value.modelName, value.id, meta.options.inverse, record);\n }\n }\n\n /**\n * Removes `value` from the `hasMany` relationship ref on `record` and syncs\n * the inverse. Pending members are removed from the pending set.\n */\n _hasManyRemove(\n record: Model,\n name: string,\n meta: RelationshipDef,\n value: Model,\n ): void {\n if (value.id === null) {\n this.removePendingMember(record, name, value);\n return;\n }\n const ref = this._getRelationshipRefFor(record, name);\n const currentData = ref?.data && Array.isArray(ref.data) ? ref.data : [];\n const filtered = currentData.filter(\n (reference) => !(reference.id === value.id && reference.type === value.modelName),\n );\n runInAction(() => {\n (record as unknown as {\n _setRelationshipRef(n: string, r: RelationshipRef): void;\n })._setRelationshipRef(name, { data: filtered });\n });\n if (meta.options.inverse) {\n this.removeInverse(value.modelName, value.id, meta.options.inverse, record);\n }\n }\n\n // --- coalesceFindRequests ---\n\n private coalescePending: Map<string, Map<string, {\n resolve: (record: Model) => void;\n reject: (error: unknown) => void;\n }[]>> = new Map();\n\n private coalesceScheduled: Set<string> = new Set();\n\n private scheduleCoalescedFind(modelName: string, id: string): Promise<Model> {\n return new Promise((resolve, reject) => {\n let byId = this.coalescePending.get(modelName);\n if (!byId) {\n byId = new Map();\n this.coalescePending.set(modelName, byId);\n }\n let callbacks = byId.get(id);\n if (!callbacks) {\n callbacks = [];\n byId.set(id, callbacks);\n }\n callbacks.push({ resolve, reject });\n\n if (!this.coalesceScheduled.has(modelName)) {\n this.coalesceScheduled.add(modelName);\n queueMicrotask(() => this.flushCoalescedFind(modelName));\n }\n });\n }\n\n private async flushCoalescedFind(modelName: string): Promise<void> {\n this.coalesceScheduled.delete(modelName);\n const byId = this.coalescePending.get(modelName);\n if (!byId || byId.size === 0) {\n return;\n }\n const pendingEntries = new Map(byId);\n byId.clear();\n\n const ids = Array.from(pendingEntries.keys());\n const adapter = this.adapterFor(modelName);\n\n try {\n const snapshots = ids.map((id) => {\n const cached = this.peekRecord(modelName, id);\n return cached\n ? this.createSnapshot(cached)\n : this.createEmptySnapshot(modelName, id);\n });\n const response = await adapter.findMany!(this, modelName, ids, snapshots);\n const doc = this.serializerFor(modelName).normalizeResponse(\n this,\n this.schema.modelFor(modelName),\n response,\n null,\n 'findMany',\n ) as NormalizedDocument;\n this.push(doc);\n\n for (const id of ids) {\n const record = this.peekRecord(modelName, id);\n const callbacks = pendingEntries.get(id);\n if (callbacks) {\n for (const callback of callbacks) {\n if (record) {\n callback.resolve(record);\n } else {\n callback.reject(new Error(`Record not found after findMany: ${modelName}:${id}`));\n }\n }\n }\n }\n } catch (error) {\n for (const callbacks of pendingEntries.values()) {\n for (const callback of callbacks) {\n callback.reject(error);\n }\n }\n }\n }\n\n // --- liveQuery ---\n\n /**\n * Returns a reactive `RecordArray` that auto-updates whenever records matching\n * the predicate are added, removed, or mutated in the identity map.\n *\n * The underlying computed uses `keepAlive: true` so it remains cached even\n * without active MobX observers — useful for long-lived filtered views.\n *\n * @param modelName - The registered model type to query.\n * @param predicate - Filter function applied to each record of `modelName`.\n * @returns A live `RecordArray` containing only records that satisfy `predicate`.\n */\n liveQuery<T extends Model = Model>(\n modelName: string,\n predicate: (record: T) => boolean,\n ): RecordArray<T> {\n return new RecordArray<T>({\n modelName,\n keepAlive: true,\n source: () => {\n const all = this.identityMap.all(modelName) as T[];\n const newRecordsForType = this.newRecords.get(modelName);\n const combined = newRecordsForType && newRecordsForType.size > 0\n ? [...all, ...(newRecordsForType as unknown as Set<T>)]\n : all;\n return combined.filter(predicate);\n },\n });\n }\n\n // --- optimisticUpdate ---\n\n /**\n * Applies attribute changes to a record immediately (optimistically), then\n * executes `persistFn`. If `persistFn` throws, the record is automatically\n * rolled back to its state before the optimistic update.\n *\n * @param record - The record to update optimistically.\n * @param optimisticAttributes - Attributes to apply before persistence.\n * @param persistFn - Async function that persists the change (e.g. `record.save()`).\n * @returns The record on success.\n * @throws Re-throws the error from `persistFn` after rollback.\n */\n async optimisticUpdate<T extends Model>(\n record: T,\n optimisticAttributes: Partial<Record<string, unknown>>,\n persistFn: () => Promise<unknown>,\n ): Promise<T> {\n const internal = record as unknown as {\n _data: Record<string, unknown>;\n _savedData: Record<string, unknown>;\n };\n const backup = { ...internal._data };\n\n runInAction(() => {\n Object.assign(internal._data, optimisticAttributes);\n });\n\n try {\n await persistFn();\n return record;\n } catch (error) {\n runInAction(() => {\n for (const [key, value] of Object.entries(backup)) {\n internal._data[key] = value;\n }\n });\n throw error;\n }\n }\n\n // --- runInTransaction ---\n\n /**\n * Executes multiple store mutations as a single MobX action, guaranteeing\n * that observers (and therefore UI renders) react only once — after all\n * mutations have been applied.\n *\n * @param callback - Synchronous function containing one or more store mutations.\n */\n runInTransaction(callback: () => void): void {\n runInAction(callback);\n }\n\n // --- SSR: serialize / hydrate ---\n\n /**\n * Produces a JSON-serializable snapshot of all records in the identity map.\n * Designed for server-side rendering: serialize on the server, transfer as\n * JSON, then `hydrate()` on the client to restore the full store state\n * without network requests.\n *\n * @param options.exclude - Per-model-type list of attribute keys to omit\n * (e.g. `{ user: ['password', 'token'] }`) to prevent leaking sensitive\n * data in SSR payloads.\n * @returns A snapshot object safe to pass through `JSON.stringify`.\n */\n serialize(options: {\n exclude?: Record<string, string[]>;\n } = {}): { records: Record<string, Array<{ id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> }>> } {\n const records: Record<string, Array<{ id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> }>> = {};\n const allTypes = this.identityMap._buckets;\n for (const [modelName, bucket] of allTypes) {\n const excludeKeys = options.exclude?.[modelName];\n const items: Array<{ id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> }> = [];\n for (const [id, record] of bucket) {\n const internal = record as unknown as {\n _data: Record<string, unknown>;\n _relationships: Map<string, RelationshipRef>;\n };\n let attributes: Record<string, unknown>;\n if (excludeKeys && excludeKeys.length > 0) {\n attributes = {};\n for (const [key, value] of Object.entries(internal._data)) {\n if (!excludeKeys.includes(key)) {\n attributes[key] = value;\n }\n }\n } else {\n attributes = { ...internal._data };\n }\n const entry: { id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> } = {\n id,\n attributes,\n };\n if (internal._relationships && internal._relationships.size > 0) {\n const relationships: Record<string, RelationshipRef> = {};\n for (const [name, ref] of internal._relationships) {\n relationships[name] = ref;\n }\n entry.relationships = relationships;\n }\n items.push(entry);\n }\n if (items.length > 0) {\n records[modelName] = items;\n }\n }\n return { records };\n }\n\n /**\n * Restores records from a snapshot produced by `serialize()` into this store\n * instance. All records are pushed into the identity map in `loaded.saved`\n * state — no network requests are issued.\n *\n * @param snapshot - A snapshot object previously returned by `serialize()`.\n */\n hydrate(snapshot: { records: Record<string, Array<{ id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> }>> }): void {\n runInAction(() => {\n for (const [modelName, items] of Object.entries(snapshot.records)) {\n for (const item of items) {\n this.pushResource({\n type: modelName,\n id: item.id,\n attributes: item.attributes,\n relationships: item.relationships,\n });\n }\n }\n });\n }\n\n /**\n * Factory method that creates a new `Store` and immediately hydrates it from\n * the given snapshot. Convenience for SSR client-side bootstrap.\n *\n * @param schema - SchemaService with all model types registered.\n * @param snapshot - A snapshot object previously returned by `serialize()`.\n * @returns A fully populated `Store` instance ready for use.\n */\n static hydrate(\n schema: SchemaService,\n snapshot: { records: Record<string, Array<{ id: string; attributes: Record<string, unknown>; relationships?: Record<string, RelationshipRef> }>> },\n ): Store {\n const store = new Store(schema);\n store.hydrate(snapshot);\n return store;\n }\n}\n"],"names":["IdentityMap","makeObservable","observable","action","modelName","create","existing","id","record","_a","bucket","total","RecordArray","opts","computed","index","callback","predicate","AdapterPopulatedRecordArray","meta","links","Store","schema","a","b","adapter","serializer","data","Klass","set","key","persisted","newRecordsForType","doc","document","resource","modelNameOrPayload","payload","body","normalized","type","runInAction","Model","name","ref","items","item","targetType","targetId","inverseName","inverseRecord","target","inverseMeta","inverseEntry","currentData","reference","options","cached","snapshot","adapterOptions","response","params","ids","array","r","result","isNew","newId","attributes","relationships","internal","resolvedRecord","value","m","isAsync","hostWithStore","wrapper","AsyncBelongsTo","AsyncHasMany","arr","ManyArray","prev","newRef","byName","_b","entry","filtered","resolve","reject","byId","callbacks","pendingEntries","snapshots","error","all","optimisticAttributes","persistFn","backup","records","allTypes","excludeKeys","store","__decorateClass","singleton","injectable","__decorateParam","SchemaService"],"mappings":"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"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Abstract base class for all adapters.
3
+ *
4
+ * An adapter translates store operations (findRecord, createRecord, …) into
5
+ * concrete network requests and returns raw payloads that the serializer layer
6
+ * then normalises. Concrete subclasses (`RestAdapter`, `ODataAdapter`, …)
7
+ * override the abstract CRUD methods and may also override the URL-building
8
+ * helpers to produce protocol-specific URLs.
9
+ *
10
+ * URL construction follows an Ember Data–style pipeline:
11
+ * `buildURL` → `urlForFindRecord` / `urlForQuery` / … → `_composeURL`
12
+ *
13
+ * Configuration surface:
14
+ * - `host` – base URL prefix (e.g. `https://api.example.com`)
15
+ * - `namespace` – path segment appended after the host (e.g. `v2`)
16
+ * - `headers` – headers merged into every request
17
+ * - `coalesceFindRequests` – when `true` the store batches separate
18
+ * `findRecord` calls into a single `findMany` call
19
+ */
20
+ /** Union of all operation names the store can issue to an adapter. */
21
+ export type AdapterRequestType = 'findRecord' | 'findAll' | 'findMany' | 'query' | 'queryRecord' | 'createRecord' | 'updateRecord' | 'deleteRecord';
22
+ /**
23
+ * A frozen view of a model record passed to the adapter.
24
+ * Adapters read but do not mutate snapshots.
25
+ */
26
+ export interface AdapterSnapshot {
27
+ /** The record's server-assigned id, or `null` for new records. */
28
+ id: string | null;
29
+ /** The model's registered `modelName`. */
30
+ modelName: string;
31
+ /** Returns the current value for an attribute key. */
32
+ attr(key: string): unknown;
33
+ /** Returns the `belongsTo` relationship value (or just its id when `{ id: true }`). */
34
+ belongsTo(key: string, options?: {
35
+ id: boolean;
36
+ }): unknown;
37
+ /** Returns the `hasMany` relationship values (or just ids when `{ ids: true }`). */
38
+ hasMany(key: string, options?: {
39
+ ids: boolean;
40
+ }): unknown;
41
+ /** Returns `{ [key]: [oldValue, newValue] }` for attributes that differ from the server state. */
42
+ changedAttributes(): Record<string, [unknown, unknown]>;
43
+ /** Reference to the live record instance. */
44
+ record: unknown;
45
+ }
46
+ export declare abstract class Adapter {
47
+ /** Base URL prepended to every generated URL. Empty string = relative URLs. */
48
+ namespace: string;
49
+ /** Host prefix, e.g. `https://api.example.com`. */
50
+ host: string;
51
+ /** Extra headers merged into every request via `defaultHeaders()`. */
52
+ headers: Record<string, string>;
53
+ /**
54
+ * When `true` the store will coalesce multiple `findRecord` calls for the
55
+ * same model type into a single `findMany` network request.
56
+ */
57
+ coalesceFindRequests: boolean;
58
+ /** Fetches a single record by id. */
59
+ abstract findRecord(store: unknown, modelName: string, id: string, snapshot: AdapterSnapshot, options?: {
60
+ include?: string;
61
+ }): Promise<unknown>;
62
+ /** Fetches all records of a given model type. */
63
+ abstract findAll(store: unknown, modelName: string, sinceToken: string | null, snapshotArray: AdapterSnapshot[], options?: {
64
+ include?: string;
65
+ }): Promise<unknown>;
66
+ /** Fetches multiple records by id in a single request. */
67
+ abstract findMany(store: unknown, modelName: string, ids: string[], snapshots: AdapterSnapshot[]): Promise<unknown>;
68
+ /** Executes an arbitrary server-side query, returning an array of records. */
69
+ abstract query(store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
70
+ /** Like `query` but returns at most one record. */
71
+ abstract queryRecord(store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
72
+ /** Persists a new record to the server (POST). */
73
+ abstract createRecord(store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
74
+ /** Persists all attributes of an existing record (PUT). */
75
+ abstract updateRecord(store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
76
+ /**
77
+ * Persists only the changed attributes of an existing record (PATCH).
78
+ * Default implementation delegates to `updateRecord`.
79
+ * Override in subclasses to send a partial payload via HTTP PATCH.
80
+ */
81
+ patchRecord(store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
82
+ /** Removes a record from the server (DELETE). */
83
+ abstract deleteRecord(store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
84
+ /**
85
+ * Returns the URL path segment for a given model name.
86
+ * Default: dasherized, pluralized form — e.g. `userPost` → `user-posts`.
87
+ */
88
+ pathForType(modelName: string): string;
89
+ /**
90
+ * Assembles a full URL from `host`, `namespace`, and the supplied `path`.
91
+ * Returns an absolute URL when `host` is set, otherwise a root-relative path.
92
+ */
93
+ protected _composeURL(path: string): string;
94
+ /**
95
+ * Dispatches to the appropriate `urlFor*` method based on `requestType`.
96
+ *
97
+ * @param modelName - Registered model name.
98
+ * @param id - Record id(s), or `null` for collection requests.
99
+ * @param snapshot - Snapshot(s) for the request.
100
+ * @param requestType - Operation being performed.
101
+ * @param query - Query parameters (used for `query` / `queryRecord`).
102
+ */
103
+ buildURL(modelName: string, id: string | string[] | null, snapshot: AdapterSnapshot | AdapterSnapshot[] | null, requestType: AdapterRequestType, query?: Record<string, unknown>): string;
104
+ /** URL for a `findRecord` request. Default: `<collection>/<id>`. */
105
+ urlForFindRecord(id: string, modelName: string, _snapshot: AdapterSnapshot): string;
106
+ /** URL for a `findAll` request. Default: `<collection>`. */
107
+ urlForFindAll(modelName: string, _snapshots: AdapterSnapshot[]): string;
108
+ /** URL for a `findMany` request. Default: `<collection>` (ids appended by the adapter). */
109
+ urlForFindMany(_ids: string[], modelName: string, _snapshots: AdapterSnapshot[]): string;
110
+ /** URL for a `query` request. Default: `<collection>`. */
111
+ urlForQuery(_query: Record<string, unknown>, modelName: string): string;
112
+ /** URL for a `queryRecord` request. Default: `<collection>`. */
113
+ urlForQueryRecord(_query: Record<string, unknown>, modelName: string): string;
114
+ /** URL for a `createRecord` request. Default: `<collection>`. */
115
+ urlForCreateRecord(modelName: string, _snapshot: AdapterSnapshot): string;
116
+ /** URL for an `updateRecord` request. Default: `<collection>/<id>`. */
117
+ urlForUpdateRecord(id: string, modelName: string, _snapshot: AdapterSnapshot): string;
118
+ /** URL for a `deleteRecord` request. Default: `<collection>/<id>`. */
119
+ urlForDeleteRecord(id: string, modelName: string, _snapshot: AdapterSnapshot): string;
120
+ /**
121
+ * Groups snapshots into batches for `findMany`.
122
+ * Default implementation puts all snapshots in a single batch.
123
+ */
124
+ groupRecordsForFindMany(_store: unknown, snapshots: AdapterSnapshot[]): AdapterSnapshot[][];
125
+ /**
126
+ * Returns `true` when the store should bypass the cache and reload this
127
+ * record immediately. Default: always `false`.
128
+ */
129
+ shouldReloadRecord(_store: unknown, _snapshot: AdapterSnapshot): boolean;
130
+ /**
131
+ * Returns `true` when the store should schedule a background reload for
132
+ * this record after returning the cached version. Default: always `true`.
133
+ */
134
+ shouldBackgroundReloadRecord(_store: unknown, _snapshot: AdapterSnapshot): boolean;
135
+ /**
136
+ * Returns `true` when the store should reload the full collection on every
137
+ * `findAll` call. Default: always `false`.
138
+ */
139
+ shouldReloadAll(_store: unknown, _snapshotRecordArray: AdapterSnapshot[]): boolean;
140
+ /**
141
+ * Returns `true` when the store should schedule a background reload after
142
+ * returning a cached collection. Default: always `true`.
143
+ */
144
+ shouldBackgroundReloadAll(_store: unknown, _snapshotRecordArray: AdapterSnapshot[]): boolean;
145
+ }
146
+ //# sourceMappingURL=Adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Adapter.d.ts","sourceRoot":"","sources":["../../src/adapter/Adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * In-memory adapter for testing and server-side rendering.
3
+ *
4
+ * `MemoryAdapter` stores records in plain `Map` structures with no network I/O.
5
+ * It implements the full adapter interface (findRecord, findAll, findMany, query,
6
+ * queryRecord, createRecord, updateRecord, deleteRecord) so it can serve as a
7
+ * drop-in replacement for `RestAdapter` in unit tests or SSR hydration scenarios.
8
+ *
9
+ * Use `seed()` to pre-populate data and `reset()` to clear all state between
10
+ * test cases.
11
+ */
12
+ import { Adapter, type AdapterSnapshot } from './Adapter.js';
13
+ export declare class MemoryAdapter extends Adapter {
14
+ private storage;
15
+ private nextId;
16
+ private getCollection;
17
+ private generateId;
18
+ /**
19
+ * Pre-populates the adapter with records for a given model type.
20
+ * Auto-increments the internal ID counter to avoid collisions with
21
+ * subsequently created records.
22
+ *
23
+ * @param modelName - The model type to seed.
24
+ * @param records - Array of plain objects; each must have an `id` key.
25
+ */
26
+ seed(modelName: string, records: Array<{
27
+ id: string;
28
+ [key: string]: unknown;
29
+ }>): void;
30
+ /** Clears all stored records and resets ID counters. */
31
+ reset(): void;
32
+ findRecord(_store: unknown, modelName: string, id: string): Promise<unknown>;
33
+ findAll(_store: unknown, modelName: string): Promise<unknown>;
34
+ findMany(_store: unknown, modelName: string, ids: string[]): Promise<unknown>;
35
+ /** Filters records by exact attribute match on all query keys. */
36
+ query(_store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
37
+ /** Returns the first record matching the query, or `null`. */
38
+ queryRecord(_store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
39
+ private static safeAssign;
40
+ createRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
41
+ updateRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
42
+ deleteRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
43
+ }
44
+ //# sourceMappingURL=MemoryAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MemoryAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/MemoryAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAQ7D,qBACa,aAAc,SAAQ,OAAO;IACxC,OAAO,CAAC,OAAO,CAAqD;IAEpE,OAAO,CAAC,MAAM,CAAkC;IAEhD,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,UAAU;IAMlB;;;;;;;OAOG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI;IAerF,wDAAwD;IACxD,KAAK,IAAI,IAAI;IAKE,UAAU,CACvB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC;IAYJ,OAAO,CACpB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAUJ,QAAQ,CACrB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EAAE,GACZ,OAAO,CAAC,OAAO,CAAC;IAanB,kEAAkE;IACnD,KAAK,CAClB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC;IAmBnB,8DAA8D;IAC/C,WAAW,CACxB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC;IAKnB,OAAO,CAAC,MAAM,CAAC,UAAU;IAYV,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;IAYJ,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;IAoBJ,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;CAQpB"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * HTTP/REST adapter that communicates with a JSON REST API.
3
+ *
4
+ * `RestAdapter` is the default concrete adapter. It uses the Fetch API and
5
+ * maps each store operation to a conventional HTTP verb:
6
+ *
7
+ * | Operation | Method |
8
+ * |----------------|--------|
9
+ * | findRecord | GET |
10
+ * | findAll | GET |
11
+ * | findMany | GET |
12
+ * | query | GET |
13
+ * | queryRecord | GET |
14
+ * | createRecord | POST |
15
+ * | updateRecord | PUT |
16
+ * | deleteRecord | DELETE |
17
+ *
18
+ * Subclasses (e.g. `JsonApiAdapter`, `ODataAdapter`) override individual
19
+ * methods to adjust headers, HTTP verbs, or body serialization without
20
+ * reimplementing the full adapter.
21
+ */
22
+ import { Adapter, type AdapterSnapshot } from './Adapter.js';
23
+ export declare class RestAdapter extends Adapter {
24
+ static serializeSnapshotToObject(snapshot: AdapterSnapshot): Record<string, unknown>;
25
+ static toQueryString(query: Record<string, unknown>): string;
26
+ /** Headers sent with every read (GET) request. */
27
+ defaultHeaders(): Record<string, string>;
28
+ /** Headers sent with every write (POST / PUT / DELETE) request. */
29
+ mutationHeaders(): Record<string, string>;
30
+ /**
31
+ * Low-level fetch wrapper used by all operation methods.
32
+ *
33
+ * - Throws an enriched `Error` (with `status` and `body` properties) for
34
+ * any non-2xx response.
35
+ * - Returns `null` for 204 No Content responses.
36
+ * - Attempts JSON parsing; falls back to the raw text string on failure.
37
+ */
38
+ _fetchJSON(url: string, init: RequestInit): Promise<unknown>;
39
+ findRecord(_store: unknown, modelName: string, id: string, snapshot: AdapterSnapshot, options?: {
40
+ include?: string;
41
+ }): Promise<unknown>;
42
+ findAll(_store: unknown, modelName: string, _sinceToken: string | null, snapshotArray: AdapterSnapshot[], options?: {
43
+ include?: string;
44
+ }): Promise<unknown>;
45
+ /**
46
+ * Fetches multiple records by appending an `ids` query parameter.
47
+ * e.g. `/posts?ids=1,2,3`
48
+ */
49
+ findMany(_store: unknown, modelName: string, ids: string[], snapshots: AdapterSnapshot[]): Promise<unknown>;
50
+ query(_store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
51
+ queryRecord(_store: unknown, modelName: string, query: Record<string, unknown>): Promise<unknown>;
52
+ createRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
53
+ updateRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
54
+ patchRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
55
+ deleteRecord(_store: unknown, modelName: string, snapshot: AdapterSnapshot): Promise<unknown>;
56
+ }
57
+ //# sourceMappingURL=RestAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RestAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/RestAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAE7D,qBACa,WAAY,SAAQ,OAAO;IACtC,MAAM,CAAC,yBAAyB,CAC9B,QAAQ,EAAE,eAAe,GACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAe1B,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAa5D,kDAAkD;IAClD,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOxC,mEAAmE;IACnE,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAOzC;;;;;;;OAOG;IACG,UAAU,CACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,OAAO,CAAC;IA6BJ,UAAU,CACvB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,eAAe,EACzB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC,OAAO,CAAC;IAWJ,OAAO,CACpB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,aAAa,EAAE,eAAe,EAAE,EAChC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7B,OAAO,CAAC,OAAO,CAAC;IAWnB;;;OAGG;IACY,QAAQ,CACrB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EAAE,EACb,SAAS,EAAE,eAAe,EAAE,GAC3B,OAAO,CAAC,OAAO,CAAC;IAUJ,KAAK,CAClB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC;IASJ,WAAW,CACxB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,OAAO,CAAC;IASJ,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;IASJ,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;IASJ,WAAW,CACxB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;IAcJ,YAAY,CACzB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,OAAO,CAAC;CAOpB"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../RestAdapter-CJOwTsKK.cjs"),r=require("../MemoryAdapter-D1cTyydm.cjs");exports.Adapter=e.Adapter;Object.defineProperty(exports,"RestAdapter",{enumerable:!0,get:()=>e.RestAdapter});Object.defineProperty(exports,"MemoryAdapter",{enumerable:!0,get:()=>r.MemoryAdapter});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export { Adapter, type AdapterRequestType, type AdapterSnapshot, } from './Adapter.js';
2
+ export { RestAdapter } from './RestAdapter.js';
3
+ export { MemoryAdapter } from './MemoryAdapter.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { A as a, R as t } from "../RestAdapter-B4aRvs4m.js";
2
+ import { M as p } from "../MemoryAdapter-Bx1e7ndV.js";
3
+ export {
4
+ a as Adapter,
5
+ p as MemoryAdapter,
6
+ t as RestAdapter
7
+ };
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,107 @@
1
+ import { injectable as s } from "tsyringe";
2
+ class c {
3
+ }
4
+ var v = Object.getOwnPropertyDescriptor, g = (r, n, u, l) => {
5
+ for (var t = l > 1 ? void 0 : l ? v(n, u) : n, e = r.length - 1, o; e >= 0; e--)
6
+ (o = r[e]) && (t = o(t) || t);
7
+ return t;
8
+ };
9
+ let a = class extends c {
10
+ deserialize(r) {
11
+ return r == null ? null : typeof r == "string" ? r : String(r);
12
+ }
13
+ serialize(r) {
14
+ return r == null ? null : String(r);
15
+ }
16
+ };
17
+ a = g([
18
+ s()
19
+ ], a);
20
+ var b = Object.getOwnPropertyDescriptor, N = (r, n, u, l) => {
21
+ for (var t = l > 1 ? void 0 : l ? b(n, u) : n, e = r.length - 1, o; e >= 0; e--)
22
+ (o = r[e]) && (t = o(t) || t);
23
+ return t;
24
+ };
25
+ let f = class extends c {
26
+ static coerce(r) {
27
+ if (r == null || r === "")
28
+ return null;
29
+ if (typeof r == "number")
30
+ return Number.isFinite(r) ? r : null;
31
+ if (typeof r == "string") {
32
+ const n = r.trim();
33
+ if (n === "")
34
+ return null;
35
+ const u = Number(n);
36
+ return Number.isFinite(u) ? u : null;
37
+ }
38
+ return null;
39
+ }
40
+ deserialize(r) {
41
+ return f.coerce(r);
42
+ }
43
+ serialize(r) {
44
+ return f.coerce(r);
45
+ }
46
+ };
47
+ f = N([
48
+ s()
49
+ ], f);
50
+ var _ = Object.getOwnPropertyDescriptor, D = (r, n, u, l) => {
51
+ for (var t = l > 1 ? void 0 : l ? _(n, u) : n, e = r.length - 1, o; e >= 0; e--)
52
+ (o = r[e]) && (t = o(t) || t);
53
+ return t;
54
+ };
55
+ let m = class extends c {
56
+ deserialize(r, n = {}) {
57
+ if (r == null)
58
+ return n.allowNull ? null : !1;
59
+ if (typeof r == "boolean")
60
+ return r;
61
+ if (typeof r == "number")
62
+ return r === 1;
63
+ if (typeof r == "string") {
64
+ const u = r.toLowerCase();
65
+ return u === "true" || u === "t" || u === "1";
66
+ }
67
+ return !!r;
68
+ }
69
+ serialize(r, n = {}) {
70
+ return r == null ? n.allowNull ? null : !1 : !!r;
71
+ }
72
+ };
73
+ m = D([
74
+ s()
75
+ ], m);
76
+ var O = Object.getOwnPropertyDescriptor, i = (r, n, u, l) => {
77
+ for (var t = l > 1 ? void 0 : l ? O(n, u) : n, e = r.length - 1, o; e >= 0; e--)
78
+ (o = r[e]) && (t = o(t) || t);
79
+ return t;
80
+ };
81
+ let p = class extends c {
82
+ deserialize(r) {
83
+ if (r == null || r === "")
84
+ return null;
85
+ if (r instanceof Date)
86
+ return Number.isNaN(r.getTime()) ? null : r;
87
+ if (typeof r == "number" || typeof r == "string") {
88
+ const n = new Date(r);
89
+ return Number.isNaN(n.getTime()) ? null : n;
90
+ }
91
+ return null;
92
+ }
93
+ serialize(r) {
94
+ return r == null ? null : r instanceof Date ? Number.isNaN(r.getTime()) ? null : r.toISOString() : null;
95
+ }
96
+ };
97
+ p = i([
98
+ s()
99
+ ], p);
100
+ export {
101
+ c as B,
102
+ p as D,
103
+ f as N,
104
+ a as S,
105
+ m as a
106
+ };
107
+ //# sourceMappingURL=date-Bj4O2W1F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-Bj4O2W1F.js","sources":["../src/transforms/Transform.ts","../src/transforms/string.ts","../src/transforms/number.ts","../src/transforms/boolean.ts","../src/transforms/date.ts"],"sourcesContent":["/**\n * Interface and abstract base class for data transforms.\n *\n * A transform converts attribute values between the wire format used by the\n * server (External) and the in-memory format used by the application\n * (Internal).\n *\n * - `deserialize` — called when the store receives data from the server\n * (normalize direction, server → app).\n * - `serialize` — called when the store sends data to the server\n * (serialize direction, app → server).\n *\n * Built-in transforms: `StringTransform`, `NumberTransform`,\n * `BooleanTransform`, `DateTransform`.\n *\n * Custom transforms can be implemented by extending `BaseTransform`:\n *\n * ```ts\n * @injectable()\n * class UpperCaseTransform extends BaseTransform<string, string> {\n * deserialize(value: string) { return value.toUpperCase(); }\n * serialize(value: string) { return value.toLowerCase(); }\n * }\n * ```\n */\n\n/** Bidirectional value converter for a single attribute type. */\nexport interface Transform<External = unknown, Internal = unknown> {\n /**\n * Converts a raw server value to the application-side type.\n * @param serialized - Raw value as it arrived from the server.\n * @param options - Extra options forwarded from the `@attr` decorator.\n */\n deserialize(serialized: External, options?: Record<string, unknown>): Internal;\n\n /**\n * Converts an application-side value back to the wire format.\n * @param deserialized - Current in-memory value.\n * @param options - Extra options forwarded from the `@attr` decorator.\n */\n serialize(deserialized: Internal, options?: Record<string, unknown>): External;\n}\n\n/**\n * Convenience abstract class that implements `Transform` and can be extended\n * to create custom transforms without repeating the interface declaration.\n */\nexport abstract class BaseTransform<External = unknown, Internal = unknown>\nimplements Transform<External, Internal> {\n abstract deserialize(serialized: External, options?: Record<string, unknown>): Internal;\n abstract serialize(deserialized: Internal, options?: Record<string, unknown>): External;\n}\n","/**\n * Transform that converts between arbitrary wire values and strings.\n *\n * Deserialization:\n * - `null` / `undefined` → `null`\n * - `string` → passed through\n * - anything else → `String(value)`\n *\n * Serialization:\n * - `null` / `undefined` → `null`\n * - anything else → `String(value)`\n */\n\nimport { injectable } from 'tsyringe';\nimport { BaseTransform } from './Transform.js';\n\n@injectable()\nexport class StringTransform extends BaseTransform<unknown, string | null> {\n deserialize(serialized: unknown): string | null {\n if (serialized === null || serialized === undefined) {\n return null;\n }\n if (typeof serialized === 'string') {\n return serialized;\n }\n return String(serialized);\n }\n\n serialize(deserialized: string | null): unknown {\n if (deserialized === null || deserialized === undefined) {\n return null;\n }\n return String(deserialized);\n }\n}\n","/**\n * Transform that converts between arbitrary wire values and numbers.\n *\n * Deserialization / serialization coercions (identical in both directions):\n * - `null` / `undefined` / `''` → `null`\n * - finite `number` → passed through\n * - non-finite `number` (NaN, Infinity) → `null`\n * - `string` → trimmed and parsed; `null` when the result is not finite\n * - anything else → `null`\n */\n\nimport { injectable } from 'tsyringe';\nimport { BaseTransform } from './Transform.js';\n\n@injectable()\nexport class NumberTransform extends BaseTransform<unknown, number | null> {\n static coerce(value: unknown): number | null {\n if (value === null || value === undefined || value === '') {\n return null;\n }\n if (typeof value === 'number') {\n return Number.isFinite(value) ? value : null;\n }\n if (typeof value === 'string') {\n const trimmed = value.trim();\n if (trimmed === '') {\n return null;\n }\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) ? parsed : null;\n }\n return null;\n }\n\n deserialize(serialized: unknown): number | null {\n return NumberTransform.coerce(serialized);\n }\n\n serialize(deserialized: number | null): unknown {\n return NumberTransform.coerce(deserialized);\n }\n}\n","/**\n * Transform that converts between arbitrary wire values and booleans.\n *\n * Deserialization coercions:\n * - `null` / `undefined` → `false` (or `null` when `allowNull: true`)\n * - `boolean` → passed through\n * - `number` → `true` only when the value is exactly `1`\n * - `string` → `true` for `'true'`, `'t'`, or `'1'` (case-insensitive)\n * - anything else → `Boolean(value)`\n *\n * Serialization: `Boolean(value)` (preserves `null` when `allowNull: true`).\n */\n\nimport { injectable } from 'tsyringe';\nimport { BaseTransform } from './Transform.js';\n\n/** Options accepted by `BooleanTransform`. */\nexport interface BooleanTransformOptions {\n /**\n * When `true`, `null` / `undefined` input is preserved as `null` rather\n * than coerced to `false`.\n */\n allowNull?: boolean;\n}\n\n@injectable()\nexport class BooleanTransform extends BaseTransform<unknown, boolean | null> {\n deserialize(\n serialized: unknown,\n options: BooleanTransformOptions = {},\n ): boolean | null {\n if (serialized === null || serialized === undefined) {\n return options.allowNull ? null : false;\n }\n if (typeof serialized === 'boolean') {\n return serialized;\n }\n if (typeof serialized === 'number') {\n return serialized === 1;\n }\n if (typeof serialized === 'string') {\n const normalized = serialized.toLowerCase();\n return normalized === 'true' || normalized === 't' || normalized === '1';\n }\n return Boolean(serialized);\n }\n\n serialize(\n deserialized: boolean | null,\n options: BooleanTransformOptions = {},\n ): unknown {\n if (deserialized === null || deserialized === undefined) {\n return options.allowNull ? null : false;\n }\n return Boolean(deserialized);\n }\n}\n","/**\n * Transform that converts between ISO 8601 strings (or numeric timestamps)\n * and JavaScript `Date` objects.\n *\n * Deserialization:\n * - `null` / `undefined` / `''` → `null`\n * - `Date` instance → returned as-is (or `null` when invalid)\n * - `number` (Unix ms) or `string` (ISO 8601) → parsed via `new Date(value)`,\n * returns `null` when parsing yields `NaN`\n * - anything else → `null`\n *\n * Serialization:\n * - `null` / `undefined` → `null`\n * - `Date` instance → ISO 8601 string via `.toISOString()` (or `null` when invalid)\n * - anything else → `null`\n */\n\nimport { injectable } from 'tsyringe';\nimport { BaseTransform } from './Transform.js';\n\n@injectable()\nexport class DateTransform extends BaseTransform<unknown, Date | null> {\n deserialize(serialized: unknown): Date | null {\n if (serialized === null || serialized === undefined || serialized === '') {\n return null;\n }\n if (serialized instanceof Date) {\n return Number.isNaN(serialized.getTime()) ? null : serialized;\n }\n if (typeof serialized === 'number' || typeof serialized === 'string') {\n const parsed = new Date(serialized);\n return Number.isNaN(parsed.getTime()) ? null : parsed;\n }\n return null;\n }\n\n serialize(deserialized: Date | null): unknown {\n if (deserialized === null || deserialized === undefined) {\n return null;\n }\n if (deserialized instanceof Date) {\n return Number.isNaN(deserialized.getTime())\n ? null\n : deserialized.toISOString();\n }\n return null;\n }\n}\n"],"names":["BaseTransform","StringTransform","serialized","deserialized","__decorateClass","injectable","NumberTransform","value","trimmed","parsed","BooleanTransform","options","normalized","DateTransform"],"mappings":";AA+CO,MAAeA,EACmB;AAGzC;;;;;;AClCO,IAAMC,IAAN,cAA8BD,EAAsC;AAAA,EACzE,YAAYE,GAAoC;AAC9C,WAAIA,KAAe,OACV,OAEL,OAAOA,KAAe,WACjBA,IAEF,OAAOA,CAAU;AAAA,EAC1B;AAAA,EAEA,UAAUC,GAAsC;AAC9C,WAAIA,KAAiB,OACZ,OAEF,OAAOA,CAAY;AAAA,EAC5B;AACF;AAjBaF,IAANG,EAAA;AAAA,EADNC,EAAA;AAAW,GACCJ,CAAA;;;;;;ACFN,IAAMK,IAAN,cAA8BN,EAAsC;AAAA,EACzE,OAAO,OAAOO,GAA+B;AAC3C,QAAIA,KAAU,QAA+BA,MAAU;AACrD,aAAO;AAET,QAAI,OAAOA,KAAU;AACnB,aAAO,OAAO,SAASA,CAAK,IAAIA,IAAQ;AAE1C,QAAI,OAAOA,KAAU,UAAU;AAC7B,YAAMC,IAAUD,EAAM,KAAA;AACtB,UAAIC,MAAY;AACd,eAAO;AAET,YAAMC,IAAS,OAAOD,CAAO;AAC7B,aAAO,OAAO,SAASC,CAAM,IAAIA,IAAS;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAAA,EAEA,YAAYP,GAAoC;AAC9C,WAAOI,EAAgB,OAAOJ,CAAU;AAAA,EAC1C;AAAA,EAEA,UAAUC,GAAsC;AAC9C,WAAOG,EAAgB,OAAOH,CAAY;AAAA,EAC5C;AACF;AA1BaG,IAANF,EAAA;AAAA,EADNC,EAAA;AAAW,GACCC,CAAA;;;;;;ACWN,IAAMI,IAAN,cAA+BV,EAAuC;AAAA,EAC3E,YACEE,GACAS,IAAmC,IACnB;AAChB,QAAIT,KAAe;AACjB,aAAOS,EAAQ,YAAY,OAAO;AAEpC,QAAI,OAAOT,KAAe;AACxB,aAAOA;AAET,QAAI,OAAOA,KAAe;AACxB,aAAOA,MAAe;AAExB,QAAI,OAAOA,KAAe,UAAU;AAClC,YAAMU,IAAaV,EAAW,YAAA;AAC9B,aAAOU,MAAe,UAAUA,MAAe,OAAOA,MAAe;AAAA,IACvE;AACA,WAAO,EAAQV;AAAA,EACjB;AAAA,EAEA,UACEC,GACAQ,IAAmC,IAC1B;AACT,WAAIR,KAAiB,OACZQ,EAAQ,YAAY,OAAO,KAE7B,EAAQR;AAAA,EACjB;AACF;AA9BaO,IAANN,EAAA;AAAA,EADNC,EAAA;AAAW,GACCK,CAAA;;;;;;ACLN,IAAMG,IAAN,cAA4Bb,EAAoC;AAAA,EACrE,YAAYE,GAAkC;AAC5C,QAAIA,KAAe,QAAoCA,MAAe;AACpE,aAAO;AAET,QAAIA,aAAsB;AACxB,aAAO,OAAO,MAAMA,EAAW,QAAA,CAAS,IAAI,OAAOA;AAErD,QAAI,OAAOA,KAAe,YAAY,OAAOA,KAAe,UAAU;AACpE,YAAMO,IAAS,IAAI,KAAKP,CAAU;AAClC,aAAO,OAAO,MAAMO,EAAO,QAAA,CAAS,IAAI,OAAOA;AAAA,IACjD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,UAAUN,GAAoC;AAC5C,WAAIA,KAAiB,OACZ,OAELA,aAAwB,OACnB,OAAO,MAAMA,EAAa,QAAA,CAAS,IACtC,OACAA,EAAa,YAAA,IAEZ;AAAA,EACT;AACF;AA1BaU,IAANT,EAAA;AAAA,EADNC,EAAA;AAAW,GACCQ,CAAA;"}