@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":"relationships-BEXANmWg.js","sources":["../src/model/Errors.ts","../src/model/StateMachine.ts","../src/model/Snapshot.ts","../src/model/Model.ts","../src/model/relationships.ts"],"sourcesContent":["/**\n * Observable collection of validation error messages keyed by attribute name.\n *\n * `Errors` is attached to every `Model` instance as `record.errors`. It\n * mirrors Ember Data's `DS.Errors` API: each attribute can hold multiple\n * `ErrorMessage` objects, and the map is MobX-observable so templates / computed\n * properties that read `isEmpty` or `length` react automatically when errors\n * are added or cleared.\n *\n * Typical lifecycle:\n * 1. Server returns a 422; the serializer calls `store.errors.add(…)`.\n * 2. The UI reads `record.errors.get('email')` to display messages.\n * 3. The user corrects the field; `record.errors.remove('email')` clears it.\n * 4. A successful save calls `record.errors.clear()` to wipe all messages.\n */\n\nimport { injectable } from 'tsyringe';\nimport {\n makeObservable, observable, computed, action,\n} from 'mobx';\n\n/** A single validation error for one attribute. */\nexport interface ErrorMessage {\n /** Attribute name the error belongs to. */\n attribute: string;\n /** Human-readable error message. */\n message: string;\n}\n\n@injectable()\nexport class Errors implements Iterable<[string, ErrorMessage[]]> {\n private _errors: Map<string, ErrorMessage[]> = new Map();\n\n constructor() {\n makeObservable<this, '_errors'>(this, {\n _errors: observable.shallow,\n isEmpty: computed,\n length: computed,\n add: action,\n remove: action,\n clear: action,\n });\n }\n\n /** `true` when there are no validation errors. */\n get isEmpty(): boolean {\n return this._errors.size === 0;\n }\n\n /** Total number of error messages across all attributes. */\n get length(): number {\n let total = 0;\n for (const messages of this._errors.values()) {\n total += messages.length;\n }\n return total;\n }\n\n /** Returns all error messages for `attribute`, or an empty array. */\n get(attribute: string): ErrorMessage[] {\n return this._errors.get(attribute) ?? [];\n }\n\n /** Returns `true` when `attribute` has at least one error message. */\n has(attribute: string): boolean {\n const messages = this._errors.get(attribute);\n return !!messages && messages.length > 0;\n }\n\n /**\n * Appends one or more error messages for `attribute`.\n * Existing messages are preserved — this is an additive operation.\n */\n add(attribute: string, message: string | string[]): void {\n const incoming = Array.isArray(message) ? message : [message];\n const existing = this._errors.get(attribute) ?? [];\n const next: ErrorMessage[] = [\n ...existing,\n ...incoming.map((msg) => ({ attribute, message: msg })),\n ];\n this._errors.set(attribute, next);\n }\n\n /** Removes all error messages for `attribute`. */\n remove(attribute: string): void {\n this._errors.delete(attribute);\n }\n\n /** Removes all error messages for every attribute. */\n clear(): void {\n this._errors.clear();\n }\n\n /** Iterates `[attributeName, ErrorMessage[]]` pairs. */\n * [Symbol.iterator](): Iterator<[string, ErrorMessage[]]> {\n for (const entry of this._errors.entries()) {\n yield entry;\n }\n }\n}\n","/**\n * Finite-state machine that tracks the lifecycle of a single model record.\n *\n * States are organised in a dot-separated hierarchy that mirrors Ember Data's\n * record state machine. The transition table (`TABLE`) is the single source\n * of truth; illegal transitions throw immediately rather than silently\n * degrading into an unexpected state.\n *\n * State hierarchy overview:\n * ```\n * root.empty\n * root.loading\n * root.loaded\n * .saved\n * .created.uncommitted ← new record, not yet sent to server\n * .created.inFlight ← POST in progress\n * .updated.uncommitted ← dirty record, not yet sent to server\n * .updated.inFlight ← PUT/PATCH in progress\n * root.deleted\n * .uncommitted ← deleteRecord() called locally\n * .inFlight ← DELETE in progress\n * .saved ← server confirmed deletion\n * root.error ← adapter threw an unrecoverable error\n * ```\n *\n * `current` is MobX-observable so computed properties that depend on\n * `isNew`, `isDirty`, etc. react automatically.\n */\n\nimport { makeObservable, observable, action } from 'mobx';\n\n/** All valid states the record can be in. */\nexport type RecordState =\n | 'root.empty'\n | 'root.loading'\n | 'root.loaded.saved'\n | 'root.loaded.created.uncommitted'\n | 'root.loaded.created.inFlight'\n | 'root.loaded.updated.uncommitted'\n | 'root.loaded.updated.inFlight'\n | 'root.deleted.uncommitted'\n | 'root.deleted.inFlight'\n | 'root.deleted.saved'\n | 'root.error';\n\n/** Events that trigger state transitions. */\nexport type RecordEvent =\n | 'loadingData'\n | 'pushedData'\n | 'becameError'\n | 'didSetProperty'\n | 'willCommit'\n | 'didCommit'\n | 'becameInvalid'\n | 'deleteRecord'\n | 'rolledBack'\n | 'unloadRecord';\n\n/** Per-state map of allowed events → destination states. */\ntype Transitions = Partial<Record<RecordEvent, RecordState>>;\n\n/** Complete transition table. A missing entry means the transition is invalid. */\nconst TABLE: Record<RecordState, Transitions> = {\n 'root.empty': {\n loadingData: 'root.loading',\n pushedData: 'root.loaded.saved',\n },\n 'root.loading': {\n pushedData: 'root.loaded.saved',\n becameError: 'root.error',\n },\n 'root.loaded.saved': {\n didSetProperty: 'root.loaded.updated.uncommitted',\n deleteRecord: 'root.deleted.uncommitted',\n loadingData: 'root.loading',\n pushedData: 'root.loaded.saved',\n unloadRecord: 'root.empty',\n },\n 'root.loaded.created.uncommitted': {\n willCommit: 'root.loaded.created.inFlight',\n rolledBack: 'root.empty',\n deleteRecord: 'root.deleted.uncommitted',\n didSetProperty: 'root.loaded.created.uncommitted',\n unloadRecord: 'root.empty',\n },\n 'root.loaded.created.inFlight': {\n didCommit: 'root.loaded.saved',\n becameInvalid: 'root.loaded.created.uncommitted',\n becameError: 'root.error',\n },\n 'root.loaded.updated.uncommitted': {\n willCommit: 'root.loaded.updated.inFlight',\n rolledBack: 'root.loaded.saved',\n didSetProperty: 'root.loaded.updated.uncommitted',\n deleteRecord: 'root.deleted.uncommitted',\n unloadRecord: 'root.empty',\n },\n 'root.loaded.updated.inFlight': {\n didCommit: 'root.loaded.saved',\n becameInvalid: 'root.loaded.updated.uncommitted',\n becameError: 'root.error',\n },\n 'root.deleted.uncommitted': {\n willCommit: 'root.deleted.inFlight',\n rolledBack: 'root.loaded.saved',\n unloadRecord: 'root.empty',\n },\n 'root.deleted.inFlight': {\n didCommit: 'root.deleted.saved',\n becameError: 'root.error',\n },\n 'root.deleted.saved': {\n unloadRecord: 'root.empty',\n },\n 'root.error': {\n rolledBack: 'root.loaded.saved',\n unloadRecord: 'root.empty',\n },\n};\n\nexport class StateMachine {\n /** The current state of the record. Observable so computed props react. */\n current: RecordState;\n\n constructor(initial: RecordState = 'root.empty') {\n this.current = initial;\n makeObservable(this, {\n current: observable,\n transition: action,\n });\n }\n\n /**\n * Applies `event` to the current state, updates `current`, and returns the\n * new state.\n *\n * @throws `Error` when `event` is not permitted from the current state.\n */\n transition(event: RecordEvent): RecordState {\n const next = TABLE[this.current][event];\n if (!next) {\n throw new Error(\n `Invalid transition: event \"${event}\" not allowed from state \"${this.current}\"`,\n );\n }\n this.current = next;\n return next;\n }\n}\n","/**\n * Immutable point-in-time view of a model record.\n *\n * A `Snapshot` is created immediately before an adapter call so that adapter\n * and serializer code reads a consistent, frozen picture of the record\n * regardless of mutations that happen after the call begins.\n *\n * Key guarantees:\n * - Attribute data is copied at construction time; later record mutations do\n * not bleed into the snapshot.\n * - Relationship data is captured via a `Map` copy for the same reason.\n * - `changedAttributes()` compares the snapshot-time data against the\n * record's original (server-received) data, not the current live state.\n * - `eachAttribute` / `eachRelationship` iterate the merged schema definitions\n * walked at construction from the prototype chain.\n */\n\nimport 'reflect-metadata';\nimport {\n ATTRIBUTES_META_KEY,\n RELATIONSHIPS_META_KEY,\n type AttributeDef,\n type RelationshipDef,\n} from '@mobx-data/schema';\nimport type { Model, RelationshipRef } from './Model.js';\n\n/** Shape of a serialised `belongsTo` reference as stored in a snapshot. */\nexport interface BelongsToReference {\n id: string | null;\n type: string;\n}\n\n/** Shape of a serialised `hasMany` item reference as stored in a snapshot. */\nexport interface HasManyReference {\n id: string;\n type: string;\n}\n\n/**\n * Walks the prototype chain from root to leaf, merging own-metadata entries\n * so that subclass definitions override parent definitions.\n */\nfunction walk<V>(proto: object | null, key: symbol): Map<string, V> {\n const chain: object[] = [];\n let current: object | null = proto;\n while (current && current !== Object.prototype) {\n chain.push(current);\n current = Object.getPrototypeOf(current);\n }\n const merged = new Map<string, V>();\n for (const entry of chain.reverse()) {\n const local = Reflect.getOwnMetadata(key, entry) as Map<string, V> | undefined;\n if (local) {\n for (const [name, meta] of local) {\n merged.set(name, meta);\n }\n }\n }\n return merged;\n}\n\nexport class Snapshot<T extends Model = Model> {\n /** Server-assigned id at snapshot time, or `null` for new records. */\n readonly id: string | null;\n /** `modelName` of the snapshotted record. */\n readonly modelName: string;\n /** Reference to the live record (read-only from adapter/serializer code). */\n readonly record: T;\n\n private readonly _attributes: Record<string, unknown>;\n private readonly _relationships: Map<string, RelationshipRef>;\n private readonly _changedAttributes: Record<string, [unknown, unknown]>;\n private readonly _attributeDefinitions: Map<string, AttributeDef>;\n private readonly _relationshipDefinitions: Map<string, RelationshipDef>;\n\n constructor(record: T) {\n this.record = record;\n this.id = record.id;\n this.modelName = record.modelName;\n\n const internal = record as unknown as {\n _data: Record<string, unknown>;\n _relationships: Map<string, RelationshipRef>;\n };\n // Freeze a copy so later record mutations don't bleed in.\n this._attributes = { ...internal._data };\n this._relationships = new Map(internal._relationships);\n this._changedAttributes = record.changedAttributes();\n\n const proto = Object.getPrototypeOf(record) as object;\n this._attributeDefinitions = walk<AttributeDef>(proto, ATTRIBUTES_META_KEY);\n this._relationshipDefinitions = walk<RelationshipDef>(proto, RELATIONSHIPS_META_KEY);\n }\n\n /** Returns the snapshot-time value for an attribute key. */\n attr<K extends keyof T>(key: K): T[K] {\n return this._attributes[key as string] as T[K];\n }\n\n /**\n * Returns the `belongsTo` reference for `key`.\n * When `{ id: true }` is passed, returns only the id string; otherwise\n * returns a `BelongsToReference` `{ id, type }` object, or `null` when the\n * relationship is empty.\n */\n belongsTo(\n key: string,\n options?: { id: boolean },\n ): BelongsToReference | string | null {\n const relationship = this._relationships.get(key);\n if (!relationship || relationship.data === null) {\n return null;\n }\n const data = relationship.data as { id: string; type: string };\n if (options?.id) {\n return data.id;\n }\n return { id: data.id, type: data.type };\n }\n\n /**\n * Returns the `hasMany` references for `key`.\n * When `{ ids: true }` is passed, returns a plain string array of ids;\n * otherwise returns an array of `HasManyReference` objects.\n */\n hasMany(\n key: string,\n options?: { ids: boolean },\n ): HasManyReference[] | string[] {\n const relationship = this._relationships.get(key);\n if (!relationship || !Array.isArray(relationship.data)) {\n return [];\n }\n const list = relationship.data as Array<{ id: string; type: string }>;\n if (options?.ids) {\n return list.map((reference) => reference.id);\n }\n return list.map((reference) => ({ id: reference.id, type: reference.type }));\n }\n\n /**\n * Returns a `{ [key]: [original, current] }` map of attributes that\n * differ from the server-received values at snapshot time.\n */\n changedAttributes(): Record<string, [unknown, unknown]> {\n return { ...this._changedAttributes };\n }\n\n /** Iterates over every attribute definition, calling `callback` for each. */\n eachAttribute(callback: (key: string, meta: AttributeDef) => void): void {\n for (const [key, meta] of this._attributeDefinitions) {\n callback(key, meta);\n }\n }\n\n /** Iterates over every relationship definition, calling `callback` for each. */\n eachRelationship(callback: (key: string, meta: RelationshipDef) => void): void {\n for (const [key, meta] of this._relationshipDefinitions) {\n callback(key, meta);\n }\n }\n}\n","/**\n * Base class for all mobx-data model records.\n *\n * `Model` is an abstract MobX-observable class that manages the complete\n * lifecycle of a server-side resource. Subclasses declare their schema using\n * `@attr`, `@belongsTo`, and `@hasMany` decorators; `Model` automatically\n * installs observable getters/setters for each declaration the first time the\n * class is instantiated.\n *\n * ## State machine\n * Every record progresses through the states tracked by `StateMachine`:\n * - **empty** → initial placeholder state\n * - **loading** → adapter request in flight\n * - **loaded.saved** → clean, persisted record\n * - **loaded.created.uncommitted** → new, unsaved record\n * - **loaded.updated.uncommitted** → dirty, unsaved changes\n * - **deleted.*** → record marked for / undergoing deletion\n * - **error** → adapter threw a non-validation error\n *\n * ## Lifecycle hooks\n * Override `didLoad`, `didCreate`, `didUpdate`, `didDelete`, `willSave`,\n * `didSave`, `becameInvalid`, and `becameError` to react to state transitions.\n *\n * ## Store integration\n * Records are normally created and loaded through a `Store` instance. The\n * `store` property is set by the store after instantiation so that `save()`,\n * `reload()`, and `destroyRecord()` can delegate back to it.\n */\n\nimport 'reflect-metadata';\nimport {\n makeObservable,\n observable,\n computed,\n action,\n runInAction,\n} from 'mobx';\nimport {\n ATTRIBUTES_META_KEY,\n RELATIONSHIPS_META_KEY,\n type AttributeDef,\n type RelationshipDef,\n} from '@mobx-data/schema';\nimport { Errors } from './Errors.js';\nimport { StateMachine, type RecordState, type RecordEvent } from './StateMachine.js';\nimport { Snapshot } from './Snapshot.js';\n\n/**\n * Raw relationship reference stored on the record.\n * Contains either a single `{ type, id }` object (belongsTo),\n * an array of them (hasMany), or `null`.\n */\nexport interface RelationshipRef {\n data:\n | { type: string; id: string }\n | Array<{ type: string; id: string }>\n | null;\n}\n\n/**\n * Minimal store interface that `Model` uses to delegate persistence operations.\n * The full `Store` class satisfies this interface.\n */\nexport interface SaveOptions {\n patch?: boolean;\n adapterOptions?: Record<string, unknown>;\n}\n\nexport interface ModelStoreLike {\n saveRecord?<T extends Model>(record: T, options?: SaveOptions): Promise<T>;\n deleteRecord?<T extends Model>(record: T): Promise<T>;\n reloadRecord?<T extends Model>(record: T): Promise<T>;\n unloadRecord?(record: Model): void;\n peekRecord?<T extends Model = Model>(type: string, id: string): T | null;\n findRecord?<T extends Model = Model>(\n type: string,\n id: string,\n options?: unknown,\n ): Promise<T>;\n onRelationshipSet?(\n record: Model,\n relName: string,\n ref: RelationshipRef,\n ): void;\n resolveRelationship?(\n record: Model,\n name: string,\n meta: RelationshipDef,\n ): unknown;\n setRelationshipValue?(\n record: Model,\n name: string,\n meta: RelationshipDef,\n value: unknown,\n ): void;\n}\n\n/** Options accepted by the `Model` constructor. */\nexport interface ModelConstructorOptions {\n /** Server-assigned id, or `null` / `undefined` for new records. */\n id?: string | null;\n /** Initial attribute data. */\n data?: Record<string, unknown>;\n /** Initial relationship references. */\n relationships?: Record<string, RelationshipRef>;\n /** Store instance injected so records can delegate persistence. */\n store?: ModelStoreLike;\n}\n\n/** Options accepted by the static `Model.push` factory method. */\nexport interface PushOptions {\n id: string;\n data: Record<string, unknown>;\n relationships?: Record<string, RelationshipRef>;\n store?: ModelStoreLike;\n}\n\n/** Internal constructor options that include the initial state override. */\ninterface InternalOptions extends ModelConstructorOptions {\n __initialState?: RecordState;\n}\n\n/** Symbol used as a per-class flag to avoid reinstalling accessors. */\nconst ACCESSORS_INSTALLED = Symbol('mobx-data:accessors-installed');\n\n/**\n * Walks the prototype chain from root to leaf and merges own-metadata\n * entries, with subclass definitions overriding ancestors.\n */\nfunction walkProto<V>(\n proto: object | null,\n metadataKey: symbol,\n): Map<string, V> {\n const chain: object[] = [];\n let current: object | null = proto;\n while (current && current !== Object.prototype) {\n chain.push(current);\n current = Object.getPrototypeOf(current);\n }\n const merged = new Map<string, V>();\n for (const entry of chain.reverse()) {\n const local = Reflect.getOwnMetadata(metadataKey, entry) as\n | Map<string, V>\n | undefined;\n if (local) {\n for (const [name, value] of local) {\n merged.set(name, value);\n }\n }\n }\n return merged;\n}\n\n/**\n * Installs observable getters/setters on the class prototype for every\n * `@attr` and `@belongsTo` / `@hasMany` declaration.\n *\n * Run once per class (guarded by `ACCESSORS_INSTALLED`); subsequent\n * instantiations are a no-op.\n */\nfunction ensureAccessorsInstalled(klass: Function): void {\n const proto = klass.prototype as Record<PropertyKey, unknown> & {\n [ACCESSORS_INSTALLED]?: boolean;\n };\n if ((klass as unknown as Record<symbol, unknown>)[ACCESSORS_INSTALLED]) {\n return;\n }\n (klass as unknown as Record<symbol, unknown>)[ACCESSORS_INSTALLED] = true;\n\n const attrs = walkProto<AttributeDef>(proto as object, ATTRIBUTES_META_KEY);\n for (const [name] of attrs) {\n Object.defineProperty(proto, name, {\n get(this: Model) {\n return (this as unknown as { _data: Record<string, unknown> })._data[name];\n },\n set(this: Model, value: unknown) {\n (this as unknown as { _setAttribute(k: string, v: unknown): void })._setAttribute(\n name,\n value,\n );\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n const relationships = walkProto<RelationshipDef>(proto as object, RELATIONSHIPS_META_KEY);\n for (const [name, meta] of relationships) {\n Object.defineProperty(proto, name, {\n get(this: Model) {\n return (this as unknown as {\n _resolveRelationship(name: string, meta: RelationshipDef): unknown;\n })._resolveRelationship(name, meta);\n },\n set(this: Model, value: unknown) {\n (this as unknown as {\n _setRelationship(name: string, meta: RelationshipDef, value: unknown): void;\n })._setRelationship(name, meta, value);\n },\n configurable: true,\n enumerable: true,\n });\n }\n}\n\nexport abstract class Model {\n /** Registered model name — must be set as a static property on subclasses. */\n static modelName: string;\n\n /**\n * Factory method that creates an instance in the `root.loaded.saved` state\n * (i.e. as if freshly loaded from the server) and calls `didLoad()`.\n *\n * Used internally by `Store.pushResource` to avoid exposing the internal\n * `__initialState` option.\n */\n static push<T extends typeof Model>(\n this: T,\n opts: PushOptions,\n ): InstanceType<T> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const Klass = this as unknown as new (internalOpts: InternalOptions) => Model;\n const instance = new Klass({\n ...opts,\n __initialState: 'root.loaded.saved',\n });\n (instance as unknown as { didLoad(): void }).didLoad();\n return instance as InstanceType<T>;\n }\n\n // --- internal reactive state (prefixed with _) ---\n\n /** Current attribute values. Deep-observable so nested mutations are tracked. */\n protected _data: Record<string, unknown> = {};\n /** Snapshot of attribute values as last received from the server (dirty tracking baseline). */\n protected _originalData: Record<string, unknown> = {};\n /** Raw relationship references keyed by relationship name. */\n protected _relationships: Map<string, RelationshipRef> = new Map();\n /** Server-assigned id, or `null` for new records. */\n protected _id: string | null = null;\n /** Internal lifecycle state machine. */\n protected _stateMachine: StateMachine;\n\n /** Observable validation error collection. */\n readonly errors: Errors = new Errors();\n /** Reference to the owning store, injected at construction. */\n store?: ModelStoreLike;\n\n constructor(options: ModelConstructorOptions = {}) {\n const opts = options as InternalOptions;\n ensureAccessorsInstalled(this.constructor);\n\n this._id = opts.id ?? null;\n this.store = opts.store;\n this._stateMachine = new StateMachine(\n opts.__initialState ?? 'root.loaded.created.uncommitted',\n );\n\n const initialData = opts.data ? { ...opts.data } : {};\n this._data = initialData;\n // When pushed (clean), snapshot original for dirty tracking.\n if (opts.__initialState === 'root.loaded.saved') {\n this._originalData = { ...initialData };\n } else {\n this._originalData = {};\n }\n\n if (opts.relationships) {\n for (const [name, reference] of Object.entries(opts.relationships)) {\n this._relationships.set(name, reference);\n }\n }\n\n makeObservable<\n this,\n | '_data'\n | '_originalData'\n | '_relationships'\n | '_id'\n | '_setAttribute'\n | '_transitionIfClean'\n | '_applyServerData'\n | '_setState'\n >(this, {\n _data: observable.shallow,\n _originalData: observable.ref,\n _relationships: observable.shallow,\n _id: observable,\n id: computed,\n currentState: computed,\n isLoading: computed,\n isLoaded: computed,\n isSaving: computed,\n isDirty: computed,\n hasDirtyAttributes: computed,\n isNew: computed,\n isDeleted: computed,\n isValid: computed,\n isError: computed,\n isEmpty: computed,\n _setAttribute: action,\n _transitionIfClean: action,\n _applyServerData: action,\n _setState: action,\n rollbackAttributes: action,\n deleteRecord: action,\n });\n }\n\n /** Server-assigned id, or `null` for new records. */\n get id(): string | null {\n return this._id;\n }\n\n set id(v: string | null) {\n runInAction(() => {\n this._id = v;\n });\n }\n\n /** Returns the static `modelName` from the concrete subclass constructor. */\n get modelName(): string {\n return (this.constructor as typeof Model).modelName;\n }\n\n /** Current state-machine state string. */\n get currentState(): RecordState {\n return this._stateMachine.current;\n }\n\n /** `true` while an adapter request to fetch this record is in flight. */\n get isLoading(): boolean {\n return this.currentState === 'root.loading';\n }\n\n /** `true` when the record has been loaded (any `root.loaded.*` state). */\n get isLoaded(): boolean {\n return this.currentState.startsWith('root.loaded');\n }\n\n /** `true` while a create or update request is in flight. */\n get isSaving(): boolean {\n return this.currentState.endsWith('.inFlight');\n }\n\n /** `true` when the record was created locally and has never been saved. */\n get isNew(): boolean {\n return this.currentState.startsWith('root.loaded.created');\n }\n\n /** `true` when `deleteRecord()` has been called (regardless of server state). */\n get isDeleted(): boolean {\n return this.currentState.startsWith('root.deleted');\n }\n\n /** `true` when the record is in the `root.error` state. */\n get isError(): boolean {\n return this.currentState === 'root.error';\n }\n\n /** `true` when the record is in the `root.empty` placeholder state. */\n get isEmpty(): boolean {\n return this.currentState === 'root.empty';\n }\n\n /** `true` when any attribute differs from its last-saved value. */\n get hasDirtyAttributes(): boolean {\n const data = this._data;\n const original = this._originalData;\n for (const key of Object.keys(data)) {\n if (!Object.is(data[key], original[key])) {\n return true;\n }\n }\n for (const key of Object.keys(original)) {\n if (!(key in data)) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * `true` when the record needs to be saved — new, deleted (not yet\n * confirmed), or has dirty attributes.\n */\n get isDirty(): boolean {\n if (this.isNew) {\n return true;\n }\n if (this.isDeleted && this.currentState !== 'root.deleted.saved') {\n return true;\n }\n return this.hasDirtyAttributes;\n }\n\n /** `true` when `errors.isEmpty` — i.e. no validation errors are present. */\n get isValid(): boolean {\n return this.errors.isEmpty;\n }\n\n /**\n * Returns a `{ [key]: [original, current] }` map of attributes that differ\n * from the last server-received snapshot.\n */\n changedAttributes(): Record<string, [unknown, unknown]> {\n const changed: Record<string, [unknown, unknown]> = {};\n const keys = new Set([\n ...Object.keys(this._data),\n ...Object.keys(this._originalData),\n ]);\n for (const key of keys) {\n const current = this._data[key];\n const original = this._originalData[key];\n if (!Object.is(current, original)) {\n changed[key] = [original, current];\n }\n }\n return changed;\n }\n\n /**\n * Resets all attributes to their original server values and clears\n * validation errors. For new records the record is transitioned to\n * `root.empty` and unloaded from the store.\n */\n rollbackAttributes(): void {\n this._data = { ...this._originalData };\n this.errors.clear();\n if (this.isNew) {\n this._setState('root.empty');\n if (this.store?.unloadRecord) {\n this.store.unloadRecord(this);\n }\n return;\n }\n if (this.currentState === 'root.loaded.updated.uncommitted') {\n this._stateMachine.transition('rolledBack');\n } else if (this.currentState === 'root.deleted.uncommitted') {\n this._stateMachine.transition('rolledBack');\n }\n }\n\n /**\n * Persists the record to the server. No-ops if the record is not dirty.\n * Delegates to `store.saveRecord`.\n *\n * @throws when no store is attached.\n */\n async save(\n options: SaveOptions = {},\n ): Promise<this> {\n if (!this.isDirty) {\n return this;\n }\n if (!this.store?.saveRecord) {\n throw new Error('Cannot save: no store attached');\n }\n const wasNew = this.isNew;\n this.willSave();\n this._stateMachine.transition('willCommit');\n try {\n await this.store.saveRecord(this, options);\n // If the store didn't already finalize the record, do it here.\n if (\n this.currentState === 'root.loaded.created.inFlight'\n || this.currentState === 'root.loaded.updated.inFlight'\n ) {\n runInAction(() => {\n this._originalData = { ...this._data };\n this._stateMachine.transition('didCommit');\n });\n }\n if (wasNew) {\n this.didCreate();\n } else {\n this.didUpdate();\n }\n this.didSave();\n return this;\n } catch (error) {\n if (!this.errors.isEmpty) {\n this._stateMachine.transition('becameInvalid');\n this.becameInvalid();\n } else {\n this._stateMachine.transition('becameError');\n this.becameError();\n }\n throw error;\n }\n }\n\n /**\n * Reloads the record from the server.\n * @throws when no store is attached.\n */\n async reload(): Promise<this> {\n if (!this.store?.reloadRecord) {\n throw new Error('Cannot reload: no store attached');\n }\n return (await this.store.reloadRecord(this)) as this;\n }\n\n /**\n * Marks the record for deletion. The record moves to\n * `root.deleted.uncommitted` but is not yet removed from the server.\n * Call `destroyRecord()` to also issue the DELETE request.\n */\n deleteRecord(): void {\n if (this.isNew) {\n this._setState('root.deleted.uncommitted');\n } else {\n this._stateMachine.transition('deleteRecord');\n }\n }\n\n /**\n * Marks the record for deletion and immediately sends a DELETE request.\n * @throws when no store is attached.\n */\n async destroyRecord(): Promise<this> {\n this.deleteRecord();\n if (!this.store?.deleteRecord) {\n throw new Error('Cannot destroy: no store attached');\n }\n this._stateMachine.transition('willCommit');\n const result = (await this.store.deleteRecord(this)) as this;\n if (this.currentState === 'root.deleted.inFlight') {\n this._stateMachine.transition('didCommit');\n }\n this.didDelete();\n return result;\n }\n\n /** Removes the record from the store's identity map without a server call. */\n unloadRecord(): void {\n if (this.store?.unloadRecord) {\n this.store.unloadRecord(this);\n }\n }\n\n /** Creates a frozen `Snapshot` of the current record state. */\n createSnapshot(): Snapshot<this> {\n return new Snapshot(this);\n }\n\n /** Returns a plain-object representation of the current attribute data. */\n serialize(_options: { includeId?: boolean } = {}): Record<string, unknown> {\n return { ...this._data };\n }\n\n /** Returns `{ id, ...attributes }` — used by `JSON.stringify`. */\n toJSON(): Record<string, unknown> {\n return { id: this._id, ...this._data };\n }\n\n // Lifecycle hooks — default no-ops, overridable.\n\n /** Called after the record is loaded from the server. */\n didLoad(): void {}\n /** Called after a new record is successfully persisted. */\n didCreate(): void {}\n /** Called after an existing record is successfully updated. */\n didUpdate(): void {}\n /** Called after a record is successfully deleted. */\n didDelete(): void {}\n /** Called immediately before a save request is issued. */\n willSave(): void {}\n /** Called after any successful save (create or update). */\n didSave(): void {}\n /** Called when the server returns a 422-style validation error. */\n becameInvalid(): void {}\n /** Called when the server returns a non-validation error. */\n becameError(): void {}\n\n // --- internals ---\n\n /** Called by generated attribute setters. */\n protected _setAttribute(key: string, value: unknown): void {\n if (Object.is(this._data[key], value)) {\n return;\n }\n this._data[key] = value;\n this._transitionIfClean();\n }\n\n /**\n * Transitions to `updated.uncommitted` when the record becomes dirty, or\n * back to `saved` when all changes are rolled back.\n */\n protected _transitionIfClean(): void {\n const dirty = this.hasDirtyAttributes;\n if (dirty && this.currentState === 'root.loaded.saved') {\n this._stateMachine.transition('didSetProperty');\n } else if (!dirty && this.currentState === 'root.loaded.updated.uncommitted') {\n this._stateMachine.transition('rolledBack');\n }\n }\n\n /** Directly sets the state machine's current state (bypasses transition validation). */\n protected _setState(state: RecordState): void {\n this._stateMachine.current = state;\n }\n\n /** Fires a state-machine transition event. */\n protected _transition(event: RecordEvent): void {\n this._stateMachine.transition(event);\n }\n\n /** Used by Store to apply server data after save, making record clean again. */\n protected _applyServerData(\n id: string | null,\n data: Record<string, unknown>,\n relationships?: Record<string, RelationshipRef>,\n ): void {\n if (id !== null) {\n this._id = id;\n }\n this._data = { ...this._data, ...data };\n this._originalData = { ...this._data };\n this.errors.clear();\n if (relationships) {\n for (const [name, reference] of Object.entries(relationships)) {\n this._relationships.set(name, reference);\n }\n }\n if (this.currentState === 'root.loaded.created.inFlight') {\n this._stateMachine.transition('didCommit');\n this.didCreate();\n } else if (this.currentState === 'root.loaded.updated.inFlight') {\n this._stateMachine.transition('didCommit');\n this.didUpdate();\n } else if (this.currentState === 'root.deleted.inFlight') {\n this._stateMachine.transition('didCommit');\n } else if (this.currentState === 'root.loading') {\n this._stateMachine.transition('pushedData');\n }\n // If pushed externally to a created/updated record, reset to saved.\n if (\n !this.isNew\n && !this.isDeleted\n && (this.currentState === 'root.loaded.updated.uncommitted'\n || this.currentState === 'root.loaded.created.uncommitted')\n ) {\n this._setState('root.loaded.saved');\n }\n }\n\n /** Relationship data (reference only). Resolution to records lives in Store. */\n protected _getRelationshipRef(name: string): RelationshipRef | null {\n return this._relationships.get(name) ?? null;\n }\n\n /** Stores a raw relationship reference without triggering store logic. */\n protected _setRelationshipRef(name: string, ref: RelationshipRef): void {\n this._relationships.set(name, ref);\n }\n\n /**\n * Delegates relationship resolution to the store.\n * Returns `null` when no store is attached (e.g. in unit tests).\n */\n protected _resolveRelationship(\n name: string,\n meta: RelationshipDef,\n ): unknown {\n if (this.store?.resolveRelationship) {\n return this.store.resolveRelationship(this, name, meta);\n }\n return null;\n }\n\n /** Delegates relationship mutation to the store (which also handles inverse sync). */\n protected _setRelationship(\n name: string,\n meta: RelationshipDef,\n value: unknown,\n ): void {\n if (this.store?.setRelationshipValue) {\n this.store.setRelationshipValue(this, name, meta, value);\n }\n }\n}\n","/**\n * Relationship proxy classes returned by relationship getters on Model instances.\n *\n * Three classes are exported:\n *\n * - `ManyArray<T>` — a synchronous, MobX-observable live view of a `hasMany`\n * relationship. Its contents are resolved directly from the store's identity\n * map on each access, so it stays in sync automatically as records are\n * pushed, unloaded, or added/removed via `push` / `removeObject`.\n *\n * - `AsyncBelongsTo<T>` — a `PromiseLike` wrapper for a `belongsTo` that\n * may need to be fetched from the server. Supports `await`, `then`, and\n * MobX-observable state flags (`isLoading`, `isLoaded`, `isFulfilled`,\n * `isRejected`, `value`).\n *\n * - `AsyncHasMany<T>` — same semantics as `AsyncBelongsTo` but resolves to a\n * `ManyArray<T>` instead of a single record.\n *\n * Both async wrappers eagerly check the store cache on construction; if all\n * referenced records are already present they transition to `fulfilled`\n * without issuing any network requests.\n */\n\nimport {\n makeObservable, observable, computed, action, runInAction,\n} from 'mobx';\nimport type { RelationshipDef } from '@mobx-data/schema';\nimport type { Model, ModelStoreLike, RelationshipRef } from './Model.js';\n\n/** Context object shared by all relationship proxy classes. */\nexport interface RelationshipHost {\n /** The record that owns the relationship. */\n parent: Model;\n /** Name of the relationship property on the owner. */\n name: string;\n /** Relationship definition from the schema. */\n meta: RelationshipDef;\n /** Store instance used to peek / find related records. */\n store: RelationshipCapableStore;\n}\n\n/**\n * Extended store interface required by the relationship proxy classes.\n * `Store` satisfies this interface.\n */\nexport interface RelationshipCapableStore extends ModelStoreLike {\n peekRecord<T extends Model = Model>(type: string, id: string): T | null;\n findRecord<T extends Model = Model>(\n type: string,\n id: string,\n options?: unknown,\n ): Promise<T>;\n _getRelationshipRefFor(record: Model, name: string): RelationshipRef | null;\n _getPendingMembers(record: Model, name: string): Iterable<Model>;\n _hasManyAppend(record: Model, name: string, meta: RelationshipDef, value: Model): void;\n _hasManyRemove(record: Model, name: string, meta: RelationshipDef, value: Model): void;\n}\n\n/**\n * Synchronous, live-updating array proxy for a `hasMany` relationship.\n *\n * Each access to `length`, iteration, or mutation goes through the store so\n * the array always reflects the current identity map state. Records that\n * have been `push`ed to the relationship but not yet assigned a server id\n * are tracked separately as \"pending members\" and are included in the\n * resolved list.\n */\nexport class ManyArray<T extends Model = Model> implements Iterable<T> {\n static refData(\n ref: RelationshipRef | null,\n ): Array<{ type: string; id: string }> {\n if (!ref || !ref.data) {\n return [];\n }\n return Array.isArray(ref.data) ? ref.data : [];\n }\n\n private host: RelationshipHost;\n\n constructor(host: RelationshipHost) {\n this.host = host;\n makeObservable<this, 'resolved'>(this, {\n resolved: computed,\n length: computed,\n push: action,\n removeObject: action,\n });\n }\n\n /**\n * Resolves the current set of related records from the store identity map.\n * Pending (unsaved) members appended via `push()` are appended at the end.\n */\n private get resolved(): T[] {\n const ref = this.host.store._getRelationshipRefFor(this.host.parent, this.host.name);\n const resolved: T[] = [];\n const seen = new Set<T>();\n for (const reference of ManyArray.refData(ref)) {\n const record = this.host.store.peekRecord<T>(reference.type, reference.id);\n if (record) {\n resolved.push(record);\n seen.add(record);\n }\n }\n const pending = this.host.store._getPendingMembers(\n this.host.parent,\n this.host.name,\n );\n for (const pendingRecord of pending as Iterable<T>) {\n if (!seen.has(pendingRecord)) {\n resolved.push(pendingRecord);\n }\n }\n return resolved;\n }\n\n /** Number of related records currently in the array. */\n get length(): number {\n return this.resolved.length;\n }\n\n /** Returns the record at `index`, or `undefined`. */\n at(index: number): T | undefined {\n return this.resolved[index];\n }\n\n /**\n * Adds one or more records to the relationship.\n * Delegates to `store._hasManyAppend` which also handles inverse tracking.\n */\n push(...records: T[]): number {\n for (const record of records) {\n this.host.store._hasManyAppend(\n this.host.parent,\n this.host.name,\n this.host.meta,\n record,\n );\n }\n return this.length;\n }\n\n /**\n * Removes a record from the relationship.\n * Delegates to `store._hasManyRemove` which also handles inverse tracking.\n */\n removeObject(record: T): void {\n this.host.store._hasManyRemove(\n this.host.parent,\n this.host.name,\n this.host.meta,\n record,\n );\n }\n\n /** Returns `true` when `record` is currently in the relationship. */\n includes(record: T): boolean {\n return this.resolved.includes(record);\n }\n\n /** Returns a plain array snapshot of all related records. */\n toArray(): T[] {\n return [...this.resolved];\n }\n\n /** Maps over the related records. */\n map<R>(callback: (record: T, i: number) => R): R[] {\n return this.resolved.map(callback);\n }\n\n /** Filters the related records. */\n filter(predicate: (record: T, i: number) => boolean): T[] {\n return this.resolved.filter(predicate);\n }\n\n /** Iterates over the related records. */\n forEach(callback: (record: T, i: number) => void): void {\n this.resolved.forEach(callback);\n }\n\n [Symbol.iterator](): Iterator<T> {\n return this.resolved[Symbol.iterator]();\n }\n}\n\n/**\n * Async wrapper for a `belongsTo` relationship.\n *\n * Implements `PromiseLike<T | null>` so it can be `await`ed. Also exposes\n * MobX-observable state flags:\n * - `isPending` / `isFulfilled` / `isRejected` — promise lifecycle\n * - `isLoading` — a network request is currently in flight\n * - `isLoaded` — the relationship has been resolved (even to `null`)\n * - `value` — the resolved record, or `null`\n * - `reason` — the rejection error, if any\n *\n * Eagerly checks the store cache at construction; if the referenced record is\n * already present it transitions straight to `fulfilled`.\n */\nexport class AsyncBelongsTo<T extends Model = Model>\nimplements PromiseLike<T | null> {\n private host: RelationshipHost;\n\n private loadedState: 'pending' | 'fulfilled' | 'rejected' = 'pending';\n\n private currentValue: T | null = null;\n\n private error: unknown = null;\n\n private inflight: Promise<T | null> | null = null;\n\n constructor(host: RelationshipHost) {\n this.host = host;\n makeObservable<this, 'loadedState' | 'currentValue' | 'error' | 'syncFromCache'>(this, {\n loadedState: observable,\n currentValue: observable.ref,\n error: observable.ref,\n isPending: computed,\n isFulfilled: computed,\n isRejected: computed,\n isLoaded: computed,\n isLoading: computed,\n value: computed,\n reason: computed,\n syncFromCache: action,\n });\n this.syncFromCache();\n }\n\n /** Checks the store cache and transitions to `fulfilled` if the record is already loaded. */\n private syncFromCache(): void {\n const ref = this.host.store._getRelationshipRefFor(this.host.parent, this.host.name);\n if (!ref || !ref.data || Array.isArray(ref.data)) {\n this.currentValue = null;\n this.loadedState = 'fulfilled';\n return;\n }\n const cached = this.host.store.peekRecord<T>(ref.data.type, ref.data.id);\n if (cached) {\n this.currentValue = cached;\n this.loadedState = 'fulfilled';\n }\n }\n\n /** `true` while the relationship has not yet been resolved. */\n get isPending(): boolean {\n return this.loadedState === 'pending';\n }\n\n /** `true` once the relationship has been resolved (including to `null`). */\n get isFulfilled(): boolean {\n return this.loadedState === 'fulfilled';\n }\n\n /** `true` if the network request failed. */\n get isRejected(): boolean {\n return this.loadedState === 'rejected';\n }\n\n /** `true` while a network request is in flight. */\n get isLoading(): boolean {\n return this.inflight !== null && this.isPending;\n }\n\n /** `true` once the relationship is resolved. */\n get isLoaded(): boolean {\n return this.loadedState === 'fulfilled';\n }\n\n /** The resolved record, or `null` when the relationship is empty or not yet loaded. */\n get value(): T | null {\n return this.currentValue;\n }\n\n /** The rejection reason if `isRejected`. */\n get reason(): unknown {\n return this.error;\n }\n\n /**\n * Ensures the related record is loaded, returning a `Promise<T | null>`.\n * If the record is already in the store it resolves immediately.\n * Concurrent calls share the same in-flight promise.\n */\n load(): Promise<T | null> {\n // Re-check cache each time in case it was populated externally.\n this.syncFromCache();\n if (this.loadedState === 'fulfilled' && this.currentValue) {\n return Promise.resolve(this.currentValue);\n }\n if (this.inflight) {\n return this.inflight;\n }\n const ref = this.host.store._getRelationshipRefFor(this.host.parent, this.host.name);\n if (!ref || !ref.data || Array.isArray(ref.data)) {\n return Promise.resolve(null);\n }\n const { type, id } = ref.data;\n this.inflight = this.host.store.findRecord<T>(type, id).then(\n (record) => {\n runInAction(() => {\n this.currentValue = record;\n this.loadedState = 'fulfilled';\n this.inflight = null;\n });\n return record;\n },\n (error) => {\n runInAction(() => {\n this.error = error;\n this.loadedState = 'rejected';\n this.inflight = null;\n });\n throw error;\n },\n );\n return this.inflight;\n }\n\n /** Forces a fresh fetch, ignoring any cached value. */\n reload(): Promise<T | null> {\n this.inflight = null;\n this.loadedState = 'pending';\n return this.load();\n }\n\n then<TResult1 = T | null, TResult2 = never>(\n onfulfilled?:\n | ((value: T | null) => TResult1 | PromiseLike<TResult1>)\n | null\n | undefined,\n onrejected?:\n | ((reason: unknown) => TResult2 | PromiseLike<TResult2>)\n | null\n | undefined,\n ): PromiseLike<TResult1 | TResult2> {\n return this.load().then(onfulfilled, onrejected);\n }\n}\n\n/**\n * Async wrapper for a `hasMany` relationship.\n *\n * Mirrors the `AsyncBelongsTo` API but resolves to a `ManyArray<T>` instead\n * of a single record. Missing referenced records are fetched in parallel via\n * `store.findRecord`.\n */\nexport class AsyncHasMany<T extends Model = Model>\nimplements PromiseLike<ManyArray<T>> {\n private host: RelationshipHost;\n\n private manyArray: ManyArray<T>;\n\n private loadedState: 'pending' | 'fulfilled' | 'rejected' = 'pending';\n\n private error: unknown = null;\n\n private inflight: Promise<ManyArray<T>> | null = null;\n\n constructor(host: RelationshipHost) {\n this.host = host;\n this.manyArray = new ManyArray<T>(host);\n makeObservable<this, 'loadedState' | 'error' | 'syncFromCache'>(this, {\n loadedState: observable,\n error: observable.ref,\n isPending: computed,\n isFulfilled: computed,\n isRejected: computed,\n isLoaded: computed,\n isLoading: computed,\n length: computed,\n syncFromCache: action,\n });\n this.syncFromCache();\n }\n\n /** Transitions to `fulfilled` if all referenced records are already in the cache. */\n private syncFromCache(): void {\n const ref = this.host.store._getRelationshipRefFor(this.host.parent, this.host.name);\n const items = ManyArray.refData(ref);\n const allCached = items.every(\n (reference) => this.host.store.peekRecord(reference.type, reference.id) !== null,\n );\n if (allCached) {\n this.loadedState = 'fulfilled';\n }\n }\n\n /** `true` while the relationship has not yet been resolved. */\n get isPending(): boolean {\n return this.loadedState === 'pending';\n }\n\n /** `true` once all referenced records have been resolved. */\n get isFulfilled(): boolean {\n return this.loadedState === 'fulfilled';\n }\n\n /** `true` if any fetch failed. */\n get isRejected(): boolean {\n return this.loadedState === 'rejected';\n }\n\n /** `true` while a network request is in flight. */\n get isLoading(): boolean {\n return this.inflight !== null && this.isPending;\n }\n\n /** `true` once the relationship is resolved. */\n get isLoaded(): boolean {\n return this.loadedState === 'fulfilled';\n }\n\n /** The underlying `ManyArray` (always available, even before `load()`). */\n get value(): ManyArray<T> {\n return this.manyArray;\n }\n\n /** Number of records currently in the resolved array. */\n get length(): number {\n return this.manyArray.length;\n }\n\n /**\n * Ensures all referenced records are loaded.\n * Records already in the cache are not re-fetched.\n * Concurrent calls share the same in-flight promise.\n */\n load(): Promise<ManyArray<T>> {\n this.syncFromCache();\n if (this.loadedState === 'fulfilled') {\n return Promise.resolve(this.manyArray);\n }\n if (this.inflight) {\n return this.inflight;\n }\n const ref = this.host.store._getRelationshipRefFor(this.host.parent, this.host.name);\n const items = ManyArray.refData(ref);\n const missing = items.filter(\n (reference) => this.host.store.peekRecord(reference.type, reference.id) === null,\n );\n const loads = missing.map(\n (reference) => this.host.store.findRecord(reference.type, reference.id),\n );\n this.inflight = Promise.all(loads).then(\n () => {\n runInAction(() => {\n this.loadedState = 'fulfilled';\n this.inflight = null;\n });\n return this.manyArray;\n },\n (error) => {\n runInAction(() => {\n this.error = error;\n this.loadedState = 'rejected';\n this.inflight = null;\n });\n throw error;\n },\n );\n return this.inflight;\n }\n\n /** Forces a fresh fetch, ignoring any cached state. */\n reload(): Promise<ManyArray<T>> {\n this.inflight = null;\n this.loadedState = 'pending';\n return this.load();\n }\n\n then<TResult1 = ManyArray<T>, TResult2 = never>(\n onfulfilled?:\n | ((value: ManyArray<T>) => TResult1 | PromiseLike<TResult1>)\n | null\n | undefined,\n onrejected?:\n | ((reason: unknown) => TResult2 | PromiseLike<TResult2>)\n | null\n | undefined,\n ): PromiseLike<TResult1 | TResult2> {\n return this.load().then(onfulfilled, onrejected);\n }\n}\n"],"names":["Errors","makeObservable","observable","computed","action","total","messages","attribute","message","incoming","next","msg","entry","__decorateClass","injectable","TABLE","StateMachine","initial","event","walk","proto","key","chain","current","merged","local","name","meta","Snapshot","record","internal","ATTRIBUTES_META_KEY","RELATIONSHIPS_META_KEY","options","relationship","data","list","reference","callback","ACCESSORS_INSTALLED","walkProto","metadataKey","value","ensureAccessorsInstalled","klass","attrs","relationships","Model","opts","initialData","Klass","instance","v","runInAction","original","changed","keys","_a","wasNew","error","result","_options","dirty","state","id","ref","ManyArray","host","resolved","seen","pending","pendingRecord","index","records","predicate","AsyncBelongsTo","cached","type","onfulfilled","onrejected","AsyncHasMany","loads"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * In-memory caching handler for the request pipeline.
3
+ *
4
+ * `CacheHandler` is registered via `RequestManager.useCache()` so it always
5
+ * runs first in the chain. It caches `GET` responses and replays them on
6
+ * subsequent requests with the same key — unless `cacheOptions.reload: true`
7
+ * is set, in which case it bypasses the cache and stores the fresh response.
8
+ *
9
+ * Cache key: `cacheOptions.key` when provided, otherwise `"<METHOD> <URL>"`.
10
+ *
11
+ * Only `GET` requests are cached; mutations (POST, PUT, PATCH, DELETE) are
12
+ * always forwarded to `next` without touching the cache.
13
+ *
14
+ * Usage:
15
+ * ```ts
16
+ * const manager = new RequestManager()
17
+ * .useCache(new CacheHandler())
18
+ * .use(new FetchHandler());
19
+ * ```
20
+ */
21
+ import type { Handler, NextFn, RequestContext, StoreRequest, StoreResponse } from './types.js';
22
+ export declare class CacheHandler implements Handler {
23
+ private cache;
24
+ maxSize: number;
25
+ ttl: number;
26
+ private isExpired;
27
+ private evictLRU;
28
+ static keyFor(req: StoreRequest): string;
29
+ static isCacheable(req: StoreRequest): boolean;
30
+ /**
31
+ * Handles a request by checking the in-memory cache before forwarding to
32
+ * the next handler.
33
+ *
34
+ * - Non-GET requests skip the cache entirely.
35
+ * - `cacheOptions.reload: true` forces a network request and refreshes the entry.
36
+ * - Cached entries expire after `ttl` milliseconds (default 5 minutes).
37
+ * - The cache uses LRU eviction when it exceeds `maxSize` entries (default 256).
38
+ */
39
+ request<T = unknown>(context: RequestContext<T>, next: NextFn<T>): Promise<StoreResponse<T>>;
40
+ /** Returns the number of entries currently in the cache. */
41
+ get size(): number;
42
+ /** Removes all entries from the cache. */
43
+ clear(): void;
44
+ /**
45
+ * Removes a single entry by key.
46
+ * @returns `true` when the entry existed and was deleted.
47
+ */
48
+ delete(key: string): boolean;
49
+ }
50
+ //# sourceMappingURL=CacheHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CacheHandler.d.ts","sourceRoot":"","sources":["../../src/request/CacheHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,cAAc,EACd,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AAOpB,qBACa,YAAa,YAAW,OAAO;IAC1C,OAAO,CAAC,KAAK,CAAiC;IAE9C,OAAO,EAAE,MAAM,CAAO;IAEtB,GAAG,EAAE,MAAM,CAAW;IAEtB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,QAAQ;IAWhB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;IAIxC,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO;IAI9C;;;;;;;;OAQG;IACG,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GACd,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;IA6B5B,4DAA4D;IAC5D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAIb;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG7B"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Terminal request handler that executes HTTP calls via the browser / Node
3
+ * `fetch` API.
4
+ *
5
+ * `FetchHandler` is designed to sit at the end of the `RequestManager` chain.
6
+ * It does not call `next` — it issues the network request and returns the
7
+ * parsed response directly.
8
+ *
9
+ * Response body parsing:
10
+ * - `204 No Content` or `Content-Length: 0` → `null`
11
+ * - `application/json` or `application/vnd.api+json` → parsed JSON (falls
12
+ * back to raw text if parsing fails)
13
+ * - Everything else → raw text string
14
+ *
15
+ * Error handling:
16
+ * - Non-2xx responses throw a `FetchError` that includes `status`, `content`,
17
+ * and `headers` for downstream error handling.
18
+ */
19
+ import type { Handler, NextFn, RequestContext, StoreResponse } from './types.js';
20
+ /**
21
+ * Error thrown by `FetchHandler` for non-2xx HTTP responses.
22
+ * Carries the status code, parsed body content, and response headers.
23
+ */
24
+ export declare class FetchError extends Error {
25
+ readonly status: number;
26
+ readonly content: unknown;
27
+ readonly headers: Record<string, string>;
28
+ constructor(status: number, content: unknown, headers: Record<string, string>, message?: string);
29
+ }
30
+ export declare class FetchHandler implements Handler {
31
+ static headersToObject(headers: Headers): Record<string, string>;
32
+ static parseBody(response: Response): Promise<unknown>;
33
+ /**
34
+ * Issues the HTTP request and returns a `StoreResponse`.
35
+ * This is a terminal handler — it never calls `next`.
36
+ *
37
+ * @throws `FetchError` on non-2xx responses.
38
+ */
39
+ request<T = unknown>(context: RequestContext<T>, _next: NextFn<T>): Promise<StoreResponse<T>>;
40
+ }
41
+ //# sourceMappingURL=FetchHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FetchHandler.d.ts","sourceRoot":"","sources":["../../src/request/FetchHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EACV,OAAO,EACP,MAAM,EACN,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAEvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,OAAO,CAAC,EAAE,MAAM;CAOnB;AAED,qBACa,YAAa,YAAW,OAAO;IAC1C,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;WAQnD,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB5D;;;;;OAKG;IACG,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CA2B7B"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Middleware-style manager that runs a `StoreRequest` through an ordered chain
3
+ * of `Handler` instances.
4
+ *
5
+ * Handlers are invoked in registration order. Each handler receives a
6
+ * `RequestContext` and a `next` function; it may:
7
+ * - Call `next(request)` to pass control to the next handler.
8
+ * - Return a `StoreResponse` directly to short-circuit the chain.
9
+ * - Wrap `next` to inspect or transform the response (e.g. logging).
10
+ *
11
+ * An optional *cache handler* registered via `useCache()` is always prepended
12
+ * to the chain so it runs before every other handler.
13
+ *
14
+ * Usage:
15
+ * ```ts
16
+ * const manager = new RequestManager()
17
+ * .useCache(new CacheHandler())
18
+ * .use([new AuthHandler(), new FetchHandler()]);
19
+ *
20
+ * const response = await manager.request({ method: 'GET', url: '/posts' });
21
+ * ```
22
+ */
23
+ import type { Handler, StoreRequest, StoreResponse } from './types.js';
24
+ export declare class RequestManager {
25
+ private _handlers;
26
+ private _cache;
27
+ /**
28
+ * Appends one or more handlers to the pipeline.
29
+ * Returns `this` for chaining.
30
+ */
31
+ use(handlers: Handler[] | Handler): this;
32
+ /**
33
+ * Registers the cache handler. It is always inserted at the front of
34
+ * the chain so it can intercept requests before any other handler sees them.
35
+ * Returns `this` for chaining.
36
+ */
37
+ useCache(handler: Handler): this;
38
+ /** All non-cache handlers in registration order. */
39
+ get handlers(): readonly Handler[];
40
+ /** The registered cache handler, or `null`. */
41
+ get cacheHandler(): Handler | null;
42
+ /**
43
+ * Executes `request` through the full handler chain and returns the final
44
+ * `StoreResponse`.
45
+ *
46
+ * @throws when no handlers have been registered.
47
+ * @throws when the chain ends without any handler returning a response
48
+ * (i.e. no terminal handler such as `FetchHandler`).
49
+ */
50
+ request<T = unknown>(request: StoreRequest): Promise<StoreResponse<T>>;
51
+ }
52
+ //# sourceMappingURL=RequestManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestManager.d.ts","sourceRoot":"","sources":["../../src/request/RequestManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EACV,OAAO,EAGP,YAAY,EACZ,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,qBACa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,MAAM,CAAwB;IAEtC;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,GAAG,IAAI;IASxC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKhC,oDAAoD;IACpD,IAAI,QAAQ,IAAI,SAAS,OAAO,EAAE,CAEjC;IAED,+CAA+C;IAC/C,IAAI,YAAY,IAAI,OAAO,GAAG,IAAI,CAEjC;IAED;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;CAiC7E"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../CacheHandler-CXgY9IJo.cjs");Object.defineProperty(exports,"CacheHandler",{enumerable:!0,get:()=>e.CacheHandler});Object.defineProperty(exports,"FetchHandler",{enumerable:!0,get:()=>e.FetchHandler});Object.defineProperty(exports,"RequestManager",{enumerable:!0,get:()=>e.RequestManager});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ export * from './types.js';
2
+ export { RequestManager } from './RequestManager.js';
3
+ export { FetchHandler } from './FetchHandler.js';
4
+ export { CacheHandler } from './CacheHandler.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/request/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { C as r, F as s, R as n } from "../CacheHandler-BTU_rYkv.js";
2
+ export {
3
+ r as CacheHandler,
4
+ s as FetchHandler,
5
+ n as RequestManager
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Shared type definitions for the request pipeline.
3
+ *
4
+ * The request pipeline models each network call as a `StoreRequest` flowing
5
+ * through a chain of `Handler` instances. Each handler can inspect, mutate,
6
+ * or short-circuit the request before passing it to `next`.
7
+ *
8
+ * Flow:
9
+ * ```
10
+ * RequestManager.request(StoreRequest)
11
+ * → CacheHandler.request(context, next)
12
+ * → FetchHandler.request(context, next) ← terminal
13
+ * ```
14
+ */
15
+ /** HTTP methods supported by the request pipeline. */
16
+ export type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE' | 'HEAD' | 'OPTIONS';
17
+ /** Store-level operation that triggered this request. */
18
+ export type RequestOp = 'findRecord' | 'findAll' | 'findMany' | 'query' | 'queryRecord' | 'createRecord' | 'updateRecord' | 'deleteRecord' | 'custom';
19
+ /** Stable identifier for a record — type + id pair. */
20
+ export interface RecordIdentifier {
21
+ /** Model name. */
22
+ type: string;
23
+ /** Server-assigned id, or `null` for new records. */
24
+ id: string | null;
25
+ /** Optional local id for identity tracking before the server assigns an id. */
26
+ lid?: string;
27
+ }
28
+ /**
29
+ * A fully-described outgoing HTTP request.
30
+ *
31
+ * Passed to the first handler in the chain and forwarded (possibly mutated)
32
+ * to subsequent handlers via `next`.
33
+ */
34
+ export interface StoreRequest {
35
+ /** HTTP method. */
36
+ method: HttpMethod;
37
+ /** Fully-qualified URL. */
38
+ url: string;
39
+ /** HTTP headers. */
40
+ headers?: Record<string, string>;
41
+ /** Request body. `null` / `undefined` = no body. */
42
+ body?: string | FormData | Blob | ArrayBuffer | null;
43
+ /** Store operation that initiated this request. */
44
+ op?: RequestOp;
45
+ /** Records involved in this request (for cache invalidation, etc.). */
46
+ records?: RecordIdentifier[];
47
+ /** Store reference — passed through so handlers can access it if needed. */
48
+ store?: unknown;
49
+ /** Cache behavior overrides. */
50
+ cacheOptions?: {
51
+ /** When `true`, bypass the cache and always hit the network. */
52
+ reload?: boolean;
53
+ /** When `true`, return the cached value and refetch in the background. */
54
+ backgroundReload?: boolean;
55
+ /** Custom cache key. Defaults to `"${method} ${url}"`. */
56
+ key?: string;
57
+ };
58
+ /** `AbortSignal` for request cancellation. */
59
+ signal?: AbortSignal;
60
+ /** Arbitrary additional metadata forwarded to handlers. */
61
+ [key: string]: unknown;
62
+ }
63
+ /** The response produced by the terminal handler and returned up the chain. */
64
+ export interface StoreResponse<T = unknown> {
65
+ /** Parsed response body. */
66
+ content: T;
67
+ /** HTTP status code. */
68
+ status?: number;
69
+ /** Response headers. */
70
+ headers?: Record<string, string>;
71
+ /** The originating request. */
72
+ request?: StoreRequest;
73
+ }
74
+ /**
75
+ * Context object passed to each handler.
76
+ * Handlers read `request`, may call `setResponse` to stash an intermediate
77
+ * result, and call `next` to forward to the next handler.
78
+ */
79
+ export interface RequestContext<T = unknown> {
80
+ /** The current request (may have been mutated by earlier handlers). */
81
+ request: StoreRequest;
82
+ /** Response set by a previous handler, if any. */
83
+ response?: StoreResponse<T>;
84
+ /** Allows a handler to record the response without ending the chain. */
85
+ setResponse(response: StoreResponse<T>): void;
86
+ }
87
+ /**
88
+ * Function passed to each handler that invokes the next handler in the chain.
89
+ * Handlers call `next(request)` to continue, or return a response directly to
90
+ * short-circuit remaining handlers.
91
+ */
92
+ export type NextFn<T = unknown> = (request: StoreRequest) => Promise<StoreResponse<T>>;
93
+ /**
94
+ * Interface that every request handler must implement.
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * class LoggingHandler implements Handler {
99
+ * async request(context, next) {
100
+ * console.log('→', context.request.method, context.request.url);
101
+ * const response = await next(context.request);
102
+ * console.log('←', response.status);
103
+ * return response;
104
+ * }
105
+ * }
106
+ * ```
107
+ */
108
+ export interface Handler<T = unknown> {
109
+ request(context: RequestContext<T>, next: NextFn<T>): Promise<StoreResponse<T>> | StoreResponse<T>;
110
+ }
111
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/request/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,sDAAsD;AACtD,MAAM,MAAM,UAAU,GAClB,KAAK,GACL,MAAM,GACN,OAAO,GACP,KAAK,GACL,QAAQ,GACR,MAAM,GACN,SAAS,CAAC;AAEd,yDAAyD;AACzD,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,SAAS,GACT,UAAU,GACV,OAAO,GACP,aAAa,GACb,cAAc,GACd,cAAc,GACd,cAAc,GACd,QAAQ,CAAC;AAEb,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,mBAAmB;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,2BAA2B;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAAC;IACrD,mDAAmD;IACnD,EAAE,CAAC,EAAE,SAAS,CAAC;IACf,uEAAuE;IACvE,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC7B,4EAA4E;IAC5E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gCAAgC;IAChC,YAAY,CAAC,EAAE;QACb,gEAAgE;QAChE,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,0EAA0E;QAC1E,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,2DAA2D;QAC3D,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,8CAA8C;IAC9C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,2DAA2D;IAC3D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,OAAO;IACxC,4BAA4B;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,+BAA+B;IAC/B,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,uEAAuE;IACvE,OAAO,EAAE,YAAY,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,wEAAwE;IACxE,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,GAAG,OAAO,IAAI,CAChC,OAAO,EAAE,YAAY,KAClB,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/B;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,OAAO;IAClC,OAAO,CACL,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GACd,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;CACjD"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Central registry for model classes and their schema metadata.
3
+ *
4
+ * `SchemaService` is a tsyringe singleton that acts as the authoritative
5
+ * source of truth for every model registered with the store. At registration
6
+ * time it walks the full prototype chain (deepest ancestor first) and merges
7
+ * all `@attr` / `@belongsTo` / `@hasMany` definitions so subclasses
8
+ * transparently inherit parent schema.
9
+ *
10
+ * Consumers (Store, serializers, snapshot helpers) call `attributesDefinitionFor`
11
+ * and `relationshipsDefinitionFor` rather than reading reflect-metadata directly.
12
+ */
13
+ import 'reflect-metadata';
14
+ import { type AttributeDef, type AttributeDefinitionsMap, type RelationshipDef, type RelationshipDefinitionsMap } from './types.js';
15
+ /** Minimal shape of a model constructor that SchemaService can register. */
16
+ export interface ModelClass {
17
+ modelName?: string;
18
+ prototype: unknown;
19
+ new (...args: never[]): unknown;
20
+ }
21
+ export declare class SchemaService {
22
+ private entries;
23
+ /**
24
+ * Registers a model class under `modelName`.
25
+ *
26
+ * Walks the prototype chain at registration time so lookups are O(1).
27
+ * Calling this a second time for the same `modelName` replaces the entry.
28
+ */
29
+ registerModel(modelName: string, modelClass: ModelClass): void;
30
+ /**
31
+ * Returns the constructor for the given `modelName`.
32
+ * @throws if the model has not been registered.
33
+ */
34
+ modelFor(modelName: string): ModelClass;
35
+ /** Returns `true` when a model class has been registered for `modelName`. */
36
+ doesTypeExist(modelName: string): boolean;
37
+ /**
38
+ * Returns the merged attribute definitions for `modelName`.
39
+ * @throws if the model has not been registered.
40
+ */
41
+ attributesDefinitionFor(modelName: string): AttributeDefinitionsMap;
42
+ /**
43
+ * Returns the merged relationship definitions for `modelName`.
44
+ * @throws if the model has not been registered.
45
+ */
46
+ relationshipsDefinitionFor(modelName: string): RelationshipDefinitionsMap;
47
+ /**
48
+ * Iterates over every attribute definition for `modelName`, invoking
49
+ * `callback` with the attribute name and its `AttributeDef`.
50
+ */
51
+ eachAttribute(modelName: string, callback: (name: string, meta: AttributeDef) => void): void;
52
+ /**
53
+ * Iterates over every relationship definition for `modelName`, invoking
54
+ * `callback` with the relationship name and its `RelationshipDef`.
55
+ */
56
+ eachRelationship(modelName: string, callback: (name: string, meta: RelationshipDef) => void): void;
57
+ }
58
+ //# sourceMappingURL=SchemaService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaService.d.ts","sourceRoot":"","sources":["../../src/schema/SchemaService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAE1B,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,0BAA0B,EAChC,MAAM,YAAY,CAAC;AAEpB,4EAA4E;AAC5E,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,GAAG,IAAI,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;CACjC;AAyCD,qBACa,aAAa;IACxB,OAAO,CAAC,OAAO,CAA4B;IAE3C;;;;;OAKG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;IAY9D;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU;IAQvC,6EAA6E;IAC7E,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIzC;;;OAGG;IACH,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,uBAAuB;IAQnE;;;OAGG;IACH,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,0BAA0B;IAQzE;;;OAGG;IACH,aAAa,CACX,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,GACnD,IAAI;IAOP;;;OAGG;IACH,gBAAgB,CACd,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,KAAK,IAAI,GACtD,IAAI;CAMR"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Property decorators for declaring model attributes and relationships.
3
+ *
4
+ * `@attr` marks a property as a data attribute that is serialized to/from the
5
+ * server payload. `@belongsTo` and `@hasMany` declare the two supported
6
+ * association directions.
7
+ *
8
+ * All decorators write their metadata onto the class prototype via
9
+ * `reflect-metadata` so `SchemaService` can walk the prototype chain and
10
+ * merge inherited definitions.
11
+ */
12
+ import 'reflect-metadata';
13
+ import { type AttributeOptions, type RelationshipOptions } from './types.js';
14
+ /**
15
+ * Marks a class property as a serializable attribute.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * @attr('string') name!: string;
20
+ * @attr('number', { defaultValue: 0 }) age!: number;
21
+ * @attr({ defaultValue: () => [] }) tags!: string[];
22
+ * ```
23
+ */
24
+ export declare function attr(type?: string | null, options?: AttributeOptions): PropertyDecorator;
25
+ export declare function attr(options: AttributeOptions): PropertyDecorator;
26
+ /**
27
+ * Declares a `belongsTo` (many-to-one) association.
28
+ *
29
+ * @param type - `modelName` of the related model.
30
+ * @param options - Optional relationship options (async, inverse, …).
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * @belongsTo('user') author!: User;
35
+ * ```
36
+ */
37
+ export declare function belongsTo(type: string, options?: RelationshipOptions): PropertyDecorator;
38
+ /**
39
+ * Declares a `hasMany` (one-to-many) association.
40
+ *
41
+ * @param type - `modelName` of the related model.
42
+ * @param options - Optional relationship options (async, inverse, …).
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * @hasMany('comment') comments!: Comment[];
47
+ * ```
48
+ */
49
+ export declare function hasMany(type: string, options?: RelationshipOptions): PropertyDecorator;
50
+ //# sourceMappingURL=decorators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/schema/decorators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAIL,KAAK,gBAAgB,EAErB,KAAK,mBAAmB,EACzB,MAAM,YAAY,CAAC;AAkCpB;;;;;;;;;GASG;AACH,wBAAgB,IAAI,CAClB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EACpB,OAAO,CAAC,EAAE,gBAAgB,GACzB,iBAAiB,CAAC;AACrB,wBAAgB,IAAI,CAAC,OAAO,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;AA2DnE;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,iBAAiB,CAEnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,mBAAwB,GAChC,iBAAiB,CAEnB"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../types-uWOXMPWW.cjs"),r=require("../decorators-HQ1KnRdh.cjs"),E=require("../SchemaService-Di_yjVzU.cjs");exports.ATTRIBUTES_META_KEY=e.ATTRIBUTES_META_KEY;exports.MODEL_NAME_META_KEY=e.MODEL_NAME_META_KEY;exports.RELATIONSHIPS_META_KEY=e.RELATIONSHIPS_META_KEY;exports.attr=r.attr;exports.belongsTo=r.belongsTo;exports.hasMany=r.hasMany;Object.defineProperty(exports,"SchemaService",{enumerable:!0,get:()=>E.SchemaService});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ export * from './types.js';
2
+ export { attr, belongsTo, hasMany } from './decorators.js';
3
+ export { SchemaService, type ModelClass } from './SchemaService.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { A as s, M as o, R as r } from "../types-C9NB2gRj.js";
2
+ import { a as e, b as A, h as M } from "../decorators-Zr35qr6A.js";
3
+ import { S } from "../SchemaService-DZwkFgZu.js";
4
+ export {
5
+ s as ATTRIBUTES_META_KEY,
6
+ o as MODEL_NAME_META_KEY,
7
+ r as RELATIONSHIPS_META_KEY,
8
+ S as SchemaService,
9
+ e as attr,
10
+ A as belongsTo,
11
+ M as hasMany
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}