@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.
- package/LICENSE +21 -0
- package/README.md +366 -0
- package/dist/CacheHandler-BTU_rYkv.js +208 -0
- package/dist/CacheHandler-BTU_rYkv.js.map +1 -0
- package/dist/CacheHandler-CXgY9IJo.cjs +2 -0
- package/dist/CacheHandler-CXgY9IJo.cjs.map +1 -0
- package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs +2 -0
- package/dist/EmbeddedRecordsMixin-CBvqNdgC.cjs.map +1 -0
- package/dist/EmbeddedRecordsMixin-VoHluHCT.js +261 -0
- package/dist/EmbeddedRecordsMixin-VoHluHCT.js.map +1 -0
- package/dist/JsonApiSerializer-CC5HXp4b.js +194 -0
- package/dist/JsonApiSerializer-CC5HXp4b.js.map +1 -0
- package/dist/JsonApiSerializer-CKB02AgP.cjs +2 -0
- package/dist/JsonApiSerializer-CKB02AgP.cjs.map +1 -0
- package/dist/MemoryAdapter-Bx1e7ndV.js +123 -0
- package/dist/MemoryAdapter-Bx1e7ndV.js.map +1 -0
- package/dist/MemoryAdapter-D1cTyydm.cjs +2 -0
- package/dist/MemoryAdapter-D1cTyydm.cjs.map +1 -0
- package/dist/ODataAdapter-C4IHK4BK.js +157 -0
- package/dist/ODataAdapter-C4IHK4BK.js.map +1 -0
- package/dist/ODataAdapter-DyyF1sdA.cjs +2 -0
- package/dist/ODataAdapter-DyyF1sdA.cjs.map +1 -0
- package/dist/RestAdapter-B4aRvs4m.js +355 -0
- package/dist/RestAdapter-B4aRvs4m.js.map +1 -0
- package/dist/RestAdapter-CJOwTsKK.cjs +2 -0
- package/dist/RestAdapter-CJOwTsKK.cjs.map +1 -0
- package/dist/SchemaService-DZwkFgZu.js +102 -0
- package/dist/SchemaService-DZwkFgZu.js.map +1 -0
- package/dist/SchemaService-Di_yjVzU.cjs +2 -0
- package/dist/SchemaService-Di_yjVzU.cjs.map +1 -0
- package/dist/Serializer-95gi5edy.cjs +2 -0
- package/dist/Serializer-95gi5edy.cjs.map +1 -0
- package/dist/Serializer-FxJbsZ50.js +139 -0
- package/dist/Serializer-FxJbsZ50.js.map +1 -0
- package/dist/Store-BdwMrbDi.cjs +2 -0
- package/dist/Store-BdwMrbDi.cjs.map +1 -0
- package/dist/Store-CZ7Z-Nme.js +912 -0
- package/dist/Store-CZ7Z-Nme.js.map +1 -0
- package/dist/adapter/Adapter.d.ts +146 -0
- package/dist/adapter/Adapter.d.ts.map +1 -0
- package/dist/adapter/MemoryAdapter.d.ts +44 -0
- package/dist/adapter/MemoryAdapter.d.ts.map +1 -0
- package/dist/adapter/RestAdapter.d.ts +57 -0
- package/dist/adapter/RestAdapter.d.ts.map +1 -0
- package/dist/adapter/index.cjs +2 -0
- package/dist/adapter/index.cjs.map +1 -0
- package/dist/adapter/index.d.ts +4 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +8 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/date-Bj4O2W1F.js +107 -0
- package/dist/date-Bj4O2W1F.js.map +1 -0
- package/dist/date-CRCe-9gf.cjs +2 -0
- package/dist/date-CRCe-9gf.cjs.map +1 -0
- package/dist/decorators-HQ1KnRdh.cjs +2 -0
- package/dist/decorators-HQ1KnRdh.cjs.map +1 -0
- package/dist/decorators-Zr35qr6A.js +50 -0
- package/dist/decorators-Zr35qr6A.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/json-api/JsonApiAdapter.d.ts +38 -0
- package/dist/json-api/JsonApiAdapter.d.ts.map +1 -0
- package/dist/json-api/JsonApiSerializer.d.ts +73 -0
- package/dist/json-api/JsonApiSerializer.d.ts.map +1 -0
- package/dist/json-api/index.cjs +2 -0
- package/dist/json-api/index.cjs.map +1 -0
- package/dist/json-api/index.d.ts +3 -0
- package/dist/json-api/index.d.ts.map +1 -0
- package/dist/json-api/index.js +6 -0
- package/dist/json-api/index.js.map +1 -0
- package/dist/model/Errors.d.ts +46 -0
- package/dist/model/Errors.d.ts.map +1 -0
- package/dist/model/Model.d.ts +226 -0
- package/dist/model/Model.d.ts.map +1 -0
- package/dist/model/Snapshot.d.ts +72 -0
- package/dist/model/Snapshot.d.ts.map +1 -0
- package/dist/model/StateMachine.d.ts +45 -0
- package/dist/model/StateMachine.d.ts.map +1 -0
- package/dist/model/index.cjs +2 -0
- package/dist/model/index.cjs.map +1 -0
- package/dist/model/index.d.ts +6 -0
- package/dist/model/index.d.ts.map +1 -0
- package/dist/model/index.js +11 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/relationships.d.ts +182 -0
- package/dist/model/relationships.d.ts.map +1 -0
- package/dist/odata/ODataAdapter.d.ts +67 -0
- package/dist/odata/ODataAdapter.d.ts.map +1 -0
- package/dist/odata/index.cjs +2 -0
- package/dist/odata/index.cjs.map +1 -0
- package/dist/odata/index.d.ts +2 -0
- package/dist/odata/index.d.ts.map +1 -0
- package/dist/odata/index.js +5 -0
- package/dist/odata/index.js.map +1 -0
- package/dist/relationships-B55LBaCW.cjs +2 -0
- package/dist/relationships-B55LBaCW.cjs.map +1 -0
- package/dist/relationships-BEXANmWg.js +821 -0
- package/dist/relationships-BEXANmWg.js.map +1 -0
- package/dist/request/CacheHandler.d.ts +50 -0
- package/dist/request/CacheHandler.d.ts.map +1 -0
- package/dist/request/FetchHandler.d.ts +41 -0
- package/dist/request/FetchHandler.d.ts.map +1 -0
- package/dist/request/RequestManager.d.ts +52 -0
- package/dist/request/RequestManager.d.ts.map +1 -0
- package/dist/request/index.cjs +2 -0
- package/dist/request/index.cjs.map +1 -0
- package/dist/request/index.d.ts +5 -0
- package/dist/request/index.d.ts.map +1 -0
- package/dist/request/index.js +7 -0
- package/dist/request/index.js.map +1 -0
- package/dist/request/types.d.ts +111 -0
- package/dist/request/types.d.ts.map +1 -0
- package/dist/schema/SchemaService.d.ts +58 -0
- package/dist/schema/SchemaService.d.ts.map +1 -0
- package/dist/schema/decorators.d.ts +50 -0
- package/dist/schema/decorators.d.ts.map +1 -0
- package/dist/schema/index.cjs +2 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +13 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/types.d.ts +61 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/serializer/EmbeddedRecordsMixin.d.ts +80 -0
- package/dist/serializer/EmbeddedRecordsMixin.d.ts.map +1 -0
- package/dist/serializer/JsonSerializer.d.ts +52 -0
- package/dist/serializer/JsonSerializer.d.ts.map +1 -0
- package/dist/serializer/RestSerializer.d.ts +43 -0
- package/dist/serializer/RestSerializer.d.ts.map +1 -0
- package/dist/serializer/Serializer.d.ts +202 -0
- package/dist/serializer/Serializer.d.ts.map +1 -0
- package/dist/serializer/index.cjs +2 -0
- package/dist/serializer/index.cjs.map +1 -0
- package/dist/serializer/index.d.ts +5 -0
- package/dist/serializer/index.d.ts.map +1 -0
- package/dist/serializer/index.js +9 -0
- package/dist/serializer/index.js.map +1 -0
- package/dist/store/IdentityMap.d.ts +53 -0
- package/dist/store/IdentityMap.d.ts.map +1 -0
- package/dist/store/RecordArray.d.ts +114 -0
- package/dist/store/RecordArray.d.ts.map +1 -0
- package/dist/store/Store.d.ts +395 -0
- package/dist/store/Store.d.ts.map +1 -0
- package/dist/store/index.cjs +2 -0
- package/dist/store/index.cjs.map +1 -0
- package/dist/store/index.d.ts +5 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +8 -0
- package/dist/store/index.js.map +1 -0
- package/dist/transforms/Transform.d.ts +49 -0
- package/dist/transforms/Transform.d.ts.map +1 -0
- package/dist/transforms/boolean.d.ts +26 -0
- package/dist/transforms/boolean.d.ts.map +1 -0
- package/dist/transforms/date.d.ts +22 -0
- package/dist/transforms/date.d.ts.map +1 -0
- package/dist/transforms/index.cjs +2 -0
- package/dist/transforms/index.cjs.map +1 -0
- package/dist/transforms/index.d.ts +6 -0
- package/dist/transforms/index.d.ts.map +1 -0
- package/dist/transforms/index.js +9 -0
- package/dist/transforms/index.js.map +1 -0
- package/dist/transforms/number.d.ts +17 -0
- package/dist/transforms/number.d.ts.map +1 -0
- package/dist/transforms/string.d.ts +18 -0
- package/dist/transforms/string.d.ts.map +1 -0
- package/dist/types-C9NB2gRj.js +7 -0
- package/dist/types-C9NB2gRj.js.map +1 -0
- package/dist/types-uWOXMPWW.cjs +2 -0
- package/dist/types-uWOXMPWW.cjs.map +1 -0
- package/package.json +140 -0
- package/src/adapter/Adapter.ts +320 -0
- package/src/adapter/MemoryAdapter.ts +216 -0
- package/src/adapter/RestAdapter.ts +248 -0
- package/src/adapter/index.ts +7 -0
- package/src/index.ts +17 -0
- package/src/json-api/JsonApiAdapter.ts +93 -0
- package/src/json-api/JsonApiSerializer.ts +245 -0
- package/src/json-api/index.ts +2 -0
- package/src/model/Errors.ts +100 -0
- package/src/model/Model.ts +683 -0
- package/src/model/Snapshot.ts +162 -0
- package/src/model/StateMachine.ts +149 -0
- package/src/model/index.ts +20 -0
- package/src/model/relationships.ts +484 -0
- package/src/odata/ODataAdapter.ts +245 -0
- package/src/odata/index.ts +1 -0
- package/src/request/CacheHandler.ts +125 -0
- package/src/request/FetchHandler.ts +119 -0
- package/src/request/RequestManager.ts +112 -0
- package/src/request/index.ts +4 -0
- package/src/request/types.ts +139 -0
- package/src/schema/SchemaService.ts +161 -0
- package/src/schema/decorators.ts +162 -0
- package/src/schema/index.ts +3 -0
- package/src/schema/types.ts +66 -0
- package/src/serializer/EmbeddedRecordsMixin.ts +257 -0
- package/src/serializer/JsonSerializer.ts +173 -0
- package/src/serializer/RestSerializer.ts +138 -0
- package/src/serializer/Serializer.ts +397 -0
- package/src/serializer/index.ts +15 -0
- package/src/store/IdentityMap.ts +110 -0
- package/src/store/RecordArray.ts +210 -0
- package/src/store/Store.ts +1391 -0
- package/src/store/index.ts +11 -0
- package/src/transforms/Transform.ts +52 -0
- package/src/transforms/boolean.ts +57 -0
- package/src/transforms/date.ts +48 -0
- package/src/transforms/index.ts +5 -0
- package/src/transforms/number.ts +42 -0
- package/src/transforms/string.ts +35 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationships-B55LBaCW.cjs","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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"}
|