@iamjulianacosta/mobx-data 1.0.1 → 1.1.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/dist/{JsonApiSerializer-CKB02AgP.cjs → JsonApiSerializer-Bc4iQB0d.cjs} +2 -2
- package/dist/{JsonApiSerializer-CKB02AgP.cjs.map → JsonApiSerializer-Bc4iQB0d.cjs.map} +1 -1
- package/dist/{JsonApiSerializer-CC5HXp4b.js → JsonApiSerializer-wndq5a1n.js} +2 -2
- package/dist/{JsonApiSerializer-CC5HXp4b.js.map → JsonApiSerializer-wndq5a1n.js.map} +1 -1
- package/dist/{MemoryAdapter-D1cTyydm.cjs → MemoryAdapter-BTK2D64s.cjs} +2 -2
- package/dist/{MemoryAdapter-D1cTyydm.cjs.map → MemoryAdapter-BTK2D64s.cjs.map} +1 -1
- package/dist/{MemoryAdapter-Bx1e7ndV.js → MemoryAdapter-ni25N4H0.js} +2 -2
- package/dist/{MemoryAdapter-Bx1e7ndV.js.map → MemoryAdapter-ni25N4H0.js.map} +1 -1
- package/dist/{ODataAdapter-C4IHK4BK.js → ODataAdapter-DAja_jKM.js} +2 -2
- package/dist/{ODataAdapter-C4IHK4BK.js.map → ODataAdapter-DAja_jKM.js.map} +1 -1
- package/dist/{ODataAdapter-DyyF1sdA.cjs → ODataAdapter-lMifLyLD.cjs} +2 -2
- package/dist/{ODataAdapter-DyyF1sdA.cjs.map → ODataAdapter-lMifLyLD.cjs.map} +1 -1
- package/dist/RestAdapter-1V94stW-.cjs +2 -0
- package/dist/{RestAdapter-CJOwTsKK.cjs.map → RestAdapter-1V94stW-.cjs.map} +1 -1
- package/dist/{RestAdapter-B4aRvs4m.js → RestAdapter-CGWqOR_G.js} +32 -23
- package/dist/{RestAdapter-B4aRvs4m.js.map → RestAdapter-CGWqOR_G.js.map} +1 -1
- package/dist/Store-KvjmBTQ9.cjs +2 -0
- package/dist/Store-KvjmBTQ9.cjs.map +1 -0
- package/dist/{Store-CZ7Z-Nme.js → Store-mvrDLQEZ.js} +195 -150
- package/dist/Store-mvrDLQEZ.js.map +1 -0
- package/dist/adapter/RestAdapter.d.ts.map +1 -1
- package/dist/adapter/index.cjs +1 -1
- package/dist/adapter/index.js +2 -2
- package/dist/cache/IndexedDBCache.d.ts +22 -0
- package/dist/cache/IndexedDBCache.d.ts.map +1 -0
- package/dist/cache/cache-utils.d.ts +4 -0
- package/dist/cache/cache-utils.d.ts.map +1 -0
- package/dist/cache/index.d.ts +4 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/types.d.ts +25 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache-utils-2lswvJ87.cjs +2 -0
- package/dist/cache-utils-2lswvJ87.cjs.map +1 -0
- package/dist/cache-utils-38Dqu4Qf.js +39 -0
- package/dist/cache-utils-38Dqu4Qf.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -49
- package/dist/index.js.map +1 -1
- package/dist/json-api/index.cjs +1 -1
- package/dist/json-api/index.js +1 -1
- package/dist/odata/index.cjs +1 -1
- package/dist/odata/index.js +1 -1
- package/dist/store/Store.d.ts +6 -0
- package/dist/store/Store.d.ts.map +1 -1
- package/dist/store/index.cjs +1 -1
- package/dist/store/index.js +1 -1
- package/package.json +2 -1
- package/src/adapter/RestAdapter.ts +12 -2
- package/src/cache/IndexedDBCache.ts +171 -0
- package/src/cache/cache-utils.ts +57 -0
- package/src/cache/index.ts +12 -0
- package/src/cache/types.ts +33 -0
- package/src/index.ts +1 -0
- package/src/store/Store.ts +100 -0
- package/dist/RestAdapter-CJOwTsKK.cjs +0 -2
- package/dist/Store-BdwMrbDi.cjs +0 -2
- package/dist/Store-BdwMrbDi.cjs.map +0 -1
- package/dist/Store-CZ7Z-Nme.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const m=require("tsyringe"),h=require("./RestAdapter-
|
|
2
|
-
//# sourceMappingURL=JsonApiSerializer-
|
|
1
|
+
"use strict";const m=require("tsyringe"),h=require("./RestAdapter-1V94stW-.cjs"),y=require("pluralize"),f=require("./Serializer-95gi5edy.cjs");var A=Object.getOwnPropertyDescriptor,b=(c,t,n,r)=>{for(var a=r>1?void 0:r?A(t,n):t,i=c.length-1,e;i>=0;i--)(e=c[i])&&(a=e(a)||a);return a};exports.JsonApiAdapter=class extends h.RestAdapter{constructor(){super(...arguments),this.coalesceFindRequests=!0}defaultHeaders(){return{Accept:"application/vnd.api+json",...this.headers}}mutationHeaders(){return{"Content-Type":"application/vnd.api+json",...this.defaultHeaders()}}async updateRecord(t,n,r){const a=this.buildURL(n,r.id,r,"updateRecord");return this._fetchJSON(a,{method:"PATCH",headers:this.mutationHeaders(),body:JSON.stringify(this._serializeForUpdate(r))})}async patchRecord(t,n,r){const a=this.buildURL(n,r.id,r,"updateRecord"),i=r.changedAttributes(),e={};for(const[l,[,s]]of Object.entries(i))e[l]=s;const d={data:{type:n,id:r.id,attributes:e}};return this._fetchJSON(a,{method:"PATCH",headers:this.mutationHeaders(),body:JSON.stringify(d)})}_serializeForUpdate(t){const n=t.record;return n._data?{...n._data}:{}}};exports.JsonApiAdapter=b([m.injectable()],exports.JsonApiAdapter);var g=Object.getOwnPropertyDescriptor,_=(c,t,n,r)=>{for(var a=r>1?void 0:r?g(t,n):t,i=c.length-1,e;i>=0;i--)(e=c[i])&&(a=e(a)||a);return a};exports.JsonApiSerializer=class extends f.Serializer{payloadKeyFromModelName(t){return y.plural(t)}modelNameFromPayloadKey(t){return y.singular(t)}normalize(t,n,r,a){if(!r||typeof r!="object"||Array.isArray(r))return null;const i=r;if(!i.type)return null;const e={type:this.modelNameFromPayloadKey(i.type),id:i.id===null||i.id===void 0?null:String(i.id)};if(i.attributes&&(e.attributes={...i.attributes}),i.relationships){const d={};for(const[l,s]of Object.entries(i.relationships))s.data===null?d[l]={data:null}:Array.isArray(s.data)?d[l]={data:s.data.map(o=>({type:this.modelNameFromPayloadKey(o.type),id:String(o.id)}))}:d[l]={data:{type:this.modelNameFromPayloadKey(s.data.type),id:String(s.data.id)}};e.relationships=d}return e}normalizeResponse(t,n,r,a,i){if(!r||typeof r!="object")return{data:null};const e=r;let d=null;e.data===null||e.data===void 0?d=null:Array.isArray(e.data)?d=e.data.map(s=>this.normalize(t,n,s)).filter(s=>s!==null):d=this.normalize(t,n,e.data);const l={data:d};if(e.included&&e.included.length>0){const s=[];for(const o of e.included){const u={modelName:this.modelNameFromPayloadKey(o.type),attributes:new Map,relationships:new Map},p=this.normalize(t,u,o);p&&s.push(p)}l.included=s}return e.meta&&(l.meta=e.meta),e.links&&(l.links=e.links),l}serialize(t,n){const r={};t.eachAttribute(e=>{r[this.keyForAttribute(e)]=t.attr(e)});const a={};t.eachRelationship((e,d)=>{const{name:l}=d,s=this.keyForRelationship(l),o=this.payloadKeyFromModelName(d.type);if(d.kind==="belongsTo"){const u=t.belongsTo(l);a[s]=u&&u.id!=null?{data:{type:o,id:String(u.id)}}:{data:null}}else{const u=t.hasMany(l)??[];a[s]={data:u.map(p=>({type:o,id:String(p.id)}))}}});const i={type:this.payloadKeyFromModelName(t.modelName),attributes:r};return n!=null&&n.includeId&&t.id!==null&&(i.id=t.id),Object.keys(a).length>0&&(i.relationships=a),{data:i}}};exports.JsonApiSerializer=_([m.injectable()],exports.JsonApiSerializer);
|
|
2
|
+
//# sourceMappingURL=JsonApiSerializer-Bc4iQB0d.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonApiSerializer-CKB02AgP.cjs","sources":["../src/json-api/JsonApiAdapter.ts","../src/json-api/JsonApiSerializer.ts"],"sourcesContent":["/**\n * Adapter that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * Extends `RestAdapter` with the following differences:\n *\n * - **MIME types** — `Accept` and `Content-Type` headers are set to\n * `application/vnd.api+json` as required by the spec.\n * - **PATCH for updates** — `updateRecord` uses `PATCH` instead of `PUT`.\n * - **`coalesceFindRequests: true`** — the store coalesces separate\n * `findRecord` calls into a single `findMany` request.\n *\n * URL construction is inherited from `RestAdapter` / `Adapter` unchanged;\n * override `pathForType` or `urlFor*` methods to customize.\n */\n\nimport { injectable } from 'tsyringe';\nimport { RestAdapter, type AdapterSnapshot } from '@mobx-data/adapter';\n\n@injectable()\nexport class JsonApiAdapter extends RestAdapter {\n /** Always coalesce `findRecord` calls into a single `findMany` request. */\n override coalesceFindRequests = true;\n\n /** Returns JSON:API `Accept` header alongside any custom headers. */\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/vnd.api+json',\n ...this.headers,\n };\n }\n\n /** Returns JSON:API `Content-Type` header for mutation requests. */\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/vnd.api+json',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Sends a PATCH request to update a record (JSON:API mandates PATCH, not PUT).\n */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeForUpdate(snapshot)),\n });\n }\n\n /**\n * Sends a PATCH request with only the changed attributes (partial update).\n * Produces a JSON:API document with only the dirty attribute keys.\n */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const attributes: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n attributes[key] = current;\n }\n const body = {\n data: {\n type: modelName,\n id: snapshot.id,\n attributes,\n },\n };\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Extracts the raw data object from the snapshot for use as the PATCH body.\n * Subclasses may override this to produce a full JSON:API `{ data: … }` document.\n */\n protected _serializeForUpdate(snapshot: AdapterSnapshot): Record<string, unknown> {\n const rec = snapshot.record as { _data?: Record<string, unknown> };\n return rec._data ? { ...rec._data } : {};\n }\n}\n","/**\n * Serializer that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * ## Normalization\n *\n * Parses a JSON:API compound document `{ data, included, meta, links }` into\n * a `NormalizedDocument`.\n *\n * For each resource object:\n * - `type` is converted from JSON:API plural form to model name via\n * `modelNameFromPayloadKey` (singularization).\n * - `id` is coerced to a string.\n * - `attributes` are copied directly.\n * - `relationships` data refs (`{ type, id }`) are normalized the same way.\n *\n * Side-loaded records in `included` are normalized individually, each using\n * its own `type` as the model class placeholder.\n *\n * ## Serialization\n *\n * Produces a JSON:API resource object wrapped in `{ data: … }`:\n *\n * ```json\n * {\n * \"data\": {\n * \"type\": \"posts\",\n * \"attributes\": { \"title\": \"Hello\" },\n * \"relationships\": {\n * \"author\": { \"data\": { \"type\": \"users\", \"id\": \"1\" } }\n * }\n * }\n * }\n * ```\n *\n * `id` is included when `options.includeId` is `true`.\n */\n\nimport { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport {\n Serializer,\n type ModelClassMeta,\n type NormalizeRequestType,\n type NormalizedDocument,\n type NormalizedResource,\n type SerializerSnapshot,\n} from '@mobx-data/serializer';\n\n/** Internal shape of a raw JSON:API resource object. */\ninterface JsonApiResource {\n type: string;\n id?: string | number | null;\n attributes?: Record<string, unknown>;\n relationships?: Record<string, {\n data:\n | { type: string; id: string | number }\n | Array<{ type: string; id: string | number }>\n | null;\n }>;\n}\n\n@injectable()\nexport class JsonApiSerializer extends Serializer {\n /**\n * Returns the plural JSON:API `type` string for a model name.\n * e.g. `'post'` → `'posts'`\n */\n payloadKeyFromModelName(modelName: string): string {\n return pluralize.plural(modelName);\n }\n\n /**\n * Returns the model name for a JSON:API `type` string.\n * e.g. `'posts'` → `'post'`\n */\n modelNameFromPayloadKey(key: string): string {\n return pluralize.singular(key);\n }\n\n /**\n * Normalizes a single JSON:API resource object into a `NormalizedResource`.\n * Returns `null` for absent, non-object, or type-less payloads.\n */\n override normalize(\n _store: unknown,\n _modelClass: ModelClassMeta,\n payload: unknown,\n _prop?: string,\n ): NormalizedResource | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null;\n }\n const resource = payload as JsonApiResource;\n if (!resource.type) {\n return null;\n }\n const normalized: NormalizedResource = {\n type: this.modelNameFromPayloadKey(resource.type),\n id: resource.id === null || resource.id === undefined ? null : String(resource.id),\n };\n if (resource.attributes) {\n normalized.attributes = { ...resource.attributes };\n }\n if (resource.relationships) {\n const relationships: NonNullable<NormalizedResource['relationships']> = {};\n for (const [name, rel] of Object.entries(resource.relationships)) {\n if (rel.data === null) {\n relationships[name] = { data: null };\n } else if (Array.isArray(rel.data)) {\n relationships[name] = {\n data: rel.data.map((ref) => ({\n type: this.modelNameFromPayloadKey(ref.type),\n id: String(ref.id),\n })),\n };\n } else {\n relationships[name] = {\n data: {\n type: this.modelNameFromPayloadKey(rel.data.type),\n id: String(rel.data.id),\n },\n };\n }\n }\n normalized.relationships = relationships;\n }\n return normalized;\n }\n\n /**\n * Normalizes a full JSON:API compound document.\n *\n * - `data` (single or array) → primary resources\n * - `included` → side-loaded resources pushed to `normalizedDoc.included`\n * - `meta` and `links` → forwarded as-is\n */\n override normalizeResponse(\n store: unknown,\n modelClass: ModelClassMeta,\n payload: unknown,\n _id: string | null,\n _requestType: NormalizeRequestType,\n ): NormalizedDocument {\n if (!payload || typeof payload !== 'object') {\n return { data: null };\n }\n const doc = payload as {\n data?: JsonApiResource | JsonApiResource[] | null;\n included?: JsonApiResource[];\n meta?: Record<string, unknown>;\n links?: Record<string, string>;\n };\n\n let data: NormalizedResource | NormalizedResource[] | null = null;\n if (doc.data === null || doc.data === undefined) {\n data = null;\n } else if (Array.isArray(doc.data)) {\n data = doc.data\n .map((resource) => this.normalize(store, modelClass, resource))\n .filter((resource): resource is NormalizedResource => resource !== null);\n } else {\n data = this.normalize(store, modelClass, doc.data);\n }\n\n const normalizedDoc: NormalizedDocument = { data };\n if (doc.included && doc.included.length > 0) {\n const included: NormalizedResource[] = [];\n for (const resource of doc.included) {\n const placeholder: ModelClassMeta = {\n modelName: this.modelNameFromPayloadKey(resource.type),\n attributes: new Map(),\n relationships: new Map(),\n };\n const normalized = this.normalize(store, placeholder, resource);\n if (normalized) {\n included.push(normalized);\n }\n }\n normalizedDoc.included = included;\n }\n if (doc.meta) {\n normalizedDoc.meta = doc.meta;\n }\n if (doc.links) {\n normalizedDoc.links = doc.links;\n }\n return normalizedDoc;\n }\n\n /**\n * Serializes a record snapshot to a JSON:API `{ data: … }` document.\n *\n * Attributes are placed in `data.attributes`; relationships are placed in\n * `data.relationships` with proper `{ data: { type, id } }` structure.\n * `id` is included in `data` when `options.includeId` is `true`.\n */\n override serialize(\n snapshot: SerializerSnapshot,\n options?: { includeId?: boolean },\n ): Record<string, unknown> {\n const attributes: Record<string, unknown> = {};\n snapshot.eachAttribute((key) => {\n attributes[this.keyForAttribute(key)] = snapshot.attr(key);\n });\n\n const relationships: Record<string, { data: unknown }> = {};\n snapshot.eachRelationship((_key, rel) => {\n const { name } = rel;\n const payloadKey = this.keyForRelationship(name);\n const payloadType = this.payloadKeyFromModelName(rel.type);\n if (rel.kind === 'belongsTo') {\n const target = snapshot.belongsTo(name) as\n | { id: string; type?: string }\n | null\n | undefined;\n relationships[payloadKey] = target && target.id != null\n ? { data: { type: payloadType, id: String(target.id) } }\n : { data: null };\n } else {\n const targets = (snapshot.hasMany(name) as Array<{\n id: string; type?: string;\n }> | null) ?? [];\n relationships[payloadKey] = {\n data: targets.map((target) => ({\n type: payloadType,\n id: String(target.id),\n })),\n };\n }\n });\n\n const data: Record<string, unknown> = {\n type: this.payloadKeyFromModelName(snapshot.modelName),\n attributes,\n };\n if (options?.includeId && snapshot.id !== null) {\n data.id = snapshot.id;\n }\n if (Object.keys(relationships).length > 0) {\n data.relationships = relationships;\n }\n\n return { data };\n }\n}\n"],"names":["JsonApiAdapter","RestAdapter","_store","modelName","snapshot","url","changed","attributes","key","current","body","rec","__decorateClass","injectable","JsonApiSerializer","Serializer","pluralize","_modelClass","payload","_prop","resource","normalized","relationships","name","rel","ref","store","modelClass","_id","_requestType","doc","data","normalizedDoc","included","placeholder","options","_key","payloadKey","payloadType","target","targets"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JsonApiSerializer-Bc4iQB0d.cjs","sources":["../src/json-api/JsonApiAdapter.ts","../src/json-api/JsonApiSerializer.ts"],"sourcesContent":["/**\n * Adapter that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * Extends `RestAdapter` with the following differences:\n *\n * - **MIME types** — `Accept` and `Content-Type` headers are set to\n * `application/vnd.api+json` as required by the spec.\n * - **PATCH for updates** — `updateRecord` uses `PATCH` instead of `PUT`.\n * - **`coalesceFindRequests: true`** — the store coalesces separate\n * `findRecord` calls into a single `findMany` request.\n *\n * URL construction is inherited from `RestAdapter` / `Adapter` unchanged;\n * override `pathForType` or `urlFor*` methods to customize.\n */\n\nimport { injectable } from 'tsyringe';\nimport { RestAdapter, type AdapterSnapshot } from '@mobx-data/adapter';\n\n@injectable()\nexport class JsonApiAdapter extends RestAdapter {\n /** Always coalesce `findRecord` calls into a single `findMany` request. */\n override coalesceFindRequests = true;\n\n /** Returns JSON:API `Accept` header alongside any custom headers. */\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/vnd.api+json',\n ...this.headers,\n };\n }\n\n /** Returns JSON:API `Content-Type` header for mutation requests. */\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/vnd.api+json',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Sends a PATCH request to update a record (JSON:API mandates PATCH, not PUT).\n */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeForUpdate(snapshot)),\n });\n }\n\n /**\n * Sends a PATCH request with only the changed attributes (partial update).\n * Produces a JSON:API document with only the dirty attribute keys.\n */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const attributes: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n attributes[key] = current;\n }\n const body = {\n data: {\n type: modelName,\n id: snapshot.id,\n attributes,\n },\n };\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Extracts the raw data object from the snapshot for use as the PATCH body.\n * Subclasses may override this to produce a full JSON:API `{ data: … }` document.\n */\n protected _serializeForUpdate(snapshot: AdapterSnapshot): Record<string, unknown> {\n const rec = snapshot.record as { _data?: Record<string, unknown> };\n return rec._data ? { ...rec._data } : {};\n }\n}\n","/**\n * Serializer that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * ## Normalization\n *\n * Parses a JSON:API compound document `{ data, included, meta, links }` into\n * a `NormalizedDocument`.\n *\n * For each resource object:\n * - `type` is converted from JSON:API plural form to model name via\n * `modelNameFromPayloadKey` (singularization).\n * - `id` is coerced to a string.\n * - `attributes` are copied directly.\n * - `relationships` data refs (`{ type, id }`) are normalized the same way.\n *\n * Side-loaded records in `included` are normalized individually, each using\n * its own `type` as the model class placeholder.\n *\n * ## Serialization\n *\n * Produces a JSON:API resource object wrapped in `{ data: … }`:\n *\n * ```json\n * {\n * \"data\": {\n * \"type\": \"posts\",\n * \"attributes\": { \"title\": \"Hello\" },\n * \"relationships\": {\n * \"author\": { \"data\": { \"type\": \"users\", \"id\": \"1\" } }\n * }\n * }\n * }\n * ```\n *\n * `id` is included when `options.includeId` is `true`.\n */\n\nimport { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport {\n Serializer,\n type ModelClassMeta,\n type NormalizeRequestType,\n type NormalizedDocument,\n type NormalizedResource,\n type SerializerSnapshot,\n} from '@mobx-data/serializer';\n\n/** Internal shape of a raw JSON:API resource object. */\ninterface JsonApiResource {\n type: string;\n id?: string | number | null;\n attributes?: Record<string, unknown>;\n relationships?: Record<string, {\n data:\n | { type: string; id: string | number }\n | Array<{ type: string; id: string | number }>\n | null;\n }>;\n}\n\n@injectable()\nexport class JsonApiSerializer extends Serializer {\n /**\n * Returns the plural JSON:API `type` string for a model name.\n * e.g. `'post'` → `'posts'`\n */\n payloadKeyFromModelName(modelName: string): string {\n return pluralize.plural(modelName);\n }\n\n /**\n * Returns the model name for a JSON:API `type` string.\n * e.g. `'posts'` → `'post'`\n */\n modelNameFromPayloadKey(key: string): string {\n return pluralize.singular(key);\n }\n\n /**\n * Normalizes a single JSON:API resource object into a `NormalizedResource`.\n * Returns `null` for absent, non-object, or type-less payloads.\n */\n override normalize(\n _store: unknown,\n _modelClass: ModelClassMeta,\n payload: unknown,\n _prop?: string,\n ): NormalizedResource | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null;\n }\n const resource = payload as JsonApiResource;\n if (!resource.type) {\n return null;\n }\n const normalized: NormalizedResource = {\n type: this.modelNameFromPayloadKey(resource.type),\n id: resource.id === null || resource.id === undefined ? null : String(resource.id),\n };\n if (resource.attributes) {\n normalized.attributes = { ...resource.attributes };\n }\n if (resource.relationships) {\n const relationships: NonNullable<NormalizedResource['relationships']> = {};\n for (const [name, rel] of Object.entries(resource.relationships)) {\n if (rel.data === null) {\n relationships[name] = { data: null };\n } else if (Array.isArray(rel.data)) {\n relationships[name] = {\n data: rel.data.map((ref) => ({\n type: this.modelNameFromPayloadKey(ref.type),\n id: String(ref.id),\n })),\n };\n } else {\n relationships[name] = {\n data: {\n type: this.modelNameFromPayloadKey(rel.data.type),\n id: String(rel.data.id),\n },\n };\n }\n }\n normalized.relationships = relationships;\n }\n return normalized;\n }\n\n /**\n * Normalizes a full JSON:API compound document.\n *\n * - `data` (single or array) → primary resources\n * - `included` → side-loaded resources pushed to `normalizedDoc.included`\n * - `meta` and `links` → forwarded as-is\n */\n override normalizeResponse(\n store: unknown,\n modelClass: ModelClassMeta,\n payload: unknown,\n _id: string | null,\n _requestType: NormalizeRequestType,\n ): NormalizedDocument {\n if (!payload || typeof payload !== 'object') {\n return { data: null };\n }\n const doc = payload as {\n data?: JsonApiResource | JsonApiResource[] | null;\n included?: JsonApiResource[];\n meta?: Record<string, unknown>;\n links?: Record<string, string>;\n };\n\n let data: NormalizedResource | NormalizedResource[] | null = null;\n if (doc.data === null || doc.data === undefined) {\n data = null;\n } else if (Array.isArray(doc.data)) {\n data = doc.data\n .map((resource) => this.normalize(store, modelClass, resource))\n .filter((resource): resource is NormalizedResource => resource !== null);\n } else {\n data = this.normalize(store, modelClass, doc.data);\n }\n\n const normalizedDoc: NormalizedDocument = { data };\n if (doc.included && doc.included.length > 0) {\n const included: NormalizedResource[] = [];\n for (const resource of doc.included) {\n const placeholder: ModelClassMeta = {\n modelName: this.modelNameFromPayloadKey(resource.type),\n attributes: new Map(),\n relationships: new Map(),\n };\n const normalized = this.normalize(store, placeholder, resource);\n if (normalized) {\n included.push(normalized);\n }\n }\n normalizedDoc.included = included;\n }\n if (doc.meta) {\n normalizedDoc.meta = doc.meta;\n }\n if (doc.links) {\n normalizedDoc.links = doc.links;\n }\n return normalizedDoc;\n }\n\n /**\n * Serializes a record snapshot to a JSON:API `{ data: … }` document.\n *\n * Attributes are placed in `data.attributes`; relationships are placed in\n * `data.relationships` with proper `{ data: { type, id } }` structure.\n * `id` is included in `data` when `options.includeId` is `true`.\n */\n override serialize(\n snapshot: SerializerSnapshot,\n options?: { includeId?: boolean },\n ): Record<string, unknown> {\n const attributes: Record<string, unknown> = {};\n snapshot.eachAttribute((key) => {\n attributes[this.keyForAttribute(key)] = snapshot.attr(key);\n });\n\n const relationships: Record<string, { data: unknown }> = {};\n snapshot.eachRelationship((_key, rel) => {\n const { name } = rel;\n const payloadKey = this.keyForRelationship(name);\n const payloadType = this.payloadKeyFromModelName(rel.type);\n if (rel.kind === 'belongsTo') {\n const target = snapshot.belongsTo(name) as\n | { id: string; type?: string }\n | null\n | undefined;\n relationships[payloadKey] = target && target.id != null\n ? { data: { type: payloadType, id: String(target.id) } }\n : { data: null };\n } else {\n const targets = (snapshot.hasMany(name) as Array<{\n id: string; type?: string;\n }> | null) ?? [];\n relationships[payloadKey] = {\n data: targets.map((target) => ({\n type: payloadType,\n id: String(target.id),\n })),\n };\n }\n });\n\n const data: Record<string, unknown> = {\n type: this.payloadKeyFromModelName(snapshot.modelName),\n attributes,\n };\n if (options?.includeId && snapshot.id !== null) {\n data.id = snapshot.id;\n }\n if (Object.keys(relationships).length > 0) {\n data.relationships = relationships;\n }\n\n return { data };\n }\n}\n"],"names":["JsonApiAdapter","RestAdapter","_store","modelName","snapshot","url","changed","attributes","key","current","body","rec","__decorateClass","injectable","JsonApiSerializer","Serializer","pluralize","_modelClass","payload","_prop","resource","normalized","relationships","name","rel","ref","store","modelClass","_id","_requestType","doc","data","normalizedDoc","included","placeholder","options","_key","payloadKey","payloadType","target","targets"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { injectable as f } from "tsyringe";
|
|
2
|
-
import { R as h } from "./RestAdapter-
|
|
2
|
+
import { R as h } from "./RestAdapter-CGWqOR_G.js";
|
|
3
3
|
import m from "pluralize";
|
|
4
4
|
import { S as b } from "./Serializer-FxJbsZ50.js";
|
|
5
5
|
var _ = Object.getOwnPropertyDescriptor, g = (t, i, a, s) => {
|
|
@@ -191,4 +191,4 @@ export {
|
|
|
191
191
|
p as J,
|
|
192
192
|
y as a
|
|
193
193
|
};
|
|
194
|
-
//# sourceMappingURL=JsonApiSerializer-
|
|
194
|
+
//# sourceMappingURL=JsonApiSerializer-wndq5a1n.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JsonApiSerializer-CC5HXp4b.js","sources":["../src/json-api/JsonApiAdapter.ts","../src/json-api/JsonApiSerializer.ts"],"sourcesContent":["/**\n * Adapter that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * Extends `RestAdapter` with the following differences:\n *\n * - **MIME types** — `Accept` and `Content-Type` headers are set to\n * `application/vnd.api+json` as required by the spec.\n * - **PATCH for updates** — `updateRecord` uses `PATCH` instead of `PUT`.\n * - **`coalesceFindRequests: true`** — the store coalesces separate\n * `findRecord` calls into a single `findMany` request.\n *\n * URL construction is inherited from `RestAdapter` / `Adapter` unchanged;\n * override `pathForType` or `urlFor*` methods to customize.\n */\n\nimport { injectable } from 'tsyringe';\nimport { RestAdapter, type AdapterSnapshot } from '@mobx-data/adapter';\n\n@injectable()\nexport class JsonApiAdapter extends RestAdapter {\n /** Always coalesce `findRecord` calls into a single `findMany` request. */\n override coalesceFindRequests = true;\n\n /** Returns JSON:API `Accept` header alongside any custom headers. */\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/vnd.api+json',\n ...this.headers,\n };\n }\n\n /** Returns JSON:API `Content-Type` header for mutation requests. */\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/vnd.api+json',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Sends a PATCH request to update a record (JSON:API mandates PATCH, not PUT).\n */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeForUpdate(snapshot)),\n });\n }\n\n /**\n * Sends a PATCH request with only the changed attributes (partial update).\n * Produces a JSON:API document with only the dirty attribute keys.\n */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const attributes: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n attributes[key] = current;\n }\n const body = {\n data: {\n type: modelName,\n id: snapshot.id,\n attributes,\n },\n };\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Extracts the raw data object from the snapshot for use as the PATCH body.\n * Subclasses may override this to produce a full JSON:API `{ data: … }` document.\n */\n protected _serializeForUpdate(snapshot: AdapterSnapshot): Record<string, unknown> {\n const rec = snapshot.record as { _data?: Record<string, unknown> };\n return rec._data ? { ...rec._data } : {};\n }\n}\n","/**\n * Serializer that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * ## Normalization\n *\n * Parses a JSON:API compound document `{ data, included, meta, links }` into\n * a `NormalizedDocument`.\n *\n * For each resource object:\n * - `type` is converted from JSON:API plural form to model name via\n * `modelNameFromPayloadKey` (singularization).\n * - `id` is coerced to a string.\n * - `attributes` are copied directly.\n * - `relationships` data refs (`{ type, id }`) are normalized the same way.\n *\n * Side-loaded records in `included` are normalized individually, each using\n * its own `type` as the model class placeholder.\n *\n * ## Serialization\n *\n * Produces a JSON:API resource object wrapped in `{ data: … }`:\n *\n * ```json\n * {\n * \"data\": {\n * \"type\": \"posts\",\n * \"attributes\": { \"title\": \"Hello\" },\n * \"relationships\": {\n * \"author\": { \"data\": { \"type\": \"users\", \"id\": \"1\" } }\n * }\n * }\n * }\n * ```\n *\n * `id` is included when `options.includeId` is `true`.\n */\n\nimport { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport {\n Serializer,\n type ModelClassMeta,\n type NormalizeRequestType,\n type NormalizedDocument,\n type NormalizedResource,\n type SerializerSnapshot,\n} from '@mobx-data/serializer';\n\n/** Internal shape of a raw JSON:API resource object. */\ninterface JsonApiResource {\n type: string;\n id?: string | number | null;\n attributes?: Record<string, unknown>;\n relationships?: Record<string, {\n data:\n | { type: string; id: string | number }\n | Array<{ type: string; id: string | number }>\n | null;\n }>;\n}\n\n@injectable()\nexport class JsonApiSerializer extends Serializer {\n /**\n * Returns the plural JSON:API `type` string for a model name.\n * e.g. `'post'` → `'posts'`\n */\n payloadKeyFromModelName(modelName: string): string {\n return pluralize.plural(modelName);\n }\n\n /**\n * Returns the model name for a JSON:API `type` string.\n * e.g. `'posts'` → `'post'`\n */\n modelNameFromPayloadKey(key: string): string {\n return pluralize.singular(key);\n }\n\n /**\n * Normalizes a single JSON:API resource object into a `NormalizedResource`.\n * Returns `null` for absent, non-object, or type-less payloads.\n */\n override normalize(\n _store: unknown,\n _modelClass: ModelClassMeta,\n payload: unknown,\n _prop?: string,\n ): NormalizedResource | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null;\n }\n const resource = payload as JsonApiResource;\n if (!resource.type) {\n return null;\n }\n const normalized: NormalizedResource = {\n type: this.modelNameFromPayloadKey(resource.type),\n id: resource.id === null || resource.id === undefined ? null : String(resource.id),\n };\n if (resource.attributes) {\n normalized.attributes = { ...resource.attributes };\n }\n if (resource.relationships) {\n const relationships: NonNullable<NormalizedResource['relationships']> = {};\n for (const [name, rel] of Object.entries(resource.relationships)) {\n if (rel.data === null) {\n relationships[name] = { data: null };\n } else if (Array.isArray(rel.data)) {\n relationships[name] = {\n data: rel.data.map((ref) => ({\n type: this.modelNameFromPayloadKey(ref.type),\n id: String(ref.id),\n })),\n };\n } else {\n relationships[name] = {\n data: {\n type: this.modelNameFromPayloadKey(rel.data.type),\n id: String(rel.data.id),\n },\n };\n }\n }\n normalized.relationships = relationships;\n }\n return normalized;\n }\n\n /**\n * Normalizes a full JSON:API compound document.\n *\n * - `data` (single or array) → primary resources\n * - `included` → side-loaded resources pushed to `normalizedDoc.included`\n * - `meta` and `links` → forwarded as-is\n */\n override normalizeResponse(\n store: unknown,\n modelClass: ModelClassMeta,\n payload: unknown,\n _id: string | null,\n _requestType: NormalizeRequestType,\n ): NormalizedDocument {\n if (!payload || typeof payload !== 'object') {\n return { data: null };\n }\n const doc = payload as {\n data?: JsonApiResource | JsonApiResource[] | null;\n included?: JsonApiResource[];\n meta?: Record<string, unknown>;\n links?: Record<string, string>;\n };\n\n let data: NormalizedResource | NormalizedResource[] | null = null;\n if (doc.data === null || doc.data === undefined) {\n data = null;\n } else if (Array.isArray(doc.data)) {\n data = doc.data\n .map((resource) => this.normalize(store, modelClass, resource))\n .filter((resource): resource is NormalizedResource => resource !== null);\n } else {\n data = this.normalize(store, modelClass, doc.data);\n }\n\n const normalizedDoc: NormalizedDocument = { data };\n if (doc.included && doc.included.length > 0) {\n const included: NormalizedResource[] = [];\n for (const resource of doc.included) {\n const placeholder: ModelClassMeta = {\n modelName: this.modelNameFromPayloadKey(resource.type),\n attributes: new Map(),\n relationships: new Map(),\n };\n const normalized = this.normalize(store, placeholder, resource);\n if (normalized) {\n included.push(normalized);\n }\n }\n normalizedDoc.included = included;\n }\n if (doc.meta) {\n normalizedDoc.meta = doc.meta;\n }\n if (doc.links) {\n normalizedDoc.links = doc.links;\n }\n return normalizedDoc;\n }\n\n /**\n * Serializes a record snapshot to a JSON:API `{ data: … }` document.\n *\n * Attributes are placed in `data.attributes`; relationships are placed in\n * `data.relationships` with proper `{ data: { type, id } }` structure.\n * `id` is included in `data` when `options.includeId` is `true`.\n */\n override serialize(\n snapshot: SerializerSnapshot,\n options?: { includeId?: boolean },\n ): Record<string, unknown> {\n const attributes: Record<string, unknown> = {};\n snapshot.eachAttribute((key) => {\n attributes[this.keyForAttribute(key)] = snapshot.attr(key);\n });\n\n const relationships: Record<string, { data: unknown }> = {};\n snapshot.eachRelationship((_key, rel) => {\n const { name } = rel;\n const payloadKey = this.keyForRelationship(name);\n const payloadType = this.payloadKeyFromModelName(rel.type);\n if (rel.kind === 'belongsTo') {\n const target = snapshot.belongsTo(name) as\n | { id: string; type?: string }\n | null\n | undefined;\n relationships[payloadKey] = target && target.id != null\n ? { data: { type: payloadType, id: String(target.id) } }\n : { data: null };\n } else {\n const targets = (snapshot.hasMany(name) as Array<{\n id: string; type?: string;\n }> | null) ?? [];\n relationships[payloadKey] = {\n data: targets.map((target) => ({\n type: payloadType,\n id: String(target.id),\n })),\n };\n }\n });\n\n const data: Record<string, unknown> = {\n type: this.payloadKeyFromModelName(snapshot.modelName),\n attributes,\n };\n if (options?.includeId && snapshot.id !== null) {\n data.id = snapshot.id;\n }\n if (Object.keys(relationships).length > 0) {\n data.relationships = relationships;\n }\n\n return { data };\n }\n}\n"],"names":["JsonApiAdapter","RestAdapter","_store","modelName","snapshot","url","changed","attributes","key","current","body","rec","__decorateClass","injectable","JsonApiSerializer","Serializer","pluralize","_modelClass","payload","_prop","resource","normalized","relationships","name","rel","ref","store","modelClass","_id","_requestType","doc","data","normalizedDoc","included","placeholder","options","_key","payloadKey","payloadType","target","targets"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"JsonApiSerializer-wndq5a1n.js","sources":["../src/json-api/JsonApiAdapter.ts","../src/json-api/JsonApiSerializer.ts"],"sourcesContent":["/**\n * Adapter that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * Extends `RestAdapter` with the following differences:\n *\n * - **MIME types** — `Accept` and `Content-Type` headers are set to\n * `application/vnd.api+json` as required by the spec.\n * - **PATCH for updates** — `updateRecord` uses `PATCH` instead of `PUT`.\n * - **`coalesceFindRequests: true`** — the store coalesces separate\n * `findRecord` calls into a single `findMany` request.\n *\n * URL construction is inherited from `RestAdapter` / `Adapter` unchanged;\n * override `pathForType` or `urlFor*` methods to customize.\n */\n\nimport { injectable } from 'tsyringe';\nimport { RestAdapter, type AdapterSnapshot } from '@mobx-data/adapter';\n\n@injectable()\nexport class JsonApiAdapter extends RestAdapter {\n /** Always coalesce `findRecord` calls into a single `findMany` request. */\n override coalesceFindRequests = true;\n\n /** Returns JSON:API `Accept` header alongside any custom headers. */\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/vnd.api+json',\n ...this.headers,\n };\n }\n\n /** Returns JSON:API `Content-Type` header for mutation requests. */\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/vnd.api+json',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Sends a PATCH request to update a record (JSON:API mandates PATCH, not PUT).\n */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeForUpdate(snapshot)),\n });\n }\n\n /**\n * Sends a PATCH request with only the changed attributes (partial update).\n * Produces a JSON:API document with only the dirty attribute keys.\n */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const attributes: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n attributes[key] = current;\n }\n const body = {\n data: {\n type: modelName,\n id: snapshot.id,\n attributes,\n },\n };\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(body),\n });\n }\n\n /**\n * Extracts the raw data object from the snapshot for use as the PATCH body.\n * Subclasses may override this to produce a full JSON:API `{ data: … }` document.\n */\n protected _serializeForUpdate(snapshot: AdapterSnapshot): Record<string, unknown> {\n const rec = snapshot.record as { _data?: Record<string, unknown> };\n return rec._data ? { ...rec._data } : {};\n }\n}\n","/**\n * Serializer that implements the [JSON:API](https://jsonapi.org) specification.\n *\n * ## Normalization\n *\n * Parses a JSON:API compound document `{ data, included, meta, links }` into\n * a `NormalizedDocument`.\n *\n * For each resource object:\n * - `type` is converted from JSON:API plural form to model name via\n * `modelNameFromPayloadKey` (singularization).\n * - `id` is coerced to a string.\n * - `attributes` are copied directly.\n * - `relationships` data refs (`{ type, id }`) are normalized the same way.\n *\n * Side-loaded records in `included` are normalized individually, each using\n * its own `type` as the model class placeholder.\n *\n * ## Serialization\n *\n * Produces a JSON:API resource object wrapped in `{ data: … }`:\n *\n * ```json\n * {\n * \"data\": {\n * \"type\": \"posts\",\n * \"attributes\": { \"title\": \"Hello\" },\n * \"relationships\": {\n * \"author\": { \"data\": { \"type\": \"users\", \"id\": \"1\" } }\n * }\n * }\n * }\n * ```\n *\n * `id` is included when `options.includeId` is `true`.\n */\n\nimport { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport {\n Serializer,\n type ModelClassMeta,\n type NormalizeRequestType,\n type NormalizedDocument,\n type NormalizedResource,\n type SerializerSnapshot,\n} from '@mobx-data/serializer';\n\n/** Internal shape of a raw JSON:API resource object. */\ninterface JsonApiResource {\n type: string;\n id?: string | number | null;\n attributes?: Record<string, unknown>;\n relationships?: Record<string, {\n data:\n | { type: string; id: string | number }\n | Array<{ type: string; id: string | number }>\n | null;\n }>;\n}\n\n@injectable()\nexport class JsonApiSerializer extends Serializer {\n /**\n * Returns the plural JSON:API `type` string for a model name.\n * e.g. `'post'` → `'posts'`\n */\n payloadKeyFromModelName(modelName: string): string {\n return pluralize.plural(modelName);\n }\n\n /**\n * Returns the model name for a JSON:API `type` string.\n * e.g. `'posts'` → `'post'`\n */\n modelNameFromPayloadKey(key: string): string {\n return pluralize.singular(key);\n }\n\n /**\n * Normalizes a single JSON:API resource object into a `NormalizedResource`.\n * Returns `null` for absent, non-object, or type-less payloads.\n */\n override normalize(\n _store: unknown,\n _modelClass: ModelClassMeta,\n payload: unknown,\n _prop?: string,\n ): NormalizedResource | null {\n if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {\n return null;\n }\n const resource = payload as JsonApiResource;\n if (!resource.type) {\n return null;\n }\n const normalized: NormalizedResource = {\n type: this.modelNameFromPayloadKey(resource.type),\n id: resource.id === null || resource.id === undefined ? null : String(resource.id),\n };\n if (resource.attributes) {\n normalized.attributes = { ...resource.attributes };\n }\n if (resource.relationships) {\n const relationships: NonNullable<NormalizedResource['relationships']> = {};\n for (const [name, rel] of Object.entries(resource.relationships)) {\n if (rel.data === null) {\n relationships[name] = { data: null };\n } else if (Array.isArray(rel.data)) {\n relationships[name] = {\n data: rel.data.map((ref) => ({\n type: this.modelNameFromPayloadKey(ref.type),\n id: String(ref.id),\n })),\n };\n } else {\n relationships[name] = {\n data: {\n type: this.modelNameFromPayloadKey(rel.data.type),\n id: String(rel.data.id),\n },\n };\n }\n }\n normalized.relationships = relationships;\n }\n return normalized;\n }\n\n /**\n * Normalizes a full JSON:API compound document.\n *\n * - `data` (single or array) → primary resources\n * - `included` → side-loaded resources pushed to `normalizedDoc.included`\n * - `meta` and `links` → forwarded as-is\n */\n override normalizeResponse(\n store: unknown,\n modelClass: ModelClassMeta,\n payload: unknown,\n _id: string | null,\n _requestType: NormalizeRequestType,\n ): NormalizedDocument {\n if (!payload || typeof payload !== 'object') {\n return { data: null };\n }\n const doc = payload as {\n data?: JsonApiResource | JsonApiResource[] | null;\n included?: JsonApiResource[];\n meta?: Record<string, unknown>;\n links?: Record<string, string>;\n };\n\n let data: NormalizedResource | NormalizedResource[] | null = null;\n if (doc.data === null || doc.data === undefined) {\n data = null;\n } else if (Array.isArray(doc.data)) {\n data = doc.data\n .map((resource) => this.normalize(store, modelClass, resource))\n .filter((resource): resource is NormalizedResource => resource !== null);\n } else {\n data = this.normalize(store, modelClass, doc.data);\n }\n\n const normalizedDoc: NormalizedDocument = { data };\n if (doc.included && doc.included.length > 0) {\n const included: NormalizedResource[] = [];\n for (const resource of doc.included) {\n const placeholder: ModelClassMeta = {\n modelName: this.modelNameFromPayloadKey(resource.type),\n attributes: new Map(),\n relationships: new Map(),\n };\n const normalized = this.normalize(store, placeholder, resource);\n if (normalized) {\n included.push(normalized);\n }\n }\n normalizedDoc.included = included;\n }\n if (doc.meta) {\n normalizedDoc.meta = doc.meta;\n }\n if (doc.links) {\n normalizedDoc.links = doc.links;\n }\n return normalizedDoc;\n }\n\n /**\n * Serializes a record snapshot to a JSON:API `{ data: … }` document.\n *\n * Attributes are placed in `data.attributes`; relationships are placed in\n * `data.relationships` with proper `{ data: { type, id } }` structure.\n * `id` is included in `data` when `options.includeId` is `true`.\n */\n override serialize(\n snapshot: SerializerSnapshot,\n options?: { includeId?: boolean },\n ): Record<string, unknown> {\n const attributes: Record<string, unknown> = {};\n snapshot.eachAttribute((key) => {\n attributes[this.keyForAttribute(key)] = snapshot.attr(key);\n });\n\n const relationships: Record<string, { data: unknown }> = {};\n snapshot.eachRelationship((_key, rel) => {\n const { name } = rel;\n const payloadKey = this.keyForRelationship(name);\n const payloadType = this.payloadKeyFromModelName(rel.type);\n if (rel.kind === 'belongsTo') {\n const target = snapshot.belongsTo(name) as\n | { id: string; type?: string }\n | null\n | undefined;\n relationships[payloadKey] = target && target.id != null\n ? { data: { type: payloadType, id: String(target.id) } }\n : { data: null };\n } else {\n const targets = (snapshot.hasMany(name) as Array<{\n id: string; type?: string;\n }> | null) ?? [];\n relationships[payloadKey] = {\n data: targets.map((target) => ({\n type: payloadType,\n id: String(target.id),\n })),\n };\n }\n });\n\n const data: Record<string, unknown> = {\n type: this.payloadKeyFromModelName(snapshot.modelName),\n attributes,\n };\n if (options?.includeId && snapshot.id !== null) {\n data.id = snapshot.id;\n }\n if (Object.keys(relationships).length > 0) {\n data.relationships = relationships;\n }\n\n return { data };\n }\n}\n"],"names":["JsonApiAdapter","RestAdapter","_store","modelName","snapshot","url","changed","attributes","key","current","body","rec","__decorateClass","injectable","JsonApiSerializer","Serializer","pluralize","_modelClass","payload","_prop","resource","normalized","relationships","name","rel","ref","store","modelClass","_id","_requestType","doc","data","normalizedDoc","included","placeholder","options","_key","payloadKey","payloadType","target","targets"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const l=require("tsyringe"),y=require("./RestAdapter-
|
|
2
|
-
//# sourceMappingURL=MemoryAdapter-
|
|
1
|
+
"use strict";const l=require("tsyringe"),y=require("./RestAdapter-1V94stW-.cjs");var p=Object.getOwnPropertyDescriptor,f=(c,s,t,e)=>{for(var r=e>1?void 0:e?p(s,t):s,n=c.length-1,o;n>=0;n--)(o=c[n])&&(r=o(r)||r);return r};exports.MemoryAdapter=class extends y.Adapter{constructor(){super(...arguments),this.storage=new Map,this.nextId=new Map}getCollection(s){let t=this.storage.get(s);return t||(t=new Map,this.storage.set(s,t)),t}generateId(s){const t=this.nextId.get(s)??1;return this.nextId.set(s,t+1),String(t)}seed(s,t){const e=this.getCollection(s);for(const r of t){const{id:n,...o}=r;e.set(n,{id:n,type:s,attributes:o});const i=Number(n);if(!Number.isNaN(i)){const a=this.nextId.get(s)??1;i>=a&&this.nextId.set(s,i+1)}}}reset(){this.storage.clear(),this.nextId.clear()}async findRecord(s,t,e){const n=this.getCollection(t).get(e);if(!n)throw Object.assign(new Error(`Record not found: ${t}:${e}`),{status:404});return{data:{id:n.id,type:n.type,attributes:{...n.attributes}}}}async findAll(s,t){const e=this.getCollection(t);return{data:Array.from(e.values()).map(n=>({id:n.id,type:n.type,attributes:{...n.attributes}}))}}async findMany(s,t,e){const r=this.getCollection(t);return{data:e.map(o=>r.get(o)).filter(o=>o!==void 0).map(o=>({id:o.id,type:o.type,attributes:{...o.attributes}}))}}async query(s,t,e){const r=this.getCollection(t);return{data:Array.from(r.values()).filter(a=>{for(const[u,d]of Object.entries(e))if(a.attributes[u]!==d)return!1;return!0}).map(a=>({id:a.id,type:a.type,attributes:{...a.attributes}}))}}async queryRecord(s,t,e){return{data:(await this.query(s,t,e)).data[0]??null}}static safeAssign(s,t){for(const[e,r]of Object.entries(t))e==="__proto__"||e==="constructor"||e==="prototype"||(s[e]=r)}async createRecord(s,t,e){const r=this.generateId(t),n={},o=e.record;o._data&&exports.MemoryAdapter.safeAssign(n,o._data);const i={id:r,type:t,attributes:n};return this.getCollection(t).set(r,i),{data:{id:r,type:t,attributes:{...n}}}}async updateRecord(s,t,e){const{id:r}=e;if(!r)throw new Error("Cannot update a record without an id");const o=this.getCollection(t).get(r);if(!o)throw Object.assign(new Error(`Record not found: ${t}:${r}`),{status:404});const i=e.record;return i._data&&exports.MemoryAdapter.safeAssign(o.attributes,i._data),{data:{id:r,type:t,attributes:{...o.attributes}}}}async deleteRecord(s,t,e){const{id:r}=e;if(!r)throw new Error("Cannot delete a record without an id");return this.getCollection(t).delete(r),null}};exports.MemoryAdapter=f([l.injectable()],exports.MemoryAdapter);
|
|
2
|
+
//# sourceMappingURL=MemoryAdapter-BTK2D64s.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryAdapter-D1cTyydm.cjs","sources":["../src/adapter/MemoryAdapter.ts"],"sourcesContent":["/**\n * In-memory adapter for testing and server-side rendering.\n *\n * `MemoryAdapter` stores records in plain `Map` structures with no network I/O.\n * It implements the full adapter interface (findRecord, findAll, findMany, query,\n * queryRecord, createRecord, updateRecord, deleteRecord) so it can serve as a\n * drop-in replacement for `RestAdapter` in unit tests or SSR hydration scenarios.\n *\n * Use `seed()` to pre-populate data and `reset()` to clear all state between\n * test cases.\n */\n\nimport { injectable } from 'tsyringe';\nimport { Adapter, type AdapterSnapshot } from './Adapter.js';\n\ninterface MemoryRecord {\n id: string;\n type: string;\n attributes: Record<string, unknown>;\n}\n\n@injectable()\nexport class MemoryAdapter extends Adapter {\n private storage: Map<string, Map<string, MemoryRecord>> = new Map();\n\n private nextId: Map<string, number> = new Map();\n\n private getCollection(modelName: string): Map<string, MemoryRecord> {\n let collection = this.storage.get(modelName);\n if (!collection) {\n collection = new Map();\n this.storage.set(modelName, collection);\n }\n return collection;\n }\n\n private generateId(modelName: string): string {\n const current = this.nextId.get(modelName) ?? 1;\n this.nextId.set(modelName, current + 1);\n return String(current);\n }\n\n /**\n * Pre-populates the adapter with records for a given model type.\n * Auto-increments the internal ID counter to avoid collisions with\n * subsequently created records.\n *\n * @param modelName - The model type to seed.\n * @param records - Array of plain objects; each must have an `id` key.\n */\n seed(modelName: string, records: Array<{ id: string; [key: string]: unknown }>): void {\n const collection = this.getCollection(modelName);\n for (const record of records) {\n const { id, ...attributes } = record;\n collection.set(id, { id, type: modelName, attributes });\n const numId = Number(id);\n if (!Number.isNaN(numId)) {\n const current = this.nextId.get(modelName) ?? 1;\n if (numId >= current) {\n this.nextId.set(modelName, numId + 1);\n }\n }\n }\n }\n\n /** Clears all stored records and resets ID counters. */\n reset(): void {\n this.storage.clear();\n this.nextId.clear();\n }\n\n override async findRecord(\n _store: unknown,\n modelName: string,\n id: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const record = collection.get(id);\n if (!record) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n return { data: { id: record.id, type: record.type, attributes: { ...record.attributes } } };\n }\n\n override async findAll(\n _store: unknown,\n modelName: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = Array.from(collection.values()).map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = ids\n .map((id) => collection.get(id))\n .filter((record): record is MemoryRecord => record !== undefined)\n .map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Filters records by exact attribute match on all query keys. */\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const entries = Array.from(collection.values());\n const filtered = entries.filter((record) => {\n for (const [key, value] of Object.entries(query)) {\n if (record.attributes[key] !== value) {\n return false;\n }\n }\n return true;\n });\n const data = filtered.map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Returns the first record matching the query, or `null`. */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const result = await this.query(_store, modelName, query) as { data: unknown[] };\n return { data: result.data[0] ?? null };\n }\n\n private static safeAssign(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n ): void {\n for (const [key, value] of Object.entries(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n continue;\n }\n target[key] = value;\n }\n }\n\n override async createRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const id = this.generateId(modelName);\n const attributes: Record<string, unknown> = {};\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(attributes, record._data);\n }\n const entry: MemoryRecord = { id, type: modelName, attributes };\n this.getCollection(modelName).set(id, entry);\n return { data: { id, type: modelName, attributes: { ...attributes } } };\n }\n\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot update a record without an id');\n }\n const collection = this.getCollection(modelName);\n const existing = collection.get(id);\n if (!existing) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(existing.attributes, record._data);\n }\n return { data: { id, type: modelName, attributes: { ...existing.attributes } } };\n }\n\n override async deleteRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot delete a record without an id');\n }\n this.getCollection(modelName).delete(id);\n return null;\n }\n}\n"],"names":["MemoryAdapter","Adapter","modelName","collection","current","records","record","id","attributes","numId","_store","ids","query","key","value","target","source","snapshot","entry","existing","__decorateClass","injectable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MemoryAdapter-BTK2D64s.cjs","sources":["../src/adapter/MemoryAdapter.ts"],"sourcesContent":["/**\n * In-memory adapter for testing and server-side rendering.\n *\n * `MemoryAdapter` stores records in plain `Map` structures with no network I/O.\n * It implements the full adapter interface (findRecord, findAll, findMany, query,\n * queryRecord, createRecord, updateRecord, deleteRecord) so it can serve as a\n * drop-in replacement for `RestAdapter` in unit tests or SSR hydration scenarios.\n *\n * Use `seed()` to pre-populate data and `reset()` to clear all state between\n * test cases.\n */\n\nimport { injectable } from 'tsyringe';\nimport { Adapter, type AdapterSnapshot } from './Adapter.js';\n\ninterface MemoryRecord {\n id: string;\n type: string;\n attributes: Record<string, unknown>;\n}\n\n@injectable()\nexport class MemoryAdapter extends Adapter {\n private storage: Map<string, Map<string, MemoryRecord>> = new Map();\n\n private nextId: Map<string, number> = new Map();\n\n private getCollection(modelName: string): Map<string, MemoryRecord> {\n let collection = this.storage.get(modelName);\n if (!collection) {\n collection = new Map();\n this.storage.set(modelName, collection);\n }\n return collection;\n }\n\n private generateId(modelName: string): string {\n const current = this.nextId.get(modelName) ?? 1;\n this.nextId.set(modelName, current + 1);\n return String(current);\n }\n\n /**\n * Pre-populates the adapter with records for a given model type.\n * Auto-increments the internal ID counter to avoid collisions with\n * subsequently created records.\n *\n * @param modelName - The model type to seed.\n * @param records - Array of plain objects; each must have an `id` key.\n */\n seed(modelName: string, records: Array<{ id: string; [key: string]: unknown }>): void {\n const collection = this.getCollection(modelName);\n for (const record of records) {\n const { id, ...attributes } = record;\n collection.set(id, { id, type: modelName, attributes });\n const numId = Number(id);\n if (!Number.isNaN(numId)) {\n const current = this.nextId.get(modelName) ?? 1;\n if (numId >= current) {\n this.nextId.set(modelName, numId + 1);\n }\n }\n }\n }\n\n /** Clears all stored records and resets ID counters. */\n reset(): void {\n this.storage.clear();\n this.nextId.clear();\n }\n\n override async findRecord(\n _store: unknown,\n modelName: string,\n id: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const record = collection.get(id);\n if (!record) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n return { data: { id: record.id, type: record.type, attributes: { ...record.attributes } } };\n }\n\n override async findAll(\n _store: unknown,\n modelName: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = Array.from(collection.values()).map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = ids\n .map((id) => collection.get(id))\n .filter((record): record is MemoryRecord => record !== undefined)\n .map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Filters records by exact attribute match on all query keys. */\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const entries = Array.from(collection.values());\n const filtered = entries.filter((record) => {\n for (const [key, value] of Object.entries(query)) {\n if (record.attributes[key] !== value) {\n return false;\n }\n }\n return true;\n });\n const data = filtered.map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Returns the first record matching the query, or `null`. */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const result = await this.query(_store, modelName, query) as { data: unknown[] };\n return { data: result.data[0] ?? null };\n }\n\n private static safeAssign(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n ): void {\n for (const [key, value] of Object.entries(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n continue;\n }\n target[key] = value;\n }\n }\n\n override async createRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const id = this.generateId(modelName);\n const attributes: Record<string, unknown> = {};\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(attributes, record._data);\n }\n const entry: MemoryRecord = { id, type: modelName, attributes };\n this.getCollection(modelName).set(id, entry);\n return { data: { id, type: modelName, attributes: { ...attributes } } };\n }\n\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot update a record without an id');\n }\n const collection = this.getCollection(modelName);\n const existing = collection.get(id);\n if (!existing) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(existing.attributes, record._data);\n }\n return { data: { id, type: modelName, attributes: { ...existing.attributes } } };\n }\n\n override async deleteRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot delete a record without an id');\n }\n this.getCollection(modelName).delete(id);\n return null;\n }\n}\n"],"names":["MemoryAdapter","Adapter","modelName","collection","current","records","record","id","attributes","numId","_store","ids","query","key","value","target","source","snapshot","entry","existing","__decorateClass","injectable"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { injectable as d } from "tsyringe";
|
|
2
|
-
import { A as f } from "./RestAdapter-
|
|
2
|
+
import { A as f } from "./RestAdapter-CGWqOR_G.js";
|
|
3
3
|
var p = Object.getOwnPropertyDescriptor, y = (s, t, e, r) => {
|
|
4
4
|
for (var n = r > 1 ? void 0 : r ? p(t, e) : t, o = s.length - 1, i; o >= 0; o--)
|
|
5
5
|
(i = s[o]) && (n = i(n) || n);
|
|
@@ -120,4 +120,4 @@ c = y([
|
|
|
120
120
|
export {
|
|
121
121
|
c as M
|
|
122
122
|
};
|
|
123
|
-
//# sourceMappingURL=MemoryAdapter-
|
|
123
|
+
//# sourceMappingURL=MemoryAdapter-ni25N4H0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MemoryAdapter-Bx1e7ndV.js","sources":["../src/adapter/MemoryAdapter.ts"],"sourcesContent":["/**\n * In-memory adapter for testing and server-side rendering.\n *\n * `MemoryAdapter` stores records in plain `Map` structures with no network I/O.\n * It implements the full adapter interface (findRecord, findAll, findMany, query,\n * queryRecord, createRecord, updateRecord, deleteRecord) so it can serve as a\n * drop-in replacement for `RestAdapter` in unit tests or SSR hydration scenarios.\n *\n * Use `seed()` to pre-populate data and `reset()` to clear all state between\n * test cases.\n */\n\nimport { injectable } from 'tsyringe';\nimport { Adapter, type AdapterSnapshot } from './Adapter.js';\n\ninterface MemoryRecord {\n id: string;\n type: string;\n attributes: Record<string, unknown>;\n}\n\n@injectable()\nexport class MemoryAdapter extends Adapter {\n private storage: Map<string, Map<string, MemoryRecord>> = new Map();\n\n private nextId: Map<string, number> = new Map();\n\n private getCollection(modelName: string): Map<string, MemoryRecord> {\n let collection = this.storage.get(modelName);\n if (!collection) {\n collection = new Map();\n this.storage.set(modelName, collection);\n }\n return collection;\n }\n\n private generateId(modelName: string): string {\n const current = this.nextId.get(modelName) ?? 1;\n this.nextId.set(modelName, current + 1);\n return String(current);\n }\n\n /**\n * Pre-populates the adapter with records for a given model type.\n * Auto-increments the internal ID counter to avoid collisions with\n * subsequently created records.\n *\n * @param modelName - The model type to seed.\n * @param records - Array of plain objects; each must have an `id` key.\n */\n seed(modelName: string, records: Array<{ id: string; [key: string]: unknown }>): void {\n const collection = this.getCollection(modelName);\n for (const record of records) {\n const { id, ...attributes } = record;\n collection.set(id, { id, type: modelName, attributes });\n const numId = Number(id);\n if (!Number.isNaN(numId)) {\n const current = this.nextId.get(modelName) ?? 1;\n if (numId >= current) {\n this.nextId.set(modelName, numId + 1);\n }\n }\n }\n }\n\n /** Clears all stored records and resets ID counters. */\n reset(): void {\n this.storage.clear();\n this.nextId.clear();\n }\n\n override async findRecord(\n _store: unknown,\n modelName: string,\n id: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const record = collection.get(id);\n if (!record) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n return { data: { id: record.id, type: record.type, attributes: { ...record.attributes } } };\n }\n\n override async findAll(\n _store: unknown,\n modelName: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = Array.from(collection.values()).map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = ids\n .map((id) => collection.get(id))\n .filter((record): record is MemoryRecord => record !== undefined)\n .map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Filters records by exact attribute match on all query keys. */\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const entries = Array.from(collection.values());\n const filtered = entries.filter((record) => {\n for (const [key, value] of Object.entries(query)) {\n if (record.attributes[key] !== value) {\n return false;\n }\n }\n return true;\n });\n const data = filtered.map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Returns the first record matching the query, or `null`. */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const result = await this.query(_store, modelName, query) as { data: unknown[] };\n return { data: result.data[0] ?? null };\n }\n\n private static safeAssign(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n ): void {\n for (const [key, value] of Object.entries(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n continue;\n }\n target[key] = value;\n }\n }\n\n override async createRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const id = this.generateId(modelName);\n const attributes: Record<string, unknown> = {};\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(attributes, record._data);\n }\n const entry: MemoryRecord = { id, type: modelName, attributes };\n this.getCollection(modelName).set(id, entry);\n return { data: { id, type: modelName, attributes: { ...attributes } } };\n }\n\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot update a record without an id');\n }\n const collection = this.getCollection(modelName);\n const existing = collection.get(id);\n if (!existing) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(existing.attributes, record._data);\n }\n return { data: { id, type: modelName, attributes: { ...existing.attributes } } };\n }\n\n override async deleteRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot delete a record without an id');\n }\n this.getCollection(modelName).delete(id);\n return null;\n }\n}\n"],"names":["MemoryAdapter","Adapter","modelName","collection","current","records","record","id","attributes","numId","_store","ids","query","key","value","target","source","snapshot","entry","existing","__decorateClass","injectable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MemoryAdapter-ni25N4H0.js","sources":["../src/adapter/MemoryAdapter.ts"],"sourcesContent":["/**\n * In-memory adapter for testing and server-side rendering.\n *\n * `MemoryAdapter` stores records in plain `Map` structures with no network I/O.\n * It implements the full adapter interface (findRecord, findAll, findMany, query,\n * queryRecord, createRecord, updateRecord, deleteRecord) so it can serve as a\n * drop-in replacement for `RestAdapter` in unit tests or SSR hydration scenarios.\n *\n * Use `seed()` to pre-populate data and `reset()` to clear all state between\n * test cases.\n */\n\nimport { injectable } from 'tsyringe';\nimport { Adapter, type AdapterSnapshot } from './Adapter.js';\n\ninterface MemoryRecord {\n id: string;\n type: string;\n attributes: Record<string, unknown>;\n}\n\n@injectable()\nexport class MemoryAdapter extends Adapter {\n private storage: Map<string, Map<string, MemoryRecord>> = new Map();\n\n private nextId: Map<string, number> = new Map();\n\n private getCollection(modelName: string): Map<string, MemoryRecord> {\n let collection = this.storage.get(modelName);\n if (!collection) {\n collection = new Map();\n this.storage.set(modelName, collection);\n }\n return collection;\n }\n\n private generateId(modelName: string): string {\n const current = this.nextId.get(modelName) ?? 1;\n this.nextId.set(modelName, current + 1);\n return String(current);\n }\n\n /**\n * Pre-populates the adapter with records for a given model type.\n * Auto-increments the internal ID counter to avoid collisions with\n * subsequently created records.\n *\n * @param modelName - The model type to seed.\n * @param records - Array of plain objects; each must have an `id` key.\n */\n seed(modelName: string, records: Array<{ id: string; [key: string]: unknown }>): void {\n const collection = this.getCollection(modelName);\n for (const record of records) {\n const { id, ...attributes } = record;\n collection.set(id, { id, type: modelName, attributes });\n const numId = Number(id);\n if (!Number.isNaN(numId)) {\n const current = this.nextId.get(modelName) ?? 1;\n if (numId >= current) {\n this.nextId.set(modelName, numId + 1);\n }\n }\n }\n }\n\n /** Clears all stored records and resets ID counters. */\n reset(): void {\n this.storage.clear();\n this.nextId.clear();\n }\n\n override async findRecord(\n _store: unknown,\n modelName: string,\n id: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const record = collection.get(id);\n if (!record) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n return { data: { id: record.id, type: record.type, attributes: { ...record.attributes } } };\n }\n\n override async findAll(\n _store: unknown,\n modelName: string,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = Array.from(collection.values()).map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const data = ids\n .map((id) => collection.get(id))\n .filter((record): record is MemoryRecord => record !== undefined)\n .map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Filters records by exact attribute match on all query keys. */\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const collection = this.getCollection(modelName);\n const entries = Array.from(collection.values());\n const filtered = entries.filter((record) => {\n for (const [key, value] of Object.entries(query)) {\n if (record.attributes[key] !== value) {\n return false;\n }\n }\n return true;\n });\n const data = filtered.map((record) => ({\n id: record.id,\n type: record.type,\n attributes: { ...record.attributes },\n }));\n return { data };\n }\n\n /** Returns the first record matching the query, or `null`. */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const result = await this.query(_store, modelName, query) as { data: unknown[] };\n return { data: result.data[0] ?? null };\n }\n\n private static safeAssign(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n ): void {\n for (const [key, value] of Object.entries(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n continue;\n }\n target[key] = value;\n }\n }\n\n override async createRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const id = this.generateId(modelName);\n const attributes: Record<string, unknown> = {};\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(attributes, record._data);\n }\n const entry: MemoryRecord = { id, type: modelName, attributes };\n this.getCollection(modelName).set(id, entry);\n return { data: { id, type: modelName, attributes: { ...attributes } } };\n }\n\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot update a record without an id');\n }\n const collection = this.getCollection(modelName);\n const existing = collection.get(id);\n if (!existing) {\n throw Object.assign(\n new Error(`Record not found: ${modelName}:${id}`),\n { status: 404 },\n );\n }\n const record = snapshot.record as { _data?: Record<string, unknown> };\n if (record._data) {\n MemoryAdapter.safeAssign(existing.attributes, record._data);\n }\n return { data: { id, type: modelName, attributes: { ...existing.attributes } } };\n }\n\n override async deleteRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const { id } = snapshot;\n if (!id) {\n throw new Error('Cannot delete a record without an id');\n }\n this.getCollection(modelName).delete(id);\n return null;\n }\n}\n"],"names":["MemoryAdapter","Adapter","modelName","collection","current","records","record","id","attributes","numId","_store","ids","query","key","value","target","source","snapshot","entry","existing","__decorateClass","injectable"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { injectable as u } from "tsyringe";
|
|
2
2
|
import h from "pluralize";
|
|
3
|
-
import { R as l, p } from "./RestAdapter-
|
|
3
|
+
import { R as l, p } from "./RestAdapter-CGWqOR_G.js";
|
|
4
4
|
var y = Object.getOwnPropertyDescriptor, m = (t, r, e, s) => {
|
|
5
5
|
for (var o = s > 1 ? void 0 : s ? y(r, e) : r, n = t.length - 1, a; n >= 0; n--)
|
|
6
6
|
(a = t[n]) && (o = a(o) || o);
|
|
@@ -154,4 +154,4 @@ i = m([
|
|
|
154
154
|
export {
|
|
155
155
|
i as O
|
|
156
156
|
};
|
|
157
|
-
//# sourceMappingURL=ODataAdapter-
|
|
157
|
+
//# sourceMappingURL=ODataAdapter-DAja_jKM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ODataAdapter-C4IHK4BK.js","sources":["../src/odata/ODataAdapter.ts"],"sourcesContent":["import { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport { pascalCase } from 'change-case';\nimport { RestAdapter } from '@mobx-data/adapter';\nimport type { AdapterSnapshot } from '@mobx-data/adapter';\n\n/** All OData v4 system query option names (both bare and $-prefixed forms are checked). */\nconst ODATA_SYSTEM_QUERY_OPTIONS = new Set([\n '$filter',\n '$select',\n '$orderby',\n '$top',\n '$skip',\n '$expand',\n '$count',\n '$search',\n '$format',\n '$skiptoken',\n]);\n\n/**\n * OData v4 adapter.\n *\n * Extends `RestAdapter` with OData-specific conventions:\n * - Entity-set names are PascalCase plural (`user` → `Users`).\n * - Single-entity URLs use key-in-parentheses syntax (`Users(1)`, `Users('abc')`).\n * - Mutations use PATCH instead of PUT.\n * - Accept / Content-Type headers carry the `odata.metadata=minimal` parameter.\n * - System query options (`$filter`, `$expand`, etc.) are passed through verbatim;\n * bare names are auto-prefixed (`filter` → `$filter`).\n */\n@injectable()\nexport class ODataAdapter extends RestAdapter {\n /** OData protocol version sent in `OData-Version` and `OData-MaxVersion` headers. */\n odataVersion: string = '4.0';\n\n static isNumericKey(id: string): boolean {\n return /^-?\\d+(?:\\.\\d+)?$/.test(id);\n }\n\n static escapeODataString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/json;odata.metadata=minimal',\n 'OData-Version': this.odataVersion,\n 'OData-MaxVersion': this.odataVersion,\n ...this.headers,\n };\n }\n\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json;odata.metadata=minimal',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Maps a camelCase/dasherized model name to a PascalCase plural entity-set name.\n * @example `pathForType('orderItem')` → `'OrderItems'`\n */\n override pathForType(modelName: string): string {\n return pascalCase(pluralize.plural(modelName));\n }\n\n /**\n * Encodes a record id as an OData key literal.\n * Numeric ids are returned bare (`1`); string ids are single-quoted with\n * inner apostrophes escaped (`o'brien` → `'o''brien'`).\n *\n * Override this method when the service uses a non-default key format (e.g. GUIDs).\n */\n encodeKey(id: string): string {\n if (ODataAdapter.isNumericKey(id)) {\n return id;\n }\n return `'${ODataAdapter.escapeODataString(id)}'`;\n }\n\n override urlForFindRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForUpdateRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForDeleteRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n /**\n * Fetches multiple records by id using a single request.\n * Builds a `$filter=id eq X or id eq Y` expression so only one HTTP round-trip\n * is needed regardless of how many ids are requested.\n */\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n snapshots: AdapterSnapshot[],\n ): Promise<unknown> {\n const base = this.buildURL(modelName, ids, snapshots, 'findMany');\n const filter = ids.map((id) => `id eq ${this.encodeKey(id)}`).join(' or ');\n const url = `${base}?${this._toQueryString({ $filter: filter })}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'query', query);\n const normalized = this._normalizeQuery(query);\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /**\n * Queries for a single record by appending `$top=1` to whatever filter is provided.\n * The caller is responsible for picking the first element from the returned `value` array.\n */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'queryRecord', query);\n const normalized = { ...this._normalizeQuery(query), $top: 1 };\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /** Sends a PATCH request (partial update) as required by the OData v4 spec. */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeSnapshot(snapshot)),\n });\n }\n\n /** Sends a PATCH request with only the changed attributes (partial update). */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const partial: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n partial[key] = current;\n }\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(partial),\n });\n }\n\n /** Extracts the raw attribute map from the snapshot's internal record. */\n protected _serializeSnapshot(snapshot: AdapterSnapshot): Record<string, unknown> {\n const record = snapshot.record as { _data?: Record<string, unknown> };\n const data = record._data;\n const body: Record<string, unknown> = {};\n if (data) {\n Object.assign(body, data);\n }\n return body;\n }\n\n /**\n * Normalises a query hash so every OData system option has its `$` prefix.\n * Bare names (`filter`, `top`, `expand`) are prefixed automatically.\n * Custom (non-system) keys are forwarded verbatim.\n * `null` and `undefined` values are dropped.\n */\n protected _normalizeQuery(\n query: Record<string, unknown>,\n ): Record<string, unknown> {\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n if (ODATA_SYSTEM_QUERY_OPTIONS.has(key)) {\n normalized[key] = value;\n } else if (ODATA_SYSTEM_QUERY_OPTIONS.has(`$${key}`)) {\n normalized[`$${key}`] = value;\n } else {\n normalized[key] = value;\n }\n }\n return normalized;\n }\n\n /** Serialises a key→value map to a `key=value&…` query string (percent-encoded). */\n protected _toQueryString(query: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n return parts.join('&');\n }\n\n /** Returns `?key=value&…` when the query is non-empty, or an empty string. */\n protected _appendQuery(query: Record<string, unknown>): string {\n const queryString = this._toQueryString(query);\n return queryString ? `?${queryString}` : '';\n }\n}\n"],"names":["ODATA_SYSTEM_QUERY_OPTIONS","ODataAdapter","RestAdapter","id","value","modelName","pascalCase","pluralize","_snapshot","_store","ids","snapshots","base","filter","url","query","normalized","snapshot","changed","partial","key","current","data","body","parts","queryString","__decorateClass","injectable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ODataAdapter-DAja_jKM.js","sources":["../src/odata/ODataAdapter.ts"],"sourcesContent":["import { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport { pascalCase } from 'change-case';\nimport { RestAdapter } from '@mobx-data/adapter';\nimport type { AdapterSnapshot } from '@mobx-data/adapter';\n\n/** All OData v4 system query option names (both bare and $-prefixed forms are checked). */\nconst ODATA_SYSTEM_QUERY_OPTIONS = new Set([\n '$filter',\n '$select',\n '$orderby',\n '$top',\n '$skip',\n '$expand',\n '$count',\n '$search',\n '$format',\n '$skiptoken',\n]);\n\n/**\n * OData v4 adapter.\n *\n * Extends `RestAdapter` with OData-specific conventions:\n * - Entity-set names are PascalCase plural (`user` → `Users`).\n * - Single-entity URLs use key-in-parentheses syntax (`Users(1)`, `Users('abc')`).\n * - Mutations use PATCH instead of PUT.\n * - Accept / Content-Type headers carry the `odata.metadata=minimal` parameter.\n * - System query options (`$filter`, `$expand`, etc.) are passed through verbatim;\n * bare names are auto-prefixed (`filter` → `$filter`).\n */\n@injectable()\nexport class ODataAdapter extends RestAdapter {\n /** OData protocol version sent in `OData-Version` and `OData-MaxVersion` headers. */\n odataVersion: string = '4.0';\n\n static isNumericKey(id: string): boolean {\n return /^-?\\d+(?:\\.\\d+)?$/.test(id);\n }\n\n static escapeODataString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/json;odata.metadata=minimal',\n 'OData-Version': this.odataVersion,\n 'OData-MaxVersion': this.odataVersion,\n ...this.headers,\n };\n }\n\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json;odata.metadata=minimal',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Maps a camelCase/dasherized model name to a PascalCase plural entity-set name.\n * @example `pathForType('orderItem')` → `'OrderItems'`\n */\n override pathForType(modelName: string): string {\n return pascalCase(pluralize.plural(modelName));\n }\n\n /**\n * Encodes a record id as an OData key literal.\n * Numeric ids are returned bare (`1`); string ids are single-quoted with\n * inner apostrophes escaped (`o'brien` → `'o''brien'`).\n *\n * Override this method when the service uses a non-default key format (e.g. GUIDs).\n */\n encodeKey(id: string): string {\n if (ODataAdapter.isNumericKey(id)) {\n return id;\n }\n return `'${ODataAdapter.escapeODataString(id)}'`;\n }\n\n override urlForFindRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForUpdateRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForDeleteRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n /**\n * Fetches multiple records by id using a single request.\n * Builds a `$filter=id eq X or id eq Y` expression so only one HTTP round-trip\n * is needed regardless of how many ids are requested.\n */\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n snapshots: AdapterSnapshot[],\n ): Promise<unknown> {\n const base = this.buildURL(modelName, ids, snapshots, 'findMany');\n const filter = ids.map((id) => `id eq ${this.encodeKey(id)}`).join(' or ');\n const url = `${base}?${this._toQueryString({ $filter: filter })}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'query', query);\n const normalized = this._normalizeQuery(query);\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /**\n * Queries for a single record by appending `$top=1` to whatever filter is provided.\n * The caller is responsible for picking the first element from the returned `value` array.\n */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'queryRecord', query);\n const normalized = { ...this._normalizeQuery(query), $top: 1 };\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /** Sends a PATCH request (partial update) as required by the OData v4 spec. */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeSnapshot(snapshot)),\n });\n }\n\n /** Sends a PATCH request with only the changed attributes (partial update). */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const partial: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n partial[key] = current;\n }\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(partial),\n });\n }\n\n /** Extracts the raw attribute map from the snapshot's internal record. */\n protected _serializeSnapshot(snapshot: AdapterSnapshot): Record<string, unknown> {\n const record = snapshot.record as { _data?: Record<string, unknown> };\n const data = record._data;\n const body: Record<string, unknown> = {};\n if (data) {\n Object.assign(body, data);\n }\n return body;\n }\n\n /**\n * Normalises a query hash so every OData system option has its `$` prefix.\n * Bare names (`filter`, `top`, `expand`) are prefixed automatically.\n * Custom (non-system) keys are forwarded verbatim.\n * `null` and `undefined` values are dropped.\n */\n protected _normalizeQuery(\n query: Record<string, unknown>,\n ): Record<string, unknown> {\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n if (ODATA_SYSTEM_QUERY_OPTIONS.has(key)) {\n normalized[key] = value;\n } else if (ODATA_SYSTEM_QUERY_OPTIONS.has(`$${key}`)) {\n normalized[`$${key}`] = value;\n } else {\n normalized[key] = value;\n }\n }\n return normalized;\n }\n\n /** Serialises a key→value map to a `key=value&…` query string (percent-encoded). */\n protected _toQueryString(query: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n return parts.join('&');\n }\n\n /** Returns `?key=value&…` when the query is non-empty, or an empty string. */\n protected _appendQuery(query: Record<string, unknown>): string {\n const queryString = this._toQueryString(query);\n return queryString ? `?${queryString}` : '';\n }\n}\n"],"names":["ODATA_SYSTEM_QUERY_OPTIONS","ODataAdapter","RestAdapter","id","value","modelName","pascalCase","pluralize","_snapshot","_store","ids","snapshots","base","filter","url","query","normalized","snapshot","changed","partial","key","current","data","body","parts","queryString","__decorateClass","injectable"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const h=require("tsyringe"),l=require("pluralize"),d=require("./RestAdapter-
|
|
2
|
-
//# sourceMappingURL=ODataAdapter-
|
|
1
|
+
"use strict";const h=require("tsyringe"),l=require("pluralize"),d=require("./RestAdapter-1V94stW-.cjs");var p=Object.getOwnPropertyDescriptor,y=(o,t,r,e)=>{for(var s=e>1?void 0:e?p(t,r):t,a=o.length-1,n;a>=0;a--)(n=o[a])&&(s=n(s)||s);return s};const u=new Set(["$filter","$select","$orderby","$top","$skip","$expand","$count","$search","$format","$skiptoken"]);exports.ODataAdapter=class extends d.RestAdapter{constructor(){super(...arguments),this.odataVersion="4.0"}static isNumericKey(t){return/^-?\d+(?:\.\d+)?$/.test(t)}static escapeODataString(t){return t.replace(/'/g,"''")}defaultHeaders(){return{Accept:"application/json;odata.metadata=minimal","OData-Version":this.odataVersion,"OData-MaxVersion":this.odataVersion,...this.headers}}mutationHeaders(){return{"Content-Type":"application/json;odata.metadata=minimal",...this.defaultHeaders()}}pathForType(t){return d.pascalCase(l.plural(t))}encodeKey(t){return exports.ODataAdapter.isNumericKey(t)?t:`'${exports.ODataAdapter.escapeODataString(t)}'`}urlForFindRecord(t,r,e){return this._composeURL(`${this.pathForType(r)}(${this.encodeKey(t)})`)}urlForUpdateRecord(t,r,e){return this._composeURL(`${this.pathForType(r)}(${this.encodeKey(t)})`)}urlForDeleteRecord(t,r,e){return this._composeURL(`${this.pathForType(r)}(${this.encodeKey(t)})`)}async findMany(t,r,e,s){const a=this.buildURL(r,e,s,"findMany"),n=e.map(c=>`id eq ${this.encodeKey(c)}`).join(" or "),i=`${a}?${this._toQueryString({$filter:n})}`;return this._fetchJSON(i,{method:"GET",headers:this.defaultHeaders()})}async query(t,r,e){const s=this.buildURL(r,null,null,"query",e),a=this._normalizeQuery(e),n=`${s}${this._appendQuery(a)}`;return this._fetchJSON(n,{method:"GET",headers:this.defaultHeaders()})}async queryRecord(t,r,e){const s=this.buildURL(r,null,null,"queryRecord",e),a={...this._normalizeQuery(e),$top:1},n=`${s}${this._appendQuery(a)}`;return this._fetchJSON(n,{method:"GET",headers:this.defaultHeaders()})}async updateRecord(t,r,e){const s=this.buildURL(r,e.id,e,"updateRecord");return this._fetchJSON(s,{method:"PATCH",headers:this.mutationHeaders(),body:JSON.stringify(this._serializeSnapshot(e))})}async patchRecord(t,r,e){const s=this.buildURL(r,e.id,e,"updateRecord"),a=e.changedAttributes(),n={};for(const[i,[,c]]of Object.entries(a))n[i]=c;return this._fetchJSON(s,{method:"PATCH",headers:this.mutationHeaders(),body:JSON.stringify(n)})}_serializeSnapshot(t){const e=t.record._data,s={};return e&&Object.assign(s,e),s}_normalizeQuery(t){const r={};for(const[e,s]of Object.entries(t))s!=null&&(u.has(e)?r[e]=s:u.has(`$${e}`)?r[`$${e}`]=s:r[e]=s);return r}_toQueryString(t){const r=[];for(const[e,s]of Object.entries(t))s!=null&&r.push(`${encodeURIComponent(e)}=${encodeURIComponent(String(s))}`);return r.join("&")}_appendQuery(t){const r=this._toQueryString(t);return r?`?${r}`:""}};exports.ODataAdapter=y([h.injectable()],exports.ODataAdapter);
|
|
2
|
+
//# sourceMappingURL=ODataAdapter-lMifLyLD.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ODataAdapter-DyyF1sdA.cjs","sources":["../src/odata/ODataAdapter.ts"],"sourcesContent":["import { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport { pascalCase } from 'change-case';\nimport { RestAdapter } from '@mobx-data/adapter';\nimport type { AdapterSnapshot } from '@mobx-data/adapter';\n\n/** All OData v4 system query option names (both bare and $-prefixed forms are checked). */\nconst ODATA_SYSTEM_QUERY_OPTIONS = new Set([\n '$filter',\n '$select',\n '$orderby',\n '$top',\n '$skip',\n '$expand',\n '$count',\n '$search',\n '$format',\n '$skiptoken',\n]);\n\n/**\n * OData v4 adapter.\n *\n * Extends `RestAdapter` with OData-specific conventions:\n * - Entity-set names are PascalCase plural (`user` → `Users`).\n * - Single-entity URLs use key-in-parentheses syntax (`Users(1)`, `Users('abc')`).\n * - Mutations use PATCH instead of PUT.\n * - Accept / Content-Type headers carry the `odata.metadata=minimal` parameter.\n * - System query options (`$filter`, `$expand`, etc.) are passed through verbatim;\n * bare names are auto-prefixed (`filter` → `$filter`).\n */\n@injectable()\nexport class ODataAdapter extends RestAdapter {\n /** OData protocol version sent in `OData-Version` and `OData-MaxVersion` headers. */\n odataVersion: string = '4.0';\n\n static isNumericKey(id: string): boolean {\n return /^-?\\d+(?:\\.\\d+)?$/.test(id);\n }\n\n static escapeODataString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/json;odata.metadata=minimal',\n 'OData-Version': this.odataVersion,\n 'OData-MaxVersion': this.odataVersion,\n ...this.headers,\n };\n }\n\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json;odata.metadata=minimal',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Maps a camelCase/dasherized model name to a PascalCase plural entity-set name.\n * @example `pathForType('orderItem')` → `'OrderItems'`\n */\n override pathForType(modelName: string): string {\n return pascalCase(pluralize.plural(modelName));\n }\n\n /**\n * Encodes a record id as an OData key literal.\n * Numeric ids are returned bare (`1`); string ids are single-quoted with\n * inner apostrophes escaped (`o'brien` → `'o''brien'`).\n *\n * Override this method when the service uses a non-default key format (e.g. GUIDs).\n */\n encodeKey(id: string): string {\n if (ODataAdapter.isNumericKey(id)) {\n return id;\n }\n return `'${ODataAdapter.escapeODataString(id)}'`;\n }\n\n override urlForFindRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForUpdateRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForDeleteRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n /**\n * Fetches multiple records by id using a single request.\n * Builds a `$filter=id eq X or id eq Y` expression so only one HTTP round-trip\n * is needed regardless of how many ids are requested.\n */\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n snapshots: AdapterSnapshot[],\n ): Promise<unknown> {\n const base = this.buildURL(modelName, ids, snapshots, 'findMany');\n const filter = ids.map((id) => `id eq ${this.encodeKey(id)}`).join(' or ');\n const url = `${base}?${this._toQueryString({ $filter: filter })}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'query', query);\n const normalized = this._normalizeQuery(query);\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /**\n * Queries for a single record by appending `$top=1` to whatever filter is provided.\n * The caller is responsible for picking the first element from the returned `value` array.\n */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'queryRecord', query);\n const normalized = { ...this._normalizeQuery(query), $top: 1 };\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /** Sends a PATCH request (partial update) as required by the OData v4 spec. */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeSnapshot(snapshot)),\n });\n }\n\n /** Sends a PATCH request with only the changed attributes (partial update). */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const partial: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n partial[key] = current;\n }\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(partial),\n });\n }\n\n /** Extracts the raw attribute map from the snapshot's internal record. */\n protected _serializeSnapshot(snapshot: AdapterSnapshot): Record<string, unknown> {\n const record = snapshot.record as { _data?: Record<string, unknown> };\n const data = record._data;\n const body: Record<string, unknown> = {};\n if (data) {\n Object.assign(body, data);\n }\n return body;\n }\n\n /**\n * Normalises a query hash so every OData system option has its `$` prefix.\n * Bare names (`filter`, `top`, `expand`) are prefixed automatically.\n * Custom (non-system) keys are forwarded verbatim.\n * `null` and `undefined` values are dropped.\n */\n protected _normalizeQuery(\n query: Record<string, unknown>,\n ): Record<string, unknown> {\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n if (ODATA_SYSTEM_QUERY_OPTIONS.has(key)) {\n normalized[key] = value;\n } else if (ODATA_SYSTEM_QUERY_OPTIONS.has(`$${key}`)) {\n normalized[`$${key}`] = value;\n } else {\n normalized[key] = value;\n }\n }\n return normalized;\n }\n\n /** Serialises a key→value map to a `key=value&…` query string (percent-encoded). */\n protected _toQueryString(query: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n return parts.join('&');\n }\n\n /** Returns `?key=value&…` when the query is non-empty, or an empty string. */\n protected _appendQuery(query: Record<string, unknown>): string {\n const queryString = this._toQueryString(query);\n return queryString ? `?${queryString}` : '';\n }\n}\n"],"names":["ODATA_SYSTEM_QUERY_OPTIONS","ODataAdapter","RestAdapter","id","value","modelName","pascalCase","pluralize","_snapshot","_store","ids","snapshots","base","filter","url","query","normalized","snapshot","changed","partial","key","current","data","body","parts","queryString","__decorateClass","injectable"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ODataAdapter-lMifLyLD.cjs","sources":["../src/odata/ODataAdapter.ts"],"sourcesContent":["import { injectable } from 'tsyringe';\nimport pluralize from 'pluralize';\nimport { pascalCase } from 'change-case';\nimport { RestAdapter } from '@mobx-data/adapter';\nimport type { AdapterSnapshot } from '@mobx-data/adapter';\n\n/** All OData v4 system query option names (both bare and $-prefixed forms are checked). */\nconst ODATA_SYSTEM_QUERY_OPTIONS = new Set([\n '$filter',\n '$select',\n '$orderby',\n '$top',\n '$skip',\n '$expand',\n '$count',\n '$search',\n '$format',\n '$skiptoken',\n]);\n\n/**\n * OData v4 adapter.\n *\n * Extends `RestAdapter` with OData-specific conventions:\n * - Entity-set names are PascalCase plural (`user` → `Users`).\n * - Single-entity URLs use key-in-parentheses syntax (`Users(1)`, `Users('abc')`).\n * - Mutations use PATCH instead of PUT.\n * - Accept / Content-Type headers carry the `odata.metadata=minimal` parameter.\n * - System query options (`$filter`, `$expand`, etc.) are passed through verbatim;\n * bare names are auto-prefixed (`filter` → `$filter`).\n */\n@injectable()\nexport class ODataAdapter extends RestAdapter {\n /** OData protocol version sent in `OData-Version` and `OData-MaxVersion` headers. */\n odataVersion: string = '4.0';\n\n static isNumericKey(id: string): boolean {\n return /^-?\\d+(?:\\.\\d+)?$/.test(id);\n }\n\n static escapeODataString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n override defaultHeaders(): Record<string, string> {\n return {\n Accept: 'application/json;odata.metadata=minimal',\n 'OData-Version': this.odataVersion,\n 'OData-MaxVersion': this.odataVersion,\n ...this.headers,\n };\n }\n\n override mutationHeaders(): Record<string, string> {\n return {\n 'Content-Type': 'application/json;odata.metadata=minimal',\n ...this.defaultHeaders(),\n };\n }\n\n /**\n * Maps a camelCase/dasherized model name to a PascalCase plural entity-set name.\n * @example `pathForType('orderItem')` → `'OrderItems'`\n */\n override pathForType(modelName: string): string {\n return pascalCase(pluralize.plural(modelName));\n }\n\n /**\n * Encodes a record id as an OData key literal.\n * Numeric ids are returned bare (`1`); string ids are single-quoted with\n * inner apostrophes escaped (`o'brien` → `'o''brien'`).\n *\n * Override this method when the service uses a non-default key format (e.g. GUIDs).\n */\n encodeKey(id: string): string {\n if (ODataAdapter.isNumericKey(id)) {\n return id;\n }\n return `'${ODataAdapter.escapeODataString(id)}'`;\n }\n\n override urlForFindRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForUpdateRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n override urlForDeleteRecord(\n id: string,\n modelName: string,\n _snapshot: AdapterSnapshot,\n ): string {\n return this._composeURL(`${this.pathForType(modelName)}(${this.encodeKey(id)})`);\n }\n\n /**\n * Fetches multiple records by id using a single request.\n * Builds a `$filter=id eq X or id eq Y` expression so only one HTTP round-trip\n * is needed regardless of how many ids are requested.\n */\n override async findMany(\n _store: unknown,\n modelName: string,\n ids: string[],\n snapshots: AdapterSnapshot[],\n ): Promise<unknown> {\n const base = this.buildURL(modelName, ids, snapshots, 'findMany');\n const filter = ids.map((id) => `id eq ${this.encodeKey(id)}`).join(' or ');\n const url = `${base}?${this._toQueryString({ $filter: filter })}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n override async query(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'query', query);\n const normalized = this._normalizeQuery(query);\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /**\n * Queries for a single record by appending `$top=1` to whatever filter is provided.\n * The caller is responsible for picking the first element from the returned `value` array.\n */\n override async queryRecord(\n _store: unknown,\n modelName: string,\n query: Record<string, unknown>,\n ): Promise<unknown> {\n const base = this.buildURL(modelName, null, null, 'queryRecord', query);\n const normalized = { ...this._normalizeQuery(query), $top: 1 };\n const url = `${base}${this._appendQuery(normalized)}`;\n return this._fetchJSON(url, {\n method: 'GET',\n headers: this.defaultHeaders(),\n });\n }\n\n /** Sends a PATCH request (partial update) as required by the OData v4 spec. */\n override async updateRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(this._serializeSnapshot(snapshot)),\n });\n }\n\n /** Sends a PATCH request with only the changed attributes (partial update). */\n override async patchRecord(\n _store: unknown,\n modelName: string,\n snapshot: AdapterSnapshot,\n ): Promise<unknown> {\n const url = this.buildURL(modelName, snapshot.id, snapshot, 'updateRecord');\n const changed = snapshot.changedAttributes();\n const partial: Record<string, unknown> = {};\n for (const [key, [, current]] of Object.entries(changed)) {\n partial[key] = current;\n }\n return this._fetchJSON(url, {\n method: 'PATCH',\n headers: this.mutationHeaders(),\n body: JSON.stringify(partial),\n });\n }\n\n /** Extracts the raw attribute map from the snapshot's internal record. */\n protected _serializeSnapshot(snapshot: AdapterSnapshot): Record<string, unknown> {\n const record = snapshot.record as { _data?: Record<string, unknown> };\n const data = record._data;\n const body: Record<string, unknown> = {};\n if (data) {\n Object.assign(body, data);\n }\n return body;\n }\n\n /**\n * Normalises a query hash so every OData system option has its `$` prefix.\n * Bare names (`filter`, `top`, `expand`) are prefixed automatically.\n * Custom (non-system) keys are forwarded verbatim.\n * `null` and `undefined` values are dropped.\n */\n protected _normalizeQuery(\n query: Record<string, unknown>,\n ): Record<string, unknown> {\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n if (ODATA_SYSTEM_QUERY_OPTIONS.has(key)) {\n normalized[key] = value;\n } else if (ODATA_SYSTEM_QUERY_OPTIONS.has(`$${key}`)) {\n normalized[`$${key}`] = value;\n } else {\n normalized[key] = value;\n }\n }\n return normalized;\n }\n\n /** Serialises a key→value map to a `key=value&…` query string (percent-encoded). */\n protected _toQueryString(query: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) {\n continue;\n }\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n return parts.join('&');\n }\n\n /** Returns `?key=value&…` when the query is non-empty, or an empty string. */\n protected _appendQuery(query: Record<string, unknown>): string {\n const queryString = this._toQueryString(query);\n return queryString ? `?${queryString}` : '';\n }\n}\n"],"names":["ODATA_SYSTEM_QUERY_OPTIONS","ODataAdapter","RestAdapter","id","value","modelName","pascalCase","pluralize","_snapshot","_store","ids","snapshots","base","filter","url","query","normalized","snapshot","changed","partial","key","current","data","body","parts","queryString","__decorateClass","injectable"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const p=require("tsyringe"),_=require("pluralize"),y=require("./cache-utils-2lswvJ87.cjs"),F=new RegExp("([\\p{Ll}\\d])(\\p{Lu})","gu"),L=new RegExp("(\\p{Lu})([\\p{Lu}][\\p{Ll}])","gu"),U=new RegExp("(\\d)\\p{Ll}|(\\p{L})\\d","u"),b=/[^\p{L}\d]+/giu,i="$1\0$2",l="";function d(a){let e=a.trim();e=e.replace(F,i).replace(L,i),e=e.replace(b,"\0");let r=0,t=e.length;for(;e.charAt(r)==="\0";)r++;if(r===t)return[];for(;e.charAt(t-1)==="\0";)t--;return e.slice(r,t).split(/\0/g)}function A(a){const e=d(a);for(let r=0;r<e.length;r++){const t=e[r],s=U.exec(t);if(s){const c=s.index+(s[1]??s[2]).length;e.splice(r,1,t.slice(0,c),t.slice(c))}}return e}function T(a,e){const[r,t,s]=f(a,e);return r+t.map(h(e==null?void 0:e.locale)).join((e==null?void 0:e.delimiter)??" ")+s}function S(a,e){const[r,t,s]=f(a,e),c=h(e==null?void 0:e.locale),n=C(e==null?void 0:e.locale),o=E(c,n);return r+t.map(o).join("")+s}function m(a,e){return T(a,{delimiter:"-",...e})}function h(a){return a===!1?e=>e.toLowerCase():e=>e.toLocaleLowerCase(a)}function C(a){return e=>e.toLocaleUpperCase(a)}function E(a,e){return(r,t)=>{const s=r[0];return(t>0&&s>="0"&&s<="9"?"_"+s:e(s))+a(r.slice(1))}}function f(a,e={}){const r=e.split??(e.separateNumbers?A:d),t=e.prefixCharacters??l,s=e.suffixCharacters??l;let c=0,n=a.length;for(;c<a.length;){const o=a.charAt(c);if(!t.includes(o))break;c++}for(;n>c;){const o=n-1,u=a.charAt(o);if(!s.includes(u))break;n=o}return[a.slice(0,c),r(a.slice(c,n)),a.slice(n)]}class R{constructor(){this.namespace="",this.host="",this.headers={},this.coalesceFindRequests=!1}patchRecord(e,r,t){return this.updateRecord(e,r,t)}pathForType(e){return _.plural(m(e))}_composeURL(e){const r=this.namespace.replace(/^\/+|\/+$/g,""),t=this.host?this.host.replace(/\/+$/,""):"",s=[];return t&&s.push(t),r&&s.push(r),s.push(e),t?s.join("/"):`/${s.filter(Boolean).join("/")}`}buildURL(e,r,t,s,c={}){switch(s){case"findRecord":return this.urlForFindRecord(r,e,t);case"findAll":return this.urlForFindAll(e,t??[]);case"findMany":return this.urlForFindMany(r??[],e,t??[]);case"query":return this.urlForQuery(c,e);case"queryRecord":return this.urlForQueryRecord(c,e);case"createRecord":return this.urlForCreateRecord(e,t);case"updateRecord":return this.urlForUpdateRecord(r,e,t);case"deleteRecord":return this.urlForDeleteRecord(r,e,t)}}urlForFindRecord(e,r,t){return this._composeURL(`${this.pathForType(r)}/${encodeURIComponent(e)}`)}urlForFindAll(e,r){return this._composeURL(this.pathForType(e))}urlForFindMany(e,r,t){return this._composeURL(this.pathForType(r))}urlForQuery(e,r){return this._composeURL(this.pathForType(r))}urlForQueryRecord(e,r){return this._composeURL(this.pathForType(r))}urlForCreateRecord(e,r){return this._composeURL(this.pathForType(e))}urlForUpdateRecord(e,r,t){return this._composeURL(`${this.pathForType(r)}/${encodeURIComponent(e)}`)}urlForDeleteRecord(e,r,t){return this._composeURL(`${this.pathForType(r)}/${encodeURIComponent(e)}`)}groupRecordsForFindMany(e,r){return[r]}shouldReloadRecord(e,r){return!1}shouldBackgroundReloadRecord(e,r){return!0}shouldReloadAll(e,r){return!1}shouldBackgroundReloadAll(e,r){return!0}}var g=Object.getOwnPropertyDescriptor,O=(a,e,r,t)=>{for(var s=t>1?void 0:t?g(e,r):e,c=a.length-1,n;c>=0;c--)(n=a[c])&&(s=n(s)||s);return s};exports.RestAdapter=class extends R{static serializeSnapshotToObject(e){const r={},s=e.record._data;if(s)for(const[c,n]of Object.entries(s))c==="__proto__"||c==="constructor"||c==="prototype"||(r[c]=n);return r}static toQueryString(e){const r=[];for(const[t,s]of Object.entries(e))s!=null&&r.push(`${encodeURIComponent(t)}=${encodeURIComponent(String(s))}`);return r.length>0?`?${r.join("&")}`:""}defaultHeaders(){return{Accept:"application/json",...this.headers}}mutationHeaders(){return{"Content-Type":"application/json",...this.defaultHeaders()}}async _fetchJSON(e,r){const t=await fetch(e,r);if(!t.ok){let n=null;try{n=await t.json()}catch{}throw Object.assign(new Error(`Request failed: ${t.status}`),{status:t.status,body:n})}if(t.status===204)return null;const s=await t.text();if(!s)return null;let c;try{c=JSON.parse(s)}catch{c=s}if(c!==null&&typeof c=="object"){const n={};t.headers.forEach((o,u)=>{n[u.toLowerCase()]=o}),y.attachResponseHeaders(c,n)}return c}async findRecord(e,r,t,s,c){let n=this.buildURL(r,t,s,"findRecord");return c!=null&&c.include&&(n+=`${n.includes("?")?"&":"?"}include=${encodeURIComponent(c.include)}`),this._fetchJSON(n,{method:"GET",headers:this.defaultHeaders()})}async findAll(e,r,t,s,c){let n=this.buildURL(r,null,s,"findAll");return c!=null&&c.include&&(n+=`${n.includes("?")?"&":"?"}include=${encodeURIComponent(c.include)}`),this._fetchJSON(n,{method:"GET",headers:this.defaultHeaders()})}async findMany(e,r,t,s){const c=this.buildURL(r,t,s,"findMany"),n=c.includes("?")?"&":"?",o=`${c}${n}ids=${t.map(encodeURIComponent).join(",")}`;return this._fetchJSON(o,{method:"GET",headers:this.defaultHeaders()})}async query(e,r,t){const c=`${this.buildURL(r,null,null,"query",t)}${exports.RestAdapter.toQueryString(t)}`;return this._fetchJSON(c,{method:"GET",headers:this.defaultHeaders()})}async queryRecord(e,r,t){const c=`${this.buildURL(r,null,null,"queryRecord",t)}${exports.RestAdapter.toQueryString(t)}`;return this._fetchJSON(c,{method:"GET",headers:this.defaultHeaders()})}async createRecord(e,r,t){const s=this.buildURL(r,null,t,"createRecord");return this._fetchJSON(s,{method:"POST",headers:this.mutationHeaders(),body:JSON.stringify(exports.RestAdapter.serializeSnapshotToObject(t))})}async updateRecord(e,r,t){const s=this.buildURL(r,t.id,t,"updateRecord");return this._fetchJSON(s,{method:"PUT",headers:this.mutationHeaders(),body:JSON.stringify(exports.RestAdapter.serializeSnapshotToObject(t))})}async patchRecord(e,r,t){const s=this.buildURL(r,t.id,t,"updateRecord"),c=t.changedAttributes(),n={};for(const[o,[,u]]of Object.entries(c))n[o]=u;return this._fetchJSON(s,{method:"PATCH",headers:this.mutationHeaders(),body:JSON.stringify(n)})}async deleteRecord(e,r,t){const s=this.buildURL(r,t.id,t,"deleteRecord");return this._fetchJSON(s,{method:"DELETE",headers:this.defaultHeaders()})}};exports.RestAdapter=O([p.injectable()],exports.RestAdapter);exports.Adapter=R;exports.pascalCase=S;
|
|
2
|
+
//# sourceMappingURL=RestAdapter-1V94stW-.cjs.map
|