yayson 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/legacy.cjs +23 -19
- package/build/legacy.d.cts +1 -1
- package/build/legacy.d.cts.map +1 -1
- package/build/legacy.d.mts +1 -1
- package/build/legacy.d.mts.map +1 -1
- package/build/legacy.mjs +23 -19
- package/build/legacy.mjs.map +1 -1
- package/build/{yayson-C4P8J4sn.cjs → yayson-B51EJfRP.cjs} +63 -8
- package/build/yayson-BvwMr4Ad.d.mts.map +1 -1
- package/build/yayson-DTMLeA5k.d.cts.map +1 -1
- package/build/{yayson-DIQ_olLX.mjs → yayson-RzT9zsdx.mjs} +47 -10
- package/build/yayson-RzT9zsdx.mjs.map +1 -0
- package/build/yayson.cjs +1 -1
- package/build/yayson.mjs +1 -1
- package/package.json +1 -1
- package/build/yayson-DIQ_olLX.mjs.map +0 -1
package/build/legacy.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_symbols = require('./symbols-B--FS78o.cjs');
|
|
2
|
-
const require_yayson = require('./yayson-
|
|
2
|
+
const require_yayson = require('./yayson-B51EJfRP.cjs');
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.ts
|
|
5
5
|
function hasId$1(value) {
|
|
@@ -122,19 +122,20 @@ var LegacyStore = class LegacyStore {
|
|
|
122
122
|
validationErrors;
|
|
123
123
|
models;
|
|
124
124
|
constructor(options) {
|
|
125
|
-
this.types =
|
|
125
|
+
this.types = require_yayson.safeObject();
|
|
126
|
+
Object.assign(this.types, options?.types);
|
|
126
127
|
this.schemas = options?.schemas;
|
|
127
128
|
this.strict = options?.strict ?? false;
|
|
128
129
|
this.records = [];
|
|
129
|
-
this.relations =
|
|
130
|
+
this.relations = require_yayson.safeObject();
|
|
130
131
|
this.validationErrors = [];
|
|
131
|
-
this.models =
|
|
132
|
+
this.models = require_yayson.safeObject();
|
|
132
133
|
}
|
|
133
134
|
reset() {
|
|
134
135
|
this.records = [];
|
|
135
|
-
this.relations =
|
|
136
|
+
this.relations = require_yayson.safeObject();
|
|
136
137
|
this.validationErrors = [];
|
|
137
|
-
this.models =
|
|
138
|
+
this.models = require_yayson.safeObject();
|
|
138
139
|
}
|
|
139
140
|
#createStub(type, id) {
|
|
140
141
|
const stub = { id };
|
|
@@ -144,7 +145,8 @@ var LegacyStore = class LegacyStore {
|
|
|
144
145
|
#resolveRelationships(model, type, resolver) {
|
|
145
146
|
const relations = this.relations[type];
|
|
146
147
|
if (!relations) return;
|
|
147
|
-
for (const attribute
|
|
148
|
+
for (const attribute of Object.keys(relations)) {
|
|
149
|
+
if (require_yayson.isUnsafeKey(attribute)) continue;
|
|
148
150
|
const relationType = relations[attribute];
|
|
149
151
|
const value = model[attribute];
|
|
150
152
|
if (Array.isArray(value)) model[attribute] = value.filter((id) => id != null).map((id) => resolver(relationType, String(id)));
|
|
@@ -161,18 +163,19 @@ var LegacyStore = class LegacyStore {
|
|
|
161
163
|
if (rec.data.links != null) model[require_symbols.LINKS] = rec.data.links;
|
|
162
164
|
if (models && hasId(model)) {
|
|
163
165
|
const idStr = String(model.id);
|
|
164
|
-
if (!models[type]) models[type] =
|
|
166
|
+
if (!models[type]) models[type] = require_yayson.safeObject();
|
|
165
167
|
models[type][idStr] = model;
|
|
166
168
|
}
|
|
167
169
|
const resolver = (relationType, id) => {
|
|
168
|
-
return this.#findModel(relationType, id, models ??
|
|
170
|
+
return this.#findModel(relationType, id, models ?? require_yayson.safeObject()) ?? this.#createStub(relationType, id);
|
|
169
171
|
};
|
|
170
172
|
this.#resolveRelationships(model, type, resolver);
|
|
171
173
|
return model;
|
|
172
174
|
}
|
|
173
|
-
toModel(rec, type,
|
|
175
|
+
toModel(rec, type, modelsArg) {
|
|
174
176
|
const idStr = String(rec.data.id);
|
|
175
|
-
|
|
177
|
+
const models = require_yayson.safeCache(modelsArg);
|
|
178
|
+
if (!models[type]) models[type] = require_yayson.safeObject();
|
|
176
179
|
if (models[type][idStr]) return models[type][idStr];
|
|
177
180
|
const result = this.#createModel(rec, type, { models });
|
|
178
181
|
if (!hasId(result)) throw new Error(`Expected model of type ${type} to have an id`);
|
|
@@ -195,13 +198,14 @@ var LegacyStore = class LegacyStore {
|
|
|
195
198
|
return model;
|
|
196
199
|
}
|
|
197
200
|
setupRelations(links) {
|
|
198
|
-
for (const key
|
|
201
|
+
for (const key of Object.keys(links)) {
|
|
199
202
|
const value = links[key];
|
|
200
203
|
const parts = key.split(".");
|
|
201
204
|
const typeRaw = parts[0];
|
|
202
205
|
const attribute = parts[1];
|
|
206
|
+
if (require_yayson.isUnsafeKey(attribute)) continue;
|
|
203
207
|
const type = this.types[typeRaw] || typeRaw;
|
|
204
|
-
if (!this.relations[type]) this.relations[type] =
|
|
208
|
+
if (!this.relations[type]) this.relations[type] = require_yayson.safeObject();
|
|
205
209
|
this.relations[type][attribute] = this.types[value.type] || value.type;
|
|
206
210
|
}
|
|
207
211
|
}
|
|
@@ -222,7 +226,7 @@ var LegacyStore = class LegacyStore {
|
|
|
222
226
|
build(data) {
|
|
223
227
|
if (data.links) this.setupRelations(data.links);
|
|
224
228
|
let name;
|
|
225
|
-
for (const key
|
|
229
|
+
for (const key of Object.keys(data)) if (key !== "meta" && key !== "links") {
|
|
226
230
|
name = key;
|
|
227
231
|
break;
|
|
228
232
|
}
|
|
@@ -248,14 +252,14 @@ var LegacyStore = class LegacyStore {
|
|
|
248
252
|
return model;
|
|
249
253
|
}
|
|
250
254
|
find(type, id, models) {
|
|
251
|
-
return this.#findModel(type, String(id), models ?? this.models);
|
|
255
|
+
return this.#findModel(type, String(id), require_yayson.safeCache(models ?? this.models));
|
|
252
256
|
}
|
|
253
257
|
findAll(type, models) {
|
|
254
|
-
const modelsObj = models ?? this.models;
|
|
258
|
+
const modelsObj = require_yayson.safeCache(models ?? this.models);
|
|
255
259
|
const recs = this.findRecords(type);
|
|
256
260
|
if (recs.length === 0) return [];
|
|
257
261
|
recs.forEach((rec) => {
|
|
258
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
262
|
+
if (!modelsObj[type]) modelsObj[type] = require_yayson.safeObject();
|
|
259
263
|
return this.toModel(rec, type, modelsObj);
|
|
260
264
|
});
|
|
261
265
|
return Object.values(modelsObj[type] || {});
|
|
@@ -274,10 +278,10 @@ var LegacyStore = class LegacyStore {
|
|
|
274
278
|
}
|
|
275
279
|
syncAll(data) {
|
|
276
280
|
this.validationErrors = [];
|
|
277
|
-
this.models =
|
|
281
|
+
this.models = require_yayson.safeObject();
|
|
278
282
|
if (data.links) this.setupRelations(data.links);
|
|
279
283
|
const syncedRecords = [];
|
|
280
|
-
for (const name
|
|
284
|
+
for (const name of Object.keys(data)) {
|
|
281
285
|
if (name === "meta" || name === "links") continue;
|
|
282
286
|
const value = data[name];
|
|
283
287
|
const type = this.types[name] || name;
|
package/build/legacy.d.cts
CHANGED
|
@@ -112,7 +112,7 @@ declare class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {
|
|
|
112
112
|
models: StoreModels;
|
|
113
113
|
constructor(options?: LegacyStoreOptions<S>);
|
|
114
114
|
reset(): void;
|
|
115
|
-
toModel(rec: LegacyStoreRecordType, type: string,
|
|
115
|
+
toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel;
|
|
116
116
|
setupRelations(links: LegacyLinks): void;
|
|
117
117
|
findRecord(type: string, id: string): LegacyStoreRecordType | undefined;
|
|
118
118
|
findRecords(type: string): LegacyStoreRecordType[];
|
package/build/legacy.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.d.cts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":";;;;UASU,qBAAA,SAA8B,eAAA;EAAA,CACrC,GAAA;AAAA;AAAA,iBAIqB,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,aASjC,eAAA;iBAbV;WAOK,qBAAA;;yBAqBM,SAAA,UAAmB,MAAA;gCA8BZ,qBAAA,EAAqB,QAAA,EAAY,SAAA;iCAsCrC,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,sBAAA,GACT,qBAAA;sBA6De,SAAA,GAAY,qBAAA;iCAWD,SAAA,GAAY,SAAA,YAAqB,qBAAA;;;;;;qBAzElD;;;;;wCAyE6B,oCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAKjB,SAAA,GAAY,SAAA,WAAkB,OAAA,GAC1C,sBAAA,GACT,qBAAA;+BAKqB,SAAA,GAAY,SAAA,WAAkB,QAAA,GACzC,sBAAA,GACV,qBAAA;oBAIsB,SAAA,GAAY,qBAAA;kBAAqB,OAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"legacy.d.cts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":"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"}
|
package/build/legacy.d.mts
CHANGED
|
@@ -112,7 +112,7 @@ declare class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {
|
|
|
112
112
|
models: StoreModels;
|
|
113
113
|
constructor(options?: LegacyStoreOptions<S>);
|
|
114
114
|
reset(): void;
|
|
115
|
-
toModel(rec: LegacyStoreRecordType, type: string,
|
|
115
|
+
toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel;
|
|
116
116
|
setupRelations(links: LegacyLinks): void;
|
|
117
117
|
findRecord(type: string, id: string): LegacyStoreRecordType | undefined;
|
|
118
118
|
findRecords(type: string): LegacyStoreRecordType[];
|
package/build/legacy.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.d.mts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":";;;;UASU,qBAAA,SAA8B,eAAA;EAAA,CACrC,GAAA;AAAA;AAAA,iBAIqB,qBAAA,CAAsB,SAAA,EAAW,SAAA;EAAA,aASjC,eAAA;iBAbV;WAOK,qBAAA;;yBAqBM,SAAA,UAAmB,MAAA;gCA8BZ,qBAAA,EAAqB,QAAA,EAAY,SAAA;iCAsCrC,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,sBAAA,GACT,qBAAA;sBA6De,SAAA,GAAY,qBAAA;iCAWD,SAAA,GAAY,SAAA,YAAqB,qBAAA;;;;;;qBAzElD;;;;;wCAyE6B,oCAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAKjB,SAAA,GAAY,SAAA,WAAkB,OAAA,GAC1C,sBAAA,GACT,qBAAA;+BAKqB,SAAA,GAAY,SAAA,WAAkB,QAAA,GACzC,sBAAA,GACV,qBAAA;oBAIsB,SAAA,GAAY,qBAAA;kBAAqB,OAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"legacy.d.mts","names":[],"sources":["../../../../../../yayson/legacy-presenter.ts","../../../../../../yayson/legacy-store.ts","../../../../../../legacy.ts"],"mappings":"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"}
|
package/build/legacy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as TYPE, n as META, t as LINKS } from "./symbols-BfU4k1el.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as validate, i as safeObject, n as isUnsafeKey, o as filterByFields, r as safeCache, t as yayson_default } from "./yayson-RzT9zsdx.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/yayson/legacy-presenter.ts
|
|
5
5
|
function hasId$1(value) {
|
|
@@ -122,19 +122,20 @@ var LegacyStore = class LegacyStore {
|
|
|
122
122
|
validationErrors;
|
|
123
123
|
models;
|
|
124
124
|
constructor(options) {
|
|
125
|
-
this.types =
|
|
125
|
+
this.types = safeObject();
|
|
126
|
+
Object.assign(this.types, options?.types);
|
|
126
127
|
this.schemas = options?.schemas;
|
|
127
128
|
this.strict = options?.strict ?? false;
|
|
128
129
|
this.records = [];
|
|
129
|
-
this.relations =
|
|
130
|
+
this.relations = safeObject();
|
|
130
131
|
this.validationErrors = [];
|
|
131
|
-
this.models =
|
|
132
|
+
this.models = safeObject();
|
|
132
133
|
}
|
|
133
134
|
reset() {
|
|
134
135
|
this.records = [];
|
|
135
|
-
this.relations =
|
|
136
|
+
this.relations = safeObject();
|
|
136
137
|
this.validationErrors = [];
|
|
137
|
-
this.models =
|
|
138
|
+
this.models = safeObject();
|
|
138
139
|
}
|
|
139
140
|
#createStub(type, id) {
|
|
140
141
|
const stub = { id };
|
|
@@ -144,7 +145,8 @@ var LegacyStore = class LegacyStore {
|
|
|
144
145
|
#resolveRelationships(model, type, resolver) {
|
|
145
146
|
const relations = this.relations[type];
|
|
146
147
|
if (!relations) return;
|
|
147
|
-
for (const attribute
|
|
148
|
+
for (const attribute of Object.keys(relations)) {
|
|
149
|
+
if (isUnsafeKey(attribute)) continue;
|
|
148
150
|
const relationType = relations[attribute];
|
|
149
151
|
const value = model[attribute];
|
|
150
152
|
if (Array.isArray(value)) model[attribute] = value.filter((id) => id != null).map((id) => resolver(relationType, String(id)));
|
|
@@ -161,18 +163,19 @@ var LegacyStore = class LegacyStore {
|
|
|
161
163
|
if (rec.data.links != null) model[LINKS] = rec.data.links;
|
|
162
164
|
if (models && hasId(model)) {
|
|
163
165
|
const idStr = String(model.id);
|
|
164
|
-
if (!models[type]) models[type] =
|
|
166
|
+
if (!models[type]) models[type] = safeObject();
|
|
165
167
|
models[type][idStr] = model;
|
|
166
168
|
}
|
|
167
169
|
const resolver = (relationType, id) => {
|
|
168
|
-
return this.#findModel(relationType, id, models ??
|
|
170
|
+
return this.#findModel(relationType, id, models ?? safeObject()) ?? this.#createStub(relationType, id);
|
|
169
171
|
};
|
|
170
172
|
this.#resolveRelationships(model, type, resolver);
|
|
171
173
|
return model;
|
|
172
174
|
}
|
|
173
|
-
toModel(rec, type,
|
|
175
|
+
toModel(rec, type, modelsArg) {
|
|
174
176
|
const idStr = String(rec.data.id);
|
|
175
|
-
|
|
177
|
+
const models = safeCache(modelsArg);
|
|
178
|
+
if (!models[type]) models[type] = safeObject();
|
|
176
179
|
if (models[type][idStr]) return models[type][idStr];
|
|
177
180
|
const result = this.#createModel(rec, type, { models });
|
|
178
181
|
if (!hasId(result)) throw new Error(`Expected model of type ${type} to have an id`);
|
|
@@ -195,13 +198,14 @@ var LegacyStore = class LegacyStore {
|
|
|
195
198
|
return model;
|
|
196
199
|
}
|
|
197
200
|
setupRelations(links) {
|
|
198
|
-
for (const key
|
|
201
|
+
for (const key of Object.keys(links)) {
|
|
199
202
|
const value = links[key];
|
|
200
203
|
const parts = key.split(".");
|
|
201
204
|
const typeRaw = parts[0];
|
|
202
205
|
const attribute = parts[1];
|
|
206
|
+
if (isUnsafeKey(attribute)) continue;
|
|
203
207
|
const type = this.types[typeRaw] || typeRaw;
|
|
204
|
-
if (!this.relations[type]) this.relations[type] =
|
|
208
|
+
if (!this.relations[type]) this.relations[type] = safeObject();
|
|
205
209
|
this.relations[type][attribute] = this.types[value.type] || value.type;
|
|
206
210
|
}
|
|
207
211
|
}
|
|
@@ -222,7 +226,7 @@ var LegacyStore = class LegacyStore {
|
|
|
222
226
|
build(data) {
|
|
223
227
|
if (data.links) this.setupRelations(data.links);
|
|
224
228
|
let name;
|
|
225
|
-
for (const key
|
|
229
|
+
for (const key of Object.keys(data)) if (key !== "meta" && key !== "links") {
|
|
226
230
|
name = key;
|
|
227
231
|
break;
|
|
228
232
|
}
|
|
@@ -248,14 +252,14 @@ var LegacyStore = class LegacyStore {
|
|
|
248
252
|
return model;
|
|
249
253
|
}
|
|
250
254
|
find(type, id, models) {
|
|
251
|
-
return this.#findModel(type, String(id), models ?? this.models);
|
|
255
|
+
return this.#findModel(type, String(id), safeCache(models ?? this.models));
|
|
252
256
|
}
|
|
253
257
|
findAll(type, models) {
|
|
254
|
-
const modelsObj = models ?? this.models;
|
|
258
|
+
const modelsObj = safeCache(models ?? this.models);
|
|
255
259
|
const recs = this.findRecords(type);
|
|
256
260
|
if (recs.length === 0) return [];
|
|
257
261
|
recs.forEach((rec) => {
|
|
258
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
262
|
+
if (!modelsObj[type]) modelsObj[type] = safeObject();
|
|
259
263
|
return this.toModel(rec, type, modelsObj);
|
|
260
264
|
});
|
|
261
265
|
return Object.values(modelsObj[type] || {});
|
|
@@ -274,10 +278,10 @@ var LegacyStore = class LegacyStore {
|
|
|
274
278
|
}
|
|
275
279
|
syncAll(data) {
|
|
276
280
|
this.validationErrors = [];
|
|
277
|
-
this.models =
|
|
281
|
+
this.models = safeObject();
|
|
278
282
|
if (data.links) this.setupRelations(data.links);
|
|
279
283
|
const syncedRecords = [];
|
|
280
|
-
for (const name
|
|
284
|
+
for (const name of Object.keys(data)) {
|
|
281
285
|
if (name === "meta" || name === "links") continue;
|
|
282
286
|
const value = data[name];
|
|
283
287
|
const type = this.types[name] || name;
|
package/build/legacy.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"legacy.mjs","names":["hasId","#findModel","#createStub","#resolveRelationships","#createModel","result","yaysonFactory"],"sources":["../src/yayson/legacy-presenter.ts","../src/yayson/legacy-store.ts","../src/legacy.ts"],"sourcesContent":["import type { ModelLike } from './adapter.js'\nimport type { Presenter } from './presenter.js'\nimport type { JsonApiDocument, JsonApiLinks, LegacyPresenterOptions } from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction hasId(value: unknown): value is { id: unknown } {\n return typeof value === 'object' && value !== null && 'id' in value\n}\n\ninterface LegacyJsonApiDocument extends JsonApiDocument {\n [key: string]: unknown\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createLegacyPresenter(Presenter: Presenter) {\n return class LegacyPresenter extends Presenter {\n declare ['constructor']: typeof LegacyPresenter\n declare scope: LegacyJsonApiDocument\n\n static type = 'object'\n static plural?: string\n static fields?: string[]\n\n constructor(scope?: JsonApiDocument) {\n // LegacyPresenter doesn't use the 'data' property, so pass an empty scope\n const emptyScope: JsonApiDocument = { data: null }\n super(scope || emptyScope)\n // Remove the 'data' property that the parent constructor adds\n if (!scope) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Need Partial to allow delete\n delete (this.scope as Partial<JsonApiDocument>).data\n }\n }\n\n pluralType(): string {\n return this.constructor.plural || this.constructor.type + 's'\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (!instance) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n let id: unknown\n const data = attributes[key]\n if (data == null) {\n id = attributes[key + 'Id']\n if (id != null) {\n attributes[key] = id\n }\n } else if (Array.isArray(data)) {\n attributes[key] = data.map((obj: unknown) => (hasId(obj) ? obj.id : obj))\n } else if (hasId(data)) {\n attributes[key] = data.id\n }\n }\n }\n\n // Include relationship keys in allowed fields (so users don't need to list them twice)\n const relationshipKeys = relationships ? Object.keys(relationships) : []\n const allowedFields = this.constructor.fields ? [...this.constructor.fields, ...relationshipKeys] : undefined\n\n return filterByFields(attributes, allowedFields)\n }\n\n includeRelationships(scope: LegacyJsonApiDocument, instance: ModelLike): unknown[] {\n if (!scope.links) {\n scope.links = {}\n }\n const relationships = this.relationships()\n const result: unknown[] = []\n\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const entry = relationships[key]\n if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n const factory = typeof entry === 'function' ? entry : entry.presenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Factory returns PresenterInstance, we know it's LegacyPresenter\n const presenter = new factory(scope) as LegacyPresenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n if (data != null) {\n presenter.toJSON(data, { defaultPlural: true })\n }\n\n const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type\n const presenterType = presenter.constructor.type\n const keyName = scope[presenter.pluralType()] != null ? presenter.pluralType() : presenterType\n const link = { type: keyName }\n if (scope.links) {\n scope.links[`${type}.${key}`] = link\n }\n result.push(link)\n }\n return result\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n const opts = options ?? {}\n if (!this.scope.links) {\n this.scope.links = {}\n }\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n const type = this.pluralType()\n if (!this.scope[type]) {\n this.scope[type] = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance)\n })\n } else {\n let links: JsonApiLinks | undefined\n const instance = instanceOrCollection\n let added = true\n const attrs = instance ? this.attributes(instance) : null\n if ((links = this.links())) {\n if (attrs) {\n attrs.links = links\n }\n }\n // If eg x.image already exists\n if (this.scope[this.constructor.type] && !this.scope[this.pluralType()]) {\n const existingValue = this.scope[this.constructor.type]\n if (attrs && hasId(existingValue) && existingValue.id !== attrs.id) {\n this.scope[this.pluralType()] = [this.scope[this.constructor.type]]\n delete this.scope[this.constructor.type]\n const pluralArray = this.scope[this.pluralType()]\n if (Array.isArray(pluralArray)) {\n pluralArray.push(attrs)\n }\n } else {\n added = false\n }\n\n // If eg x.images already exists\n } else if (this.scope[this.pluralType()]) {\n const existing = this.scope[this.pluralType()]\n if (Array.isArray(existing)) {\n if (attrs && !existing.some((i) => hasId(i) && i.id === attrs.id)) {\n existing.push(attrs)\n } else {\n added = false\n }\n }\n } else if (opts.defaultPlural) {\n this.scope[this.pluralType()] = attrs ? [attrs] : []\n } else {\n this.scope[this.constructor.type] = attrs\n }\n\n if (added && instance) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike): LegacyJsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Legacy payload intentionally omits `data`\n return { [this.constructor.type]: this.attributes(instance) } as LegacyJsonApiDocument\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null): LegacyJsonApiDocument {\n return this.toJSON(instanceOrCollection)\n }\n\n static toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n _options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().render(instanceOrCollection)\n }\n\n static payload(instance: ModelLike): LegacyJsonApiDocument {\n return new this().payload(instance)\n }\n }\n}\n","import type {\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreResult,\n SchemaRegistry,\n ValidationError,\n InferModelType,\n LegacyStoreOptions,\n} from './types.js'\nimport { TYPE, LINKS, META } from './symbols.js'\nimport { validate } from './schema.js'\n\ninterface LegacyStoreRecordType {\n type: string\n data: Record<string, unknown> & {\n id?: string | number\n meta?: Record<string, unknown>\n links?: Record<string, unknown>\n }\n}\n\ninterface LegacyLinks {\n [key: string]: {\n type: string\n }\n}\n\ntype LegacyDataValue = Record<string, unknown> | Array<Record<string, unknown>>\n\nexport interface LegacyData {\n links?: LegacyLinks\n meta?: Record<string, unknown>\n [key: string]: LegacyDataValue | LegacyLinks | Record<string, unknown> | undefined\n}\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nexport default class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {\n types: Record<string, string>\n records: LegacyStoreRecordType[]\n relations: Record<string, Record<string, string>>\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[]\n models: StoreModels\n\n constructor(options?: LegacyStoreOptions<S>) {\n this.types = options?.types || {}\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.records = []\n this.relations = {}\n this.validationErrors = []\n this.models = {}\n }\n\n reset(): void {\n this.records = []\n this.relations = {}\n this.validationErrors = []\n this.models = {}\n }\n\n #createStub(type: string, id: string): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n type: string,\n resolver: (relationType: string, id: string) => StoreModel,\n ): void {\n const relations = this.relations[type]\n if (!relations) return\n\n for (const attribute in relations) {\n const relationType = relations[attribute]!\n const value = model[attribute]\n if (Array.isArray(value)) {\n model[attribute] = value\n .filter((id: unknown) => id != null)\n .map((id: unknown) => resolver(relationType, String(id)))\n } else if (value != null) {\n model[attribute] = resolver(relationType, String(value))\n } else {\n model[attribute] = null\n }\n }\n }\n\n #createModel(rec: LegacyStoreRecordType, type: string, options?: { models?: StoreModels }): StoreModelWithOptionalId {\n const models = options?.models\n\n const model: StoreModelWithOptionalId = { ...rec.data }\n if (rec.data.id != null) {\n model.id = rec.data.id\n }\n model[TYPE] = type\n if (rec.data.meta != null) {\n model[META] = rec.data.meta\n }\n if (rec.data.links != null) {\n model[LINKS] = rec.data.links\n }\n\n if (models && hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = {}\n }\n models[type]![idStr] = model\n }\n\n const resolver = (relationType: string, id: string): StoreModel => {\n return this.#findModel(relationType, id, models ?? {}) ?? this.#createStub(relationType, id)\n }\n this.#resolveRelationships(model, type, resolver)\n\n return model\n }\n\n toModel(rec: LegacyStoreRecordType, type: string, models: StoreModels): StoreModel {\n const idStr = String(rec.data.id)\n\n if (!models[type]) {\n models[type] = {}\n }\n\n if (models[type]![idStr]) {\n return models[type]![idStr]!\n }\n\n const result = this.#createModel(rec, type, { models })\n if (!hasId(result)) {\n throw new Error(`Expected model of type ${type} to have an id`)\n }\n const model = result\n\n if (this.schemas && this.schemas[type]) {\n const schema = this.schemas[type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type,\n id: idStr,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n models[type]![idStr] = validatedModel\n return validatedModel\n }\n\n return model\n }\n\n setupRelations(links: LegacyLinks): void {\n for (const key in links) {\n const value = links[key]!\n const parts = key.split('.')\n const typeRaw = parts[0]!\n const attribute = parts[1]!\n const type = this.types[typeRaw] || typeRaw\n if (!this.relations[type]) {\n this.relations[type] = {}\n }\n this.relations[type]![attribute] = this.types[value.type] || value.type\n }\n }\n\n findRecord(type: string, id: string): LegacyStoreRecordType | undefined {\n return this.records.find((r) => r.type === type && String(r.data.id) === id)\n }\n\n findRecords(type: string): LegacyStoreRecordType[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string, models: StoreModels): StoreModel | null {\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return models[type]?.[id] ?? this.toModel(rec, type, models)\n }\n\n static build(data: LegacyData): StoreModelWithOptionalId {\n return new LegacyStore().build(data)\n }\n\n build(data: LegacyData): StoreModelWithOptionalId {\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n let name: string | undefined\n for (const key in data) {\n if (key !== 'meta' && key !== 'links') {\n name = key\n break\n }\n }\n\n if (name == null) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const value = data[name]\n if (value == null || Array.isArray(value)) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const type = this.types[name] || name\n return this.#createModel({ type, data: value }, type)\n }\n\n /** @deprecated Use retrieve() instead. */\n retrive<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n return this.retrieve(type, data)\n }\n\n retrieve<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n const synced = this.syncAll(data)\n const normalizedType = this.types[type] || type\n const model = synced.find((m) => m[TYPE] === normalizedType)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, String(id), models ?? this.models)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = models ?? this.models\n const recs = this.findRecords(type)\n if (recs.length === 0) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = {}\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const normalizedType = this.types[type] || type\n\n const removeOne = (record: LegacyStoreRecordType): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const idStr = String(id)\n const record = this.findRecord(normalizedType, idStr)\n if (record) {\n removeOne(record)\n }\n } else {\n const records = this.findRecords(normalizedType)\n records.forEach(removeOne)\n }\n }\n\n syncAll(data: LegacyData): StoreResult {\n // Clear validation errors and models cache from previous sync\n this.validationErrors = []\n this.models = {}\n\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n const syncedRecords: LegacyStoreRecordType[] = []\n\n for (const name in data) {\n if (name === 'meta' || name === 'links') {\n continue\n }\n\n const value = data[name]!\n const type = this.types[name] || name\n\n const add = (d: Record<string, unknown>): void => {\n this.remove(type, String(d.id))\n const rec: LegacyStoreRecordType = { type, data: d }\n this.records.push(rec)\n syncedRecords.push(rec)\n }\n\n if (Array.isArray(value)) {\n value.forEach(add)\n } else if (typeof value === 'object' && value !== null) {\n add(value)\n }\n }\n\n for (const rec of syncedRecords) {\n this.toModel(rec, rec.type, this.models)\n }\n\n const result: StoreResult = syncedRecords.map((rec) => this.models[rec.type]![String(rec.data.id)]!)\n if (data.meta != null) {\n result[META] = data.meta\n }\n return result\n }\n\n sync(data: LegacyData): StoreModel | StoreResult {\n const result = this.syncAll(data)\n if (result.length === 1) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n retrieveAll<T extends string>(type: T, data: LegacyData): StoreResult<InferModelType<S, T>> {\n const normalizedType = this.types[type] || type\n const synced = this.syncAll(data)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter(\n (model) => model[TYPE] === normalizedType,\n ) as StoreResult<InferModelType<S, T>>\n result[META] = synced[META]\n return result\n }\n}\n","import yaysonFactory from './yayson.js'\nimport createLegacyPresenter from './yayson/legacy-presenter.js'\nimport LegacyStore from './yayson/legacy-store.js'\nimport type { LegacyData } from './yayson/legacy-store.js'\nimport Adapter from './yayson/adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n} from './yayson/types.js'\nimport type { YaysonOptions } from './yayson.js'\n\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyData,\n}\n\ninterface LegacyYaysonResult {\n Store: typeof LegacyStore\n Presenter: ReturnType<typeof createLegacyPresenter>\n Adapter: ReturnType<typeof yaysonFactory>['Adapter']\n}\n\nexport default function yayson(options?: YaysonOptions): LegacyYaysonResult {\n const { Presenter, Adapter } = yaysonFactory(options)\n return {\n Store: LegacyStore,\n Presenter: createLegacyPresenter(Presenter),\n Adapter,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"legacy.mjs","names":["hasId","#findModel","#createStub","#resolveRelationships","#createModel","result","yaysonFactory"],"sources":["../src/yayson/legacy-presenter.ts","../src/yayson/legacy-store.ts","../src/legacy.ts"],"sourcesContent":["import type { ModelLike } from './adapter.js'\nimport type { Presenter } from './presenter.js'\nimport type { JsonApiDocument, JsonApiLinks, LegacyPresenterOptions } from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction hasId(value: unknown): value is { id: unknown } {\n return typeof value === 'object' && value !== null && 'id' in value\n}\n\ninterface LegacyJsonApiDocument extends JsonApiDocument {\n [key: string]: unknown\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createLegacyPresenter(Presenter: Presenter) {\n return class LegacyPresenter extends Presenter {\n declare ['constructor']: typeof LegacyPresenter\n declare scope: LegacyJsonApiDocument\n\n static type = 'object'\n static plural?: string\n static fields?: string[]\n\n constructor(scope?: JsonApiDocument) {\n // LegacyPresenter doesn't use the 'data' property, so pass an empty scope\n const emptyScope: JsonApiDocument = { data: null }\n super(scope || emptyScope)\n // Remove the 'data' property that the parent constructor adds\n if (!scope) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Need Partial to allow delete\n delete (this.scope as Partial<JsonApiDocument>).data\n }\n }\n\n pluralType(): string {\n return this.constructor.plural || this.constructor.type + 's'\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (!instance) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n let id: unknown\n const data = attributes[key]\n if (data == null) {\n id = attributes[key + 'Id']\n if (id != null) {\n attributes[key] = id\n }\n } else if (Array.isArray(data)) {\n attributes[key] = data.map((obj: unknown) => (hasId(obj) ? obj.id : obj))\n } else if (hasId(data)) {\n attributes[key] = data.id\n }\n }\n }\n\n // Include relationship keys in allowed fields (so users don't need to list them twice)\n const relationshipKeys = relationships ? Object.keys(relationships) : []\n const allowedFields = this.constructor.fields ? [...this.constructor.fields, ...relationshipKeys] : undefined\n\n return filterByFields(attributes, allowedFields)\n }\n\n includeRelationships(scope: LegacyJsonApiDocument, instance: ModelLike): unknown[] {\n if (!scope.links) {\n scope.links = {}\n }\n const relationships = this.relationships()\n const result: unknown[] = []\n\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const entry = relationships[key]\n if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n const factory = typeof entry === 'function' ? entry : entry.presenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Factory returns PresenterInstance, we know it's LegacyPresenter\n const presenter = new factory(scope) as LegacyPresenter\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n if (data != null) {\n presenter.toJSON(data, { defaultPlural: true })\n }\n\n const type = scope[this.pluralType()] != null ? this.pluralType() : this.constructor.type\n const presenterType = presenter.constructor.type\n const keyName = scope[presenter.pluralType()] != null ? presenter.pluralType() : presenterType\n const link = { type: keyName }\n if (scope.links) {\n scope.links[`${type}.${key}`] = link\n }\n result.push(link)\n }\n return result\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n const opts = options ?? {}\n if (!this.scope.links) {\n this.scope.links = {}\n }\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n const type = this.pluralType()\n if (!this.scope[type]) {\n this.scope[type] = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance)\n })\n } else {\n let links: JsonApiLinks | undefined\n const instance = instanceOrCollection\n let added = true\n const attrs = instance ? this.attributes(instance) : null\n if ((links = this.links())) {\n if (attrs) {\n attrs.links = links\n }\n }\n // If eg x.image already exists\n if (this.scope[this.constructor.type] && !this.scope[this.pluralType()]) {\n const existingValue = this.scope[this.constructor.type]\n if (attrs && hasId(existingValue) && existingValue.id !== attrs.id) {\n this.scope[this.pluralType()] = [this.scope[this.constructor.type]]\n delete this.scope[this.constructor.type]\n const pluralArray = this.scope[this.pluralType()]\n if (Array.isArray(pluralArray)) {\n pluralArray.push(attrs)\n }\n } else {\n added = false\n }\n\n // If eg x.images already exists\n } else if (this.scope[this.pluralType()]) {\n const existing = this.scope[this.pluralType()]\n if (Array.isArray(existing)) {\n if (attrs && !existing.some((i) => hasId(i) && i.id === attrs.id)) {\n existing.push(attrs)\n } else {\n added = false\n }\n }\n } else if (opts.defaultPlural) {\n this.scope[this.pluralType()] = attrs ? [attrs] : []\n } else {\n this.scope[this.constructor.type] = attrs\n }\n\n if (added && instance) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike): LegacyJsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Legacy payload intentionally omits `data`\n return { [this.constructor.type]: this.attributes(instance) } as LegacyJsonApiDocument\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null): LegacyJsonApiDocument {\n return this.toJSON(instanceOrCollection)\n }\n\n static toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(\n instanceOrCollection: ModelLike | ModelLike[] | null,\n _options?: LegacyPresenterOptions,\n ): LegacyJsonApiDocument {\n return new this().render(instanceOrCollection)\n }\n\n static payload(instance: ModelLike): LegacyJsonApiDocument {\n return new this().payload(instance)\n }\n }\n}\n","import type {\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreResult,\n SchemaRegistry,\n ValidationError,\n InferModelType,\n LegacyStoreOptions,\n} from './types.js'\nimport { TYPE, LINKS, META } from './symbols.js'\nimport { validate } from './schema.js'\nimport { safeObject, safeCache, isUnsafeKey } from './safe.js'\n\ninterface LegacyStoreRecordType {\n type: string\n data: Record<string, unknown> & {\n id?: string | number\n meta?: Record<string, unknown>\n links?: Record<string, unknown>\n }\n}\n\ninterface LegacyLinks {\n [key: string]: {\n type: string\n }\n}\n\ntype LegacyDataValue = Record<string, unknown> | Array<Record<string, unknown>>\n\nexport interface LegacyData {\n links?: LegacyLinks\n meta?: Record<string, unknown>\n [key: string]: LegacyDataValue | LegacyLinks | Record<string, unknown> | undefined\n}\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nexport default class LegacyStore<S extends SchemaRegistry = SchemaRegistry> {\n types: Record<string, string>\n records: LegacyStoreRecordType[]\n relations: Record<string, Record<string, string>>\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[]\n models: StoreModels\n\n constructor(options?: LegacyStoreOptions<S>) {\n // Null-prototype: read with untrusted `name`/`type` values, so \"__proto__\"\n // must not resolve to Object.prototype.\n this.types = safeObject<Record<string, string>>()\n Object.assign(this.types, options?.types)\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.records = []\n this.relations = safeObject<Record<string, Record<string, string>>>()\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n }\n\n reset(): void {\n this.records = []\n this.relations = safeObject<Record<string, Record<string, string>>>()\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n }\n\n #createStub(type: string, id: string): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n type: string,\n resolver: (relationType: string, id: string) => StoreModel,\n ): void {\n const relations = this.relations[type]\n if (!relations) return\n\n for (const attribute of Object.keys(relations)) {\n if (isUnsafeKey(attribute)) {\n continue\n }\n const relationType = relations[attribute]!\n const value = model[attribute]\n if (Array.isArray(value)) {\n model[attribute] = value\n .filter((id: unknown) => id != null)\n .map((id: unknown) => resolver(relationType, String(id)))\n } else if (value != null) {\n model[attribute] = resolver(relationType, String(value))\n } else {\n model[attribute] = null\n }\n }\n }\n\n #createModel(rec: LegacyStoreRecordType, type: string, options?: { models?: StoreModels }): StoreModelWithOptionalId {\n const models = options?.models\n\n const model: StoreModelWithOptionalId = { ...rec.data }\n if (rec.data.id != null) {\n model.id = rec.data.id\n }\n model[TYPE] = type\n if (rec.data.meta != null) {\n model[META] = rec.data.meta\n }\n if (rec.data.links != null) {\n model[LINKS] = rec.data.links\n }\n\n if (models && hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = safeObject<StoreModels[string]>()\n }\n models[type]![idStr] = model\n }\n\n const resolver = (relationType: string, id: string): StoreModel => {\n return (\n this.#findModel(relationType, id, models ?? safeObject<StoreModels>()) ?? this.#createStub(relationType, id)\n )\n }\n this.#resolveRelationships(model, type, resolver)\n\n return model\n }\n\n toModel(rec: LegacyStoreRecordType, type: string, modelsArg: StoreModels): StoreModel {\n const idStr = String(rec.data.id)\n const models = safeCache(modelsArg)\n\n if (!models[type]) {\n models[type] = safeObject<StoreModels[string]>()\n }\n\n if (models[type]![idStr]) {\n return models[type]![idStr]!\n }\n\n const result = this.#createModel(rec, type, { models })\n if (!hasId(result)) {\n throw new Error(`Expected model of type ${type} to have an id`)\n }\n const model = result\n\n if (this.schemas && this.schemas[type]) {\n const schema = this.schemas[type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type,\n id: idStr,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n models[type]![idStr] = validatedModel\n return validatedModel\n }\n\n return model\n }\n\n setupRelations(links: LegacyLinks): void {\n for (const key of Object.keys(links)) {\n const value = links[key]!\n const parts = key.split('.')\n const typeRaw = parts[0]!\n const attribute = parts[1]!\n if (isUnsafeKey(attribute)) {\n continue\n }\n const type = this.types[typeRaw] || typeRaw\n if (!this.relations[type]) {\n this.relations[type] = safeObject<Record<string, string>>()\n }\n this.relations[type]![attribute] = this.types[value.type] || value.type\n }\n }\n\n findRecord(type: string, id: string): LegacyStoreRecordType | undefined {\n return this.records.find((r) => r.type === type && String(r.data.id) === id)\n }\n\n findRecords(type: string): LegacyStoreRecordType[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string, models: StoreModels): StoreModel | null {\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return models[type]?.[id] ?? this.toModel(rec, type, models)\n }\n\n static build(data: LegacyData): StoreModelWithOptionalId {\n return new LegacyStore().build(data)\n }\n\n build(data: LegacyData): StoreModelWithOptionalId {\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n let name: string | undefined\n for (const key of Object.keys(data)) {\n if (key !== 'meta' && key !== 'links') {\n name = key\n break\n }\n }\n\n if (name == null) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const value = data[name]\n if (value == null || Array.isArray(value)) {\n throw new Error('build() expects a single resource, not an array')\n }\n\n const type = this.types[name] || name\n return this.#createModel({ type, data: value }, type)\n }\n\n /** @deprecated Use retrieve() instead. */\n retrive<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n return this.retrieve(type, data)\n }\n\n retrieve<T extends string>(type: T, data: LegacyData): InferModelType<S, T> | null {\n const synced = this.syncAll(data)\n const normalizedType = this.types[type] || type\n const model = synced.find((m) => m[TYPE] === normalizedType)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, String(id), safeCache(models ?? this.models))\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = safeCache(models ?? this.models)\n const recs = this.findRecords(type)\n if (recs.length === 0) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = safeObject<StoreModels[string]>()\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Type inference: maps string literal type parameter to schema type\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const normalizedType = this.types[type] || type\n\n const removeOne = (record: LegacyStoreRecordType): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const idStr = String(id)\n const record = this.findRecord(normalizedType, idStr)\n if (record) {\n removeOne(record)\n }\n } else {\n const records = this.findRecords(normalizedType)\n records.forEach(removeOne)\n }\n }\n\n syncAll(data: LegacyData): StoreResult {\n // Clear validation errors and models cache from previous sync\n this.validationErrors = []\n this.models = safeObject<StoreModels>()\n\n if (data.links) {\n this.setupRelations(data.links)\n }\n\n const syncedRecords: LegacyStoreRecordType[] = []\n\n for (const name of Object.keys(data)) {\n if (name === 'meta' || name === 'links') {\n continue\n }\n\n const value = data[name]!\n const type = this.types[name] || name\n\n const add = (d: Record<string, unknown>): void => {\n this.remove(type, String(d.id))\n const rec: LegacyStoreRecordType = { type, data: d }\n this.records.push(rec)\n syncedRecords.push(rec)\n }\n\n if (Array.isArray(value)) {\n value.forEach(add)\n } else if (typeof value === 'object' && value !== null) {\n add(value)\n }\n }\n\n for (const rec of syncedRecords) {\n this.toModel(rec, rec.type, this.models)\n }\n\n const result: StoreResult = syncedRecords.map((rec) => this.models[rec.type]![String(rec.data.id)]!)\n if (data.meta != null) {\n result[META] = data.meta\n }\n return result\n }\n\n sync(data: LegacyData): StoreModel | StoreResult {\n const result = this.syncAll(data)\n if (result.length === 1) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n retrieveAll<T extends string>(type: T, data: LegacyData): StoreResult<InferModelType<S, T>> {\n const normalizedType = this.types[type] || type\n const synced = this.syncAll(data)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter(\n (model) => model[TYPE] === normalizedType,\n ) as StoreResult<InferModelType<S, T>>\n result[META] = synced[META]\n return result\n }\n}\n","import yaysonFactory from './yayson.js'\nimport createLegacyPresenter from './yayson/legacy-presenter.js'\nimport LegacyStore from './yayson/legacy-store.js'\nimport type { LegacyData } from './yayson/legacy-store.js'\nimport Adapter from './yayson/adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n} from './yayson/types.js'\nimport type { YaysonOptions } from './yayson.js'\n\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyData,\n}\n\ninterface LegacyYaysonResult {\n Store: typeof LegacyStore\n Presenter: ReturnType<typeof createLegacyPresenter>\n Adapter: ReturnType<typeof yaysonFactory>['Adapter']\n}\n\nexport default function yayson(options?: YaysonOptions): LegacyYaysonResult {\n const { Presenter, Adapter } = yaysonFactory(options)\n return {\n Store: LegacyStore,\n Presenter: createLegacyPresenter(Presenter),\n Adapter,\n }\n}\n"],"mappings":"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"}
|
|
@@ -223,6 +223,42 @@ function validate(schema, data, strict) {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/yayson/safe.ts
|
|
228
|
+
/**
|
|
229
|
+
* Defenses against prototype pollution, since yayson keys lookup tables and
|
|
230
|
+
* model objects by strings from untrusted documents (`type`, `id`, member
|
|
231
|
+
* names). Per MDN's guidance
|
|
232
|
+
* (https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution):
|
|
233
|
+
* caches use null-prototype objects, and "__proto__"/"constructor"/"prototype"
|
|
234
|
+
* are rejected as member names.
|
|
235
|
+
*/
|
|
236
|
+
/** Null-prototype lookup table (MDN's `Object.create(null)`, never `obj.__proto__`). */
|
|
237
|
+
function safeObject() {
|
|
238
|
+
return Object.create(null);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Normalize a caller-supplied cache to a null-prototype object, so a public
|
|
242
|
+
* `models` argument that happens to be a plain `{}` can't let type="__proto__"
|
|
243
|
+
* resolve through Object.prototype. Already-null-prototype caches pass through
|
|
244
|
+
* unchanged (preserving identity/memoization).
|
|
245
|
+
*/
|
|
246
|
+
function safeCache(cache) {
|
|
247
|
+
if (cache === void 0) return safeObject();
|
|
248
|
+
if (Object.getPrototypeOf(cache) === null) return cache;
|
|
249
|
+
const safe = safeObject();
|
|
250
|
+
Object.assign(safe, cache);
|
|
251
|
+
return safe;
|
|
252
|
+
}
|
|
253
|
+
const UNSAFE_KEYS = new Set([
|
|
254
|
+
"__proto__",
|
|
255
|
+
"constructor",
|
|
256
|
+
"prototype"
|
|
257
|
+
]);
|
|
258
|
+
function isUnsafeKey(key) {
|
|
259
|
+
return UNSAFE_KEYS.has(key);
|
|
260
|
+
}
|
|
261
|
+
|
|
226
262
|
//#endregion
|
|
227
263
|
//#region src/yayson/store.ts
|
|
228
264
|
function hasId(model) {
|
|
@@ -264,7 +300,7 @@ var Store = class Store {
|
|
|
264
300
|
return stub;
|
|
265
301
|
}
|
|
266
302
|
#createModel(resource, options) {
|
|
267
|
-
const models = options?.models ??
|
|
303
|
+
const models = options?.models ?? safeObject();
|
|
268
304
|
const model = { ...resource.attributes || {} };
|
|
269
305
|
if (resource.id != null) model.id = resource.id;
|
|
270
306
|
const type = resource.type;
|
|
@@ -273,7 +309,7 @@ var Store = class Store {
|
|
|
273
309
|
if (resource.links != null) model[require_symbols.LINKS] = resource.links;
|
|
274
310
|
if (hasId(model)) {
|
|
275
311
|
const idStr = String(model.id);
|
|
276
|
-
if (!models[type]) models[type] =
|
|
312
|
+
if (!models[type]) models[type] = safeObject();
|
|
277
313
|
if (!models[type][idStr]) models[type][idStr] = model;
|
|
278
314
|
}
|
|
279
315
|
if (resource.relationships != null) {
|
|
@@ -286,7 +322,8 @@ var Store = class Store {
|
|
|
286
322
|
}
|
|
287
323
|
#resolveRelationships(model, relationships, resolver, options) {
|
|
288
324
|
const includeRelMeta = options?.includeRelMeta ?? true;
|
|
289
|
-
for (const key
|
|
325
|
+
for (const key of Object.keys(relationships)) {
|
|
326
|
+
if (isUnsafeKey(key)) continue;
|
|
290
327
|
const { data, links, meta } = relationships[key];
|
|
291
328
|
model[key] = null;
|
|
292
329
|
if (data == null && links == null) continue;
|
|
@@ -308,7 +345,7 @@ var Store = class Store {
|
|
|
308
345
|
}
|
|
309
346
|
}
|
|
310
347
|
toModel(rec, type, models) {
|
|
311
|
-
const model = this.#createModel(rec, { models });
|
|
348
|
+
const model = this.#createModel(rec, { models: safeCache(models) });
|
|
312
349
|
if (this.schemas && this.schemas[rec.type]) {
|
|
313
350
|
const schema = this.schemas[rec.type];
|
|
314
351
|
const result = validate(schema, model, this.strict);
|
|
@@ -341,14 +378,14 @@ var Store = class Store {
|
|
|
341
378
|
return this.toModel(rec, type, models);
|
|
342
379
|
}
|
|
343
380
|
find(type, id, models) {
|
|
344
|
-
return this.#findModel(type, id, models
|
|
381
|
+
return this.#findModel(type, id, safeCache(models));
|
|
345
382
|
}
|
|
346
383
|
findAll(type, models) {
|
|
347
|
-
const modelsObj = models
|
|
384
|
+
const modelsObj = safeCache(models);
|
|
348
385
|
const recs = this.findRecords(type);
|
|
349
386
|
if (recs == null) return [];
|
|
350
387
|
recs.forEach((rec) => {
|
|
351
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
388
|
+
if (!modelsObj[type]) modelsObj[type] = safeObject();
|
|
352
389
|
return this.toModel(rec, type, modelsObj);
|
|
353
390
|
});
|
|
354
391
|
return Object.values(modelsObj[type] || {});
|
|
@@ -397,7 +434,7 @@ var Store = class Store {
|
|
|
397
434
|
try {
|
|
398
435
|
syncData(body.included);
|
|
399
436
|
const recs = syncData(body.data);
|
|
400
|
-
const models =
|
|
437
|
+
const models = safeObject();
|
|
401
438
|
const result = recs.map((rec) => this.toModel(rec, rec.type, models));
|
|
402
439
|
if (body.meta != null) result[require_symbols.META] = body.meta;
|
|
403
440
|
return result;
|
|
@@ -469,6 +506,24 @@ Object.defineProperty(exports, 'filterByFields', {
|
|
|
469
506
|
return filterByFields;
|
|
470
507
|
}
|
|
471
508
|
});
|
|
509
|
+
Object.defineProperty(exports, 'isUnsafeKey', {
|
|
510
|
+
enumerable: true,
|
|
511
|
+
get: function () {
|
|
512
|
+
return isUnsafeKey;
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
Object.defineProperty(exports, 'safeCache', {
|
|
516
|
+
enumerable: true,
|
|
517
|
+
get: function () {
|
|
518
|
+
return safeCache;
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
Object.defineProperty(exports, 'safeObject', {
|
|
522
|
+
enumerable: true,
|
|
523
|
+
get: function () {
|
|
524
|
+
return safeObject;
|
|
525
|
+
}
|
|
526
|
+
});
|
|
472
527
|
Object.defineProperty(exports, 'validate', {
|
|
473
528
|
enumerable: true,
|
|
474
529
|
get: function () {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yayson-BvwMr4Ad.d.mts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBA0BwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ,gBAYsC,kBAAA,EAZtC;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAqB1B,SAAA,SAAgB,OAAA;MAAa,OAAA;IAAA,IAA2B,oBAAA;4BAuE7D,SAAA,GAAY,WAAA;iCAKZ,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,gBAAA,GACT,eAAA;sBA8Ee,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;iCA0B7B,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;EAAA;;;;+BAItD,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;+BAI7D,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;oBAIxE,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;AAAA;AAAA,KAQzD,SAAA,GAAY,UAAA,QAAkB,eAAA;;;
|
|
1
|
+
{"version":3,"file":"yayson-BvwMr4Ad.d.mts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBA0BwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ,gBAYsC,kBAAA,EAZtC;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAqB1B,SAAA,SAAgB,OAAA;MAAa,OAAA;IAAA,IAA2B,oBAAA;4BAuE7D,SAAA,GAAY,WAAA;iCAKZ,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,gBAAA,GACT,eAAA;sBA8Ee,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;iCA0B7B,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;EAAA;;;;+BAItD,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;+BAI7D,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;oBAIxE,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;AAAA;AAAA,KAQzD,SAAA,GAAY,UAAA,QAAkB,eAAA;;;cCjRpC,WAAA,YAAuB,aAAA;EAC3B,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;cAEK,OAAA,EAAS,aAAA;AAAA;AAAA,cAUF,KAAA,WAAgB,cAAA,GAAiB,cAAA;EAAA;EACpD,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,CAAA;EACV,MAAA;EACA,gBAAA,EAAkB,eAAA;cAEN,OAAA,GAAU,YAAA,CAAa,CAAA;EAMnC,KAAA,CAAA;EAuGA,OAAA,CAAQ,GAAA,EAAK,WAAA,EAAa,IAAA,UAAc,MAAA,EAAQ,WAAA,GAAc,UAAA;EA+B9D,UAAA,CAAW,IAAA,UAAc,EAAA,oBAAsB,WAAA;EAK/C,WAAA,CAAY,IAAA,WAAe,WAAA;EAiB3B,IAAA,kBAAA,CAAuB,IAAA,EAAM,CAAA,EAAG,EAAA,mBAAqB,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAM9F,OAAA,kBAAA,CAA0B,IAAA,EAAM,CAAA,EAAG,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAgB5E,MAAA,CAAO,IAAA,UAAc,EAAA;EAkBrB,OAAA,CAAQ,IAAA,EAAM,eAAA,GAAkB,WAAA;EA8DhC,IAAA,CAAK,IAAA,EAAM,eAAA,GAAkB,UAAA,GAAa,WAAA;ED5I5B;;;;;;;EAAA,OC+JP,KAAA,CAAM,IAAA,EAAM,eAAA,GAAkB,wBAAA;EAIrC,KAAA,CAAM,IAAA,EAAM,eAAA,GAAkB,wBAAA;EAQ9B,QAAA,kBAAA,CAA2B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,cAAA,CAAe,CAAA,EAAG,CAAA;EAW9E,WAAA,kBAAA,CAA8B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,WAAA,CAAY,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA;;;KC9U1F,aAAA,mBAAgC,OAAA;AAAA,UAE3B,aAAA;EACR,OAAA,GAAU,aAAA;AAAA;AAAA,UAGF,YAAA;EACR,KAAA,SAAc,KAAA;EACd,SAAA,EAAW,SAAA;EACX,OAAA,SAAgB,OAAA;AAAA;AAAA,iBAgBT,MAAA,CAAO,OAAA,GAAU,aAAA,GAAgB,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yayson-DTMLeA5k.d.cts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBA0BwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ,gBAYsC,kBAAA,EAZtC;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAqB1B,SAAA,SAAgB,OAAA;MAAa,OAAA;IAAA,IAA2B,oBAAA;4BAuE7D,SAAA,GAAY,WAAA;iCAKZ,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,gBAAA,GACT,eAAA;sBA8Ee,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;iCA0B7B,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;EAAA;;;;+BAItD,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;+BAI7D,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;oBAIxE,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;AAAA;AAAA,KAQzD,SAAA,GAAY,UAAA,QAAkB,eAAA;;;
|
|
1
|
+
{"version":3,"file":"yayson-DTMLeA5k.d.cts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBA0BwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ,gBAYsC,kBAAA,EAZtC;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAqB1B,SAAA,SAAgB,OAAA;MAAa,OAAA;IAAA,IAA2B,oBAAA;4BAuE7D,SAAA,GAAY,WAAA;iCAKZ,SAAA,GAAY,SAAA,uBAA8B,OAAA,GACtD,gBAAA,GACT,eAAA;sBA8Ee,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;iCA0B7B,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;EAAA;;;;+BAItD,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;+BAI7D,SAAA,GAAY,SAAA,WAAkB,OAAA,GAAY,gBAAA,GAAmB,eAAA;oBAIxE,SAAA,EAAS,OAAA,GAAY,gBAAA,GAAmB,eAAA;AAAA;AAAA,KAQzD,SAAA,GAAY,UAAA,QAAkB,eAAA;;;cCjRpC,WAAA,YAAuB,aAAA;EAC3B,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;cAEK,OAAA,EAAS,aAAA;AAAA;AAAA,cAUF,KAAA,WAAgB,cAAA,GAAiB,cAAA;EAAA;EACpD,OAAA,EAAS,WAAA;EACT,OAAA,GAAU,CAAA;EACV,MAAA;EACA,gBAAA,EAAkB,eAAA;cAEN,OAAA,GAAU,YAAA,CAAa,CAAA;EAMnC,KAAA,CAAA;EAuGA,OAAA,CAAQ,GAAA,EAAK,WAAA,EAAa,IAAA,UAAc,MAAA,EAAQ,WAAA,GAAc,UAAA;EA+B9D,UAAA,CAAW,IAAA,UAAc,EAAA,oBAAsB,WAAA;EAK/C,WAAA,CAAY,IAAA,WAAe,WAAA;EAiB3B,IAAA,kBAAA,CAAuB,IAAA,EAAM,CAAA,EAAG,EAAA,mBAAqB,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAM9F,OAAA,kBAAA,CAA0B,IAAA,EAAM,CAAA,EAAG,MAAA,GAAS,WAAA,GAAc,cAAA,CAAe,CAAA,EAAG,CAAA;EAgB5E,MAAA,CAAO,IAAA,UAAc,EAAA;EAkBrB,OAAA,CAAQ,IAAA,EAAM,eAAA,GAAkB,WAAA;EA8DhC,IAAA,CAAK,IAAA,EAAM,eAAA,GAAkB,UAAA,GAAa,WAAA;ED5I5B;;;;;;;EAAA,OC+JP,KAAA,CAAM,IAAA,EAAM,eAAA,GAAkB,wBAAA;EAIrC,KAAA,CAAM,IAAA,EAAM,eAAA,GAAkB,wBAAA;EAQ9B,QAAA,kBAAA,CAA2B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,cAAA,CAAe,CAAA,EAAG,CAAA;EAW9E,WAAA,kBAAA,CAA8B,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,eAAA,GAAkB,WAAA,CAAY,cAAA,CAAe,CAAA,EAAG,CAAA;AAAA;;;KC9U1F,aAAA,mBAAgC,OAAA;AAAA,UAE3B,aAAA;EACR,OAAA,GAAU,aAAA;AAAA;AAAA,UAGF,YAAA;EACR,KAAA,SAAc,KAAA;EACd,SAAA,EAAW,SAAA;EACX,OAAA,SAAgB,OAAA;AAAA;AAAA,iBAgBT,MAAA,CAAO,OAAA,GAAU,aAAA,GAAgB,YAAA"}
|
|
@@ -223,6 +223,42 @@ function validate(schema, data, strict) {
|
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/yayson/safe.ts
|
|
228
|
+
/**
|
|
229
|
+
* Defenses against prototype pollution, since yayson keys lookup tables and
|
|
230
|
+
* model objects by strings from untrusted documents (`type`, `id`, member
|
|
231
|
+
* names). Per MDN's guidance
|
|
232
|
+
* (https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution):
|
|
233
|
+
* caches use null-prototype objects, and "__proto__"/"constructor"/"prototype"
|
|
234
|
+
* are rejected as member names.
|
|
235
|
+
*/
|
|
236
|
+
/** Null-prototype lookup table (MDN's `Object.create(null)`, never `obj.__proto__`). */
|
|
237
|
+
function safeObject() {
|
|
238
|
+
return Object.create(null);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Normalize a caller-supplied cache to a null-prototype object, so a public
|
|
242
|
+
* `models` argument that happens to be a plain `{}` can't let type="__proto__"
|
|
243
|
+
* resolve through Object.prototype. Already-null-prototype caches pass through
|
|
244
|
+
* unchanged (preserving identity/memoization).
|
|
245
|
+
*/
|
|
246
|
+
function safeCache(cache) {
|
|
247
|
+
if (cache === void 0) return safeObject();
|
|
248
|
+
if (Object.getPrototypeOf(cache) === null) return cache;
|
|
249
|
+
const safe = safeObject();
|
|
250
|
+
Object.assign(safe, cache);
|
|
251
|
+
return safe;
|
|
252
|
+
}
|
|
253
|
+
const UNSAFE_KEYS = new Set([
|
|
254
|
+
"__proto__",
|
|
255
|
+
"constructor",
|
|
256
|
+
"prototype"
|
|
257
|
+
]);
|
|
258
|
+
function isUnsafeKey(key) {
|
|
259
|
+
return UNSAFE_KEYS.has(key);
|
|
260
|
+
}
|
|
261
|
+
|
|
226
262
|
//#endregion
|
|
227
263
|
//#region src/yayson/store.ts
|
|
228
264
|
function hasId(model) {
|
|
@@ -264,7 +300,7 @@ var Store = class Store {
|
|
|
264
300
|
return stub;
|
|
265
301
|
}
|
|
266
302
|
#createModel(resource, options) {
|
|
267
|
-
const models = options?.models ??
|
|
303
|
+
const models = options?.models ?? safeObject();
|
|
268
304
|
const model = { ...resource.attributes || {} };
|
|
269
305
|
if (resource.id != null) model.id = resource.id;
|
|
270
306
|
const type = resource.type;
|
|
@@ -273,7 +309,7 @@ var Store = class Store {
|
|
|
273
309
|
if (resource.links != null) model[LINKS] = resource.links;
|
|
274
310
|
if (hasId(model)) {
|
|
275
311
|
const idStr = String(model.id);
|
|
276
|
-
if (!models[type]) models[type] =
|
|
312
|
+
if (!models[type]) models[type] = safeObject();
|
|
277
313
|
if (!models[type][idStr]) models[type][idStr] = model;
|
|
278
314
|
}
|
|
279
315
|
if (resource.relationships != null) {
|
|
@@ -286,7 +322,8 @@ var Store = class Store {
|
|
|
286
322
|
}
|
|
287
323
|
#resolveRelationships(model, relationships, resolver, options) {
|
|
288
324
|
const includeRelMeta = options?.includeRelMeta ?? true;
|
|
289
|
-
for (const key
|
|
325
|
+
for (const key of Object.keys(relationships)) {
|
|
326
|
+
if (isUnsafeKey(key)) continue;
|
|
290
327
|
const { data, links, meta } = relationships[key];
|
|
291
328
|
model[key] = null;
|
|
292
329
|
if (data == null && links == null) continue;
|
|
@@ -308,7 +345,7 @@ var Store = class Store {
|
|
|
308
345
|
}
|
|
309
346
|
}
|
|
310
347
|
toModel(rec, type, models) {
|
|
311
|
-
const model = this.#createModel(rec, { models });
|
|
348
|
+
const model = this.#createModel(rec, { models: safeCache(models) });
|
|
312
349
|
if (this.schemas && this.schemas[rec.type]) {
|
|
313
350
|
const schema = this.schemas[rec.type];
|
|
314
351
|
const result = validate(schema, model, this.strict);
|
|
@@ -341,14 +378,14 @@ var Store = class Store {
|
|
|
341
378
|
return this.toModel(rec, type, models);
|
|
342
379
|
}
|
|
343
380
|
find(type, id, models) {
|
|
344
|
-
return this.#findModel(type, id, models
|
|
381
|
+
return this.#findModel(type, id, safeCache(models));
|
|
345
382
|
}
|
|
346
383
|
findAll(type, models) {
|
|
347
|
-
const modelsObj = models
|
|
384
|
+
const modelsObj = safeCache(models);
|
|
348
385
|
const recs = this.findRecords(type);
|
|
349
386
|
if (recs == null) return [];
|
|
350
387
|
recs.forEach((rec) => {
|
|
351
|
-
if (!modelsObj[type]) modelsObj[type] =
|
|
388
|
+
if (!modelsObj[type]) modelsObj[type] = safeObject();
|
|
352
389
|
return this.toModel(rec, type, modelsObj);
|
|
353
390
|
});
|
|
354
391
|
return Object.values(modelsObj[type] || {});
|
|
@@ -397,7 +434,7 @@ var Store = class Store {
|
|
|
397
434
|
try {
|
|
398
435
|
syncData(body.included);
|
|
399
436
|
const recs = syncData(body.data);
|
|
400
|
-
const models =
|
|
437
|
+
const models = safeObject();
|
|
401
438
|
const result = recs.map((rec) => this.toModel(rec, rec.type, models));
|
|
402
439
|
if (body.meta != null) result[META] = body.meta;
|
|
403
440
|
return result;
|
|
@@ -463,5 +500,5 @@ function yayson(options) {
|
|
|
463
500
|
var yayson_default = yayson;
|
|
464
501
|
|
|
465
502
|
//#endregion
|
|
466
|
-
export { validate as n, filterByFields as r, yayson_default as t };
|
|
467
|
-
//# sourceMappingURL=yayson-
|
|
503
|
+
export { validate as a, safeObject as i, isUnsafeKey as n, filterByFields as o, safeCache as r, yayson_default as t };
|
|
504
|
+
//# sourceMappingURL=yayson-RzT9zsdx.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yayson-RzT9zsdx.mjs","names":["Adapter","#findModel","#createStub","#resolveRelationships","#createModel","Adapter","adapters.sequelize"],"sources":["../src/yayson/adapters/sequelize.ts","../src/yayson/utils.ts","../src/yayson/presenter.ts","../src/yayson/schema.ts","../src/yayson/safe.ts","../src/yayson/store.ts","../src/yayson.ts"],"sourcesContent":["import Adapter, { type ModelLike } from '../adapter.js'\n\ninterface SequelizeModel {\n get(key?: string): unknown\n constructor?: {\n primaryKeys?: Record<string, unknown>\n }\n}\nfunction isSequelizeModel(model: unknown): model is SequelizeModel {\n return model != null && typeof model === 'object' && 'get' in model && typeof model.get === 'function'\n}\n\nclass SequelizeAdapter extends Adapter {\n static override get(model: ModelLike): Record<string, unknown>\n static override get(model: ModelLike, key: string): unknown\n static override get(model: ModelLike, key?: string): unknown {\n if (isSequelizeModel(model)) {\n return model.get(key)\n }\n return undefined\n }\n\n static override has(model: ModelLike, key: string): boolean {\n if (isSequelizeModel(model)) {\n // `key in model` doesn't work across Sequelize versions; .get() returning\n // undefined is the proxy for \"unloaded association or undeclared key\".\n return model.get(key) !== undefined\n }\n return false\n }\n\n static override id(model: ModelLike): string | undefined {\n // Retain backwards compatibility with older sequelize versions\n const hasPrimaryKeys = model.constructor && 'primaryKeys' in model.constructor\n const pkFields = hasPrimaryKeys\n ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Access primaryKeys for Sequelize v3/v4 compatibility\n Object.keys((model.constructor as unknown as { primaryKeys: Record<string, unknown> }).primaryKeys)\n : ['id']\n\n if (pkFields.length > 1) {\n throw new Error(\n 'YAYSON does not support Sequelize models with composite primary keys. You can only use one column for your primary key. Currently using: ' +\n pkFields.join(','),\n )\n } else if (pkFields.length < 1) {\n throw new Error(\n 'YAYSON can only serialize Sequelize models which have a primary key. This is used for the JSON:API model id.',\n )\n }\n\n const id = this.get(model, pkFields[0])\n if (id == null) {\n return undefined\n }\n return `${id}`\n }\n}\n\nexport default SequelizeAdapter\n","/**\n * Filters an attributes object to only include keys in the fields array.\n * Returns the original attributes if fields is undefined.\n */\nexport function filterByFields(\n attributes: Record<string, unknown>,\n fields: string[] | undefined,\n): Record<string, unknown> {\n if (!fields) {\n return attributes\n }\n const filtered: Record<string, unknown> = {}\n for (const key of fields) {\n if (key in attributes) {\n filtered[key] = attributes[key]\n }\n }\n return filtered\n}\n","import Adapter, { ModelLike } from './adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n JsonApiResourceIdentifier,\n PresenterOptions,\n RelationshipConfig,\n} from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction buildLinks(link: JsonApiLink | string | null | undefined): JsonApiLink | undefined {\n if (link == null) {\n return\n }\n if (typeof link === 'object' && (link.self != null || link.related != null)) {\n return link\n } else {\n return { self: String(link) }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createPresenter(adapter: typeof Adapter) {\n class Presenter {\n declare ['constructor']: typeof Presenter\n\n static adapter = adapter\n static type = 'objects'\n static fields?: string[]\n\n scope: JsonApiDocument\n\n constructor(scope?: JsonApiDocument) {\n this.scope = scope ?? { data: null }\n }\n\n id(instance: ModelLike): string | undefined {\n return this.constructor.adapter.id(instance)\n }\n\n selfLinks(_instance: ModelLike): JsonApiLink | string | undefined {\n return undefined\n }\n\n links(_instance?: ModelLike): JsonApiLinks | undefined {\n return undefined\n }\n\n relationships(): Record<string, typeof Presenter | RelationshipConfig<typeof Presenter>> {\n return {}\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (instance == null) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n delete attributes['id']\n\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n delete attributes[key]\n }\n }\n\n return filterByFields(attributes, this.constructor.fields)\n }\n\n includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[] {\n const relationships = this.relationships()\n const result: unknown[] = []\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const entry = relationships[key]\n if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n const factory = typeof entry === 'function' ? entry : entry.presenter\n\n const presenter = new factory(scope)\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n result.push(presenter.toJSON(data, { include: true }))\n }\n return result\n }\n\n buildRelationships(instance: ModelLike | null, options: { payload?: boolean } = {}): JsonApiRelationships | null {\n if (instance == null) {\n return null\n }\n const rels = this.relationships()\n const links = this.links(instance) || {}\n const isPayload = options.payload === true\n let relationships: JsonApiRelationships | null = null\n\n if (!rels) {\n return null\n }\n\n for (const key in rels) {\n const entry = rels[key]\n if (!entry) continue\n\n const isConfig = typeof entry !== 'function'\n const presenter = isConfig ? entry.presenter : entry\n const hasMany = isConfig ? entry.hasMany : undefined\n const optional = isConfig ? (entry.optional ?? false) : false\n\n const linkValue = links[key]\n const hasLinks = linkValue != null\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null | undefined\n const keyPresent = this.constructor.adapter.has(instance, key)\n\n const buildData = (d: ModelLike): JsonApiResourceIdentifier => {\n const id = this.constructor.adapter.id(d)\n if (!id) {\n throw new Error(\n `Model of type ${presenter.type} is missing an id (relationship '${key}' of ${this.constructor.type})`,\n )\n }\n return { id, type: presenter.type }\n }\n\n // Skip in payload mode: an omitted relationship in a write must not be\n // confused with the model simply not having loaded it.\n if (optional && !keyPresent && !isPayload) {\n if (hasLinks) {\n if (!relationships) relationships = {}\n relationships[key] = { links: buildLinks(linkValue) }\n }\n continue\n }\n\n if (!relationships) relationships = {}\n const rel: JsonApiRelationship = {}\n\n if (Array.isArray(data)) {\n rel.data = data.map(buildData)\n } else if (data != null) {\n rel.data = buildData(data)\n } else if (hasMany === true) {\n rel.data = []\n } else if (!hasLinks) {\n rel.data = null\n }\n\n if (hasLinks) {\n rel.links = buildLinks(linkValue)\n }\n\n relationships[key] = rel\n }\n return relationships\n }\n\n buildSelfLink(instance: ModelLike): JsonApiLink | undefined {\n return buildLinks(this.selfLinks(instance))\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: PresenterOptions,\n ): JsonApiDocument {\n const opts = options ?? {}\n if (opts.meta != null) {\n this.scope.meta = opts.meta\n }\n if (opts.links != null) {\n this.scope.links = opts.links\n }\n if (!this.scope.data) {\n this.scope.data = null\n }\n\n if (instanceOrCollection == null) {\n return this.scope\n }\n\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n if (!this.scope.data) {\n this.scope.data = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance, options)\n })\n } else {\n const instance = instanceOrCollection\n let added = true\n const model: JsonApiResource = {\n id: this.id(instance),\n type: this.constructor.type,\n attributes: this.attributes(instance),\n }\n if (model.id === undefined) {\n delete model.id\n }\n const relationships = this.buildRelationships(instance)\n if (relationships != null) {\n model.relationships = relationships\n }\n const links = this.buildSelfLink(instance)\n if (links != null) {\n model.links = links\n }\n\n if (opts.include) {\n if (!this.scope.included) {\n this.scope.included = []\n }\n const allResources = (this.scope.included || []).concat(\n Array.isArray(this.scope.data) ? this.scope.data : this.scope.data ? [this.scope.data] : [],\n )\n if (!allResources.some((i) => i.id === model.id && i.type === model.type)) {\n this.scope.included.push(model)\n } else {\n added = false\n }\n } else if (this.scope.data != null) {\n if (Array.isArray(this.scope.data)) {\n if (!this.scope.data.some((i) => i.id === model.id && i.type === model.type)) {\n this.scope.data.push(model)\n } else {\n added = false\n }\n } else {\n // data is a single object, convert to array if needed\n this.scope.data = model\n }\n } else {\n this.scope.data = model\n }\n\n if (added) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n const model: JsonApiResource = {\n type: this.constructor.type,\n attributes: this.attributes(instance),\n }\n const id = this.id(instance)\n if (id != null) {\n model.id = id\n }\n const relationships = this.buildRelationships(instance, { payload: true })\n if (relationships != null) {\n model.relationships = relationships\n }\n const result: JsonApiDocument = { data: model }\n const opts = options ?? {}\n if (opts.meta != null) result.meta = opts.meta\n if (opts.links != null) result.links = opts.links\n return result\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return this.toJSON(instanceOrCollection, options)\n }\n\n static toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return new this().render(instanceOrCollection, options)\n }\n\n static payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument {\n return new this().payload(instance, options)\n }\n }\n\n return Presenter\n}\n\nexport type Presenter = ReturnType<typeof createPresenter>\n","/**\n * Interface for Zod-like schema objects.\n * Any schema library that implements `parse` and `safeParse` methods will work.\n */\nexport interface ZodLikeSchema {\n parse: (data: unknown) => unknown\n safeParse: (data: unknown) => { success: true; data: unknown } | { success: false; error: unknown }\n}\n\nexport function isZodLikeSchema(schema: unknown): schema is ZodLikeSchema {\n return (\n schema != null &&\n typeof schema === 'object' &&\n 'parse' in schema &&\n typeof schema.parse === 'function' &&\n 'safeParse' in schema &&\n typeof schema.safeParse === 'function'\n )\n}\n\nexport interface ValidationResult {\n valid: boolean\n data: unknown\n error?: unknown\n}\n\nexport function validate(schema: unknown, data: unknown, strict: boolean): ValidationResult {\n if (!isZodLikeSchema(schema)) {\n throw new Error('Invalid schema: must have parse and safeParse methods')\n }\n\n if (strict) {\n const validData = schema.parse(data)\n return { valid: true, data: validData }\n } else {\n const result = schema.safeParse(data)\n if (result.success) {\n return { valid: true, data: result.data }\n } else {\n return { valid: false, data, error: result.error }\n }\n }\n}\n","/**\n * Defenses against prototype pollution, since yayson keys lookup tables and\n * model objects by strings from untrusted documents (`type`, `id`, member\n * names). Per MDN's guidance\n * (https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/Prototype_pollution):\n * caches use null-prototype objects, and \"__proto__\"/\"constructor\"/\"prototype\"\n * are rejected as member names.\n */\n\n/** Null-prototype lookup table (MDN's `Object.create(null)`, never `obj.__proto__`). */\nexport function safeObject<T extends object>(): T {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Object.create(null) is intentionally untyped\n return Object.create(null) as T\n}\n\n/**\n * Normalize a caller-supplied cache to a null-prototype object, so a public\n * `models` argument that happens to be a plain `{}` can't let type=\"__proto__\"\n * resolve through Object.prototype. Already-null-prototype caches pass through\n * unchanged (preserving identity/memoization).\n */\nexport function safeCache<T extends object>(cache: T | undefined): T {\n if (cache === undefined) {\n return safeObject<T>()\n }\n if (Object.getPrototypeOf(cache) === null) {\n return cache\n }\n const safe = safeObject<T>()\n Object.assign(safe, cache)\n return safe\n}\n\nconst UNSAFE_KEYS = new Set<string>(['__proto__', 'constructor', 'prototype'])\n\nexport function isUnsafeKey(key: string): boolean {\n return UNSAFE_KEYS.has(key)\n}\n","import type {\n InferModelType,\n JsonApiDocument,\n JsonApiLink,\n JsonApiRelationships,\n JsonApiResourceIdentifier,\n SchemaRegistry,\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreOptions,\n StoreRecord as StoreRecordType,\n StoreResult,\n ValidationError,\n} from './types.js'\nimport { TYPE, LINKS, META, REL_LINKS, REL_META } from './symbols.js'\nimport { validate } from './schema.js'\nimport { safeObject, safeCache, isUnsafeKey } from './safe.js'\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nclass StoreRecord implements StoreRecordType {\n id: string | number\n type: string\n attributes?: Record<string, unknown>\n relationships?: JsonApiRelationships\n links?: JsonApiLink\n meta?: Record<string, unknown>\n\n constructor(options: StoreRecordType) {\n this.id = options.id\n this.type = options.type\n this.attributes = options.attributes\n this.relationships = options.relationships\n this.links = options.links\n this.meta = options.meta\n }\n}\n\nexport default class Store<S extends SchemaRegistry = SchemaRegistry> {\n records: StoreRecord[] = []\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[] = []\n\n constructor(options?: StoreOptions<S>) {\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.reset()\n }\n\n reset(): void {\n this.records = []\n this.validationErrors = []\n }\n\n #createStub(type: string, id: string | number): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #createModel(\n resource: {\n type: string\n id?: string | number | null\n attributes?: Record<string, unknown> | null\n relationships?: JsonApiRelationships | null\n meta?: Record<string, unknown> | null\n links?: JsonApiLink | null\n },\n options?: {\n models?: StoreModels\n includeRelMeta?: boolean\n },\n ): StoreModelWithOptionalId {\n const models = options?.models ?? safeObject<StoreModels>()\n\n const model: StoreModelWithOptionalId = { ...(resource.attributes || {}) }\n if (resource.id != null) {\n model.id = resource.id\n }\n const type = resource.type\n model[TYPE] = type\n if (resource.meta != null) {\n model[META] = resource.meta\n }\n if (resource.links != null) {\n model[LINKS] = resource.links\n }\n\n // Cache before resolving relationships (for circular refs)\n if (hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = safeObject<StoreModels[string]>()\n }\n if (!models[type][idStr]) {\n models[type][idStr] = model\n }\n }\n\n if (resource.relationships != null) {\n const resolver = (ref: JsonApiResourceIdentifier): StoreModel => {\n return this.#findModel(ref.type, ref.id, models) ?? this.#createStub(ref.type, ref.id)\n }\n this.#resolveRelationships(model, resource.relationships, resolver, {\n includeRelMeta: options?.includeRelMeta,\n })\n }\n return model\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n relationships: JsonApiRelationships,\n resolver: (ref: JsonApiResourceIdentifier) => StoreModel | StoreModelWithOptionalId,\n options?: { includeRelMeta?: boolean },\n ): void {\n const includeRelMeta = options?.includeRelMeta ?? true\n\n // Object.keys (not for...in) so a polluted Object.prototype can't inject members.\n for (const key of Object.keys(relationships)) {\n if (isUnsafeKey(key)) {\n continue\n }\n const rel = relationships[key]\n const { data, links, meta } = rel\n\n model[key] = null\n if (data == null && links == null) {\n continue\n }\n\n if (Array.isArray(data)) {\n model[key] = data.filter((item) => item.id != null).map(resolver)\n } else if (data != null && data.id != null) {\n const relModel = resolver(data)\n if (includeRelMeta) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- REL_LINKS/REL_META only used when resolver returns StoreModel\n const modelWithMeta = relModel as StoreModel\n modelWithMeta[REL_LINKS] = links || {}\n modelWithMeta[REL_META] = meta || {}\n }\n model[key] = relModel\n } else if (data == null && (links != null || meta != null) && includeRelMeta) {\n const relModel: StoreModel = { id: '' }\n relModel[REL_LINKS] = links || {}\n relModel[REL_META] = meta || {}\n model[key] = relModel\n }\n }\n }\n\n toModel(rec: StoreRecord, type: string, models: StoreModels): StoreModel {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- StoreRecord always has id\n const model = this.#createModel(rec, { models: safeCache(models) }) as StoreModel\n\n // Validate with schema if provided\n if (this.schemas && this.schemas[rec.type]) {\n const schema = this.schemas[rec.type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type: rec.type,\n id: rec.id,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n return validatedModel\n }\n\n return model\n }\n\n findRecord(type: string, id: string | number): StoreRecord | undefined {\n const idStr = String(id)\n return this.records.find((r) => r.type === type && String(r.id) === idStr)\n }\n\n findRecords(type: string): StoreRecord[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string | number, models: StoreModels): StoreModel | null {\n const idStr = String(id)\n const cached = models[type]?.[idStr]\n if (cached) {\n return cached\n }\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return this.toModel(rec, type, models)\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, id, safeCache(models))\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from schema registry\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = safeCache(models)\n const recs = this.findRecords(type)\n if (recs == null) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = safeObject<StoreModels[string]>()\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from schema registry\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const removeOne = (record: StoreRecord): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const record = this.findRecord(type, String(id))\n if (record) {\n removeOne(record)\n }\n } else {\n this.findRecords(type).forEach(removeOne)\n }\n }\n\n syncAll(body: JsonApiDocument): StoreResult {\n // Clear previous validation errors\n this.validationErrors = []\n\n // Snapshot for rollback if strict validation throws\n const previousRecords = [...this.records]\n\n const syncData = (data: JsonApiDocument['data'] | JsonApiDocument['included']): StoreRecord[] => {\n if (data == null) {\n return []\n }\n const add = (obj: StoreRecordType): StoreRecord => {\n const { type, id } = obj\n this.remove(type, id)\n const rec = new StoreRecord(obj)\n this.records.push(rec)\n return rec\n }\n\n if (Array.isArray(data)) {\n return data.map((item) => {\n if (!item.id) {\n throw new Error(`Resource of type ${item.type} is missing an id`)\n }\n return add({\n ...item,\n attributes: item.attributes ?? undefined,\n relationships: item.relationships ?? undefined,\n id: item.id,\n })\n })\n } else {\n if (!data.id) {\n throw new Error(`Resource of type ${data.type} is missing an id`)\n }\n return [\n add({\n ...data,\n attributes: data.attributes ?? undefined,\n relationships: data.relationships ?? undefined,\n id: data.id,\n }),\n ]\n }\n }\n\n try {\n syncData(body.included)\n const recs = syncData(body.data)\n\n const models: StoreModels = safeObject<StoreModels>()\n const result: StoreResult = recs.map((rec) => this.toModel(rec, rec.type, models))\n if (body.meta != null) {\n result[META] = body.meta\n }\n return result\n } catch (e) {\n this.records = previousRecords\n throw e\n }\n }\n\n sync(body: JsonApiDocument): StoreModel | StoreResult {\n const result = this.syncAll(body)\n if (!Array.isArray(body.data) && body.data != null) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n /**\n * Build a model from a JSON:API document without storing it.\n * Useful for create payloads where id may be absent.\n *\n * Per JSON:API spec: \"The id member is not required when the resource object\n * originates at the client and represents a new resource to be created on the server.\"\n */\n static build(body: JsonApiDocument): StoreModelWithOptionalId {\n return new Store().build(body)\n }\n\n build(body: JsonApiDocument): StoreModelWithOptionalId {\n const { data } = body\n if (data == null || Array.isArray(data)) {\n throw new Error('build() expects a single resource in data, not null or an array')\n }\n return this.#createModel(data)\n }\n\n retrieve<T extends string>(type: T, body: JsonApiDocument): InferModelType<S, T> | null {\n const synced = this.syncAll(body)\n const model = synced.find((m) => m[TYPE] === type)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n retrieveAll<T extends string>(type: T, body: JsonApiDocument): StoreResult<InferModelType<S, T>> {\n const synced = this.syncAll(body)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter((model) => model[TYPE] === type) as StoreResult<\n InferModelType<S, T>\n >\n result[META] = synced[META]\n return result\n }\n}\n","import Adapter from './yayson/adapter.js'\nimport * as adapters from './yayson/adapters/index.js'\nimport createPresenter, { Presenter } from './yayson/presenter.js'\nimport Store from './yayson/store.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyStoreOptions,\n PresenterOptions,\n SchemaRegistry,\n StoreOptions,\n ValidationError,\n} from './yayson/types.js'\nimport type { ZodLikeSchema } from './yayson/schema.js'\n\ntype AdapterOption = string | typeof Adapter\n\ninterface YaysonOptions {\n adapter?: AdapterOption\n}\n\ninterface YaysonResult {\n Store: typeof Store\n Presenter: Presenter\n Adapter: typeof Adapter\n}\n\nfunction lookupAdapter(nameOrAdapter?: AdapterOption): typeof Adapter {\n if (nameOrAdapter === 'default' || !nameOrAdapter) {\n return Adapter\n } else if (typeof nameOrAdapter === 'string') {\n if (nameOrAdapter === 'sequelize') {\n return adapters.sequelize\n } else {\n throw new Error('Adapter not found: ' + nameOrAdapter)\n }\n }\n return nameOrAdapter\n}\n\nfunction yayson(options?: YaysonOptions): YaysonResult {\n const adapter = lookupAdapter(options?.adapter)\n const Presenter = createPresenter(adapter)\n\n return {\n Store,\n Presenter,\n Adapter,\n }\n}\n\nexport default yayson\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyStoreOptions,\n PresenterOptions,\n SchemaRegistry,\n StoreOptions,\n ValidationError,\n YaysonOptions,\n YaysonResult,\n ZodLikeSchema,\n}\n"],"mappings":"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"}
|
package/build/yayson.cjs
CHANGED
package/build/yayson.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"yayson-DIQ_olLX.mjs","names":["Adapter","#findModel","#createStub","#resolveRelationships","#createModel","Adapter","adapters.sequelize"],"sources":["../src/yayson/adapters/sequelize.ts","../src/yayson/utils.ts","../src/yayson/presenter.ts","../src/yayson/schema.ts","../src/yayson/store.ts","../src/yayson.ts"],"sourcesContent":["import Adapter, { type ModelLike } from '../adapter.js'\n\ninterface SequelizeModel {\n get(key?: string): unknown\n constructor?: {\n primaryKeys?: Record<string, unknown>\n }\n}\nfunction isSequelizeModel(model: unknown): model is SequelizeModel {\n return model != null && typeof model === 'object' && 'get' in model && typeof model.get === 'function'\n}\n\nclass SequelizeAdapter extends Adapter {\n static override get(model: ModelLike): Record<string, unknown>\n static override get(model: ModelLike, key: string): unknown\n static override get(model: ModelLike, key?: string): unknown {\n if (isSequelizeModel(model)) {\n return model.get(key)\n }\n return undefined\n }\n\n static override has(model: ModelLike, key: string): boolean {\n if (isSequelizeModel(model)) {\n // `key in model` doesn't work across Sequelize versions; .get() returning\n // undefined is the proxy for \"unloaded association or undeclared key\".\n return model.get(key) !== undefined\n }\n return false\n }\n\n static override id(model: ModelLike): string | undefined {\n // Retain backwards compatibility with older sequelize versions\n const hasPrimaryKeys = model.constructor && 'primaryKeys' in model.constructor\n const pkFields = hasPrimaryKeys\n ? // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Access primaryKeys for Sequelize v3/v4 compatibility\n Object.keys((model.constructor as unknown as { primaryKeys: Record<string, unknown> }).primaryKeys)\n : ['id']\n\n if (pkFields.length > 1) {\n throw new Error(\n 'YAYSON does not support Sequelize models with composite primary keys. You can only use one column for your primary key. Currently using: ' +\n pkFields.join(','),\n )\n } else if (pkFields.length < 1) {\n throw new Error(\n 'YAYSON can only serialize Sequelize models which have a primary key. This is used for the JSON:API model id.',\n )\n }\n\n const id = this.get(model, pkFields[0])\n if (id == null) {\n return undefined\n }\n return `${id}`\n }\n}\n\nexport default SequelizeAdapter\n","/**\n * Filters an attributes object to only include keys in the fields array.\n * Returns the original attributes if fields is undefined.\n */\nexport function filterByFields(\n attributes: Record<string, unknown>,\n fields: string[] | undefined,\n): Record<string, unknown> {\n if (!fields) {\n return attributes\n }\n const filtered: Record<string, unknown> = {}\n for (const key of fields) {\n if (key in attributes) {\n filtered[key] = attributes[key]\n }\n }\n return filtered\n}\n","import Adapter, { ModelLike } from './adapter.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n JsonApiResourceIdentifier,\n PresenterOptions,\n RelationshipConfig,\n} from './types.js'\nimport { filterByFields } from './utils.js'\n\nfunction buildLinks(link: JsonApiLink | string | null | undefined): JsonApiLink | undefined {\n if (link == null) {\n return\n }\n if (typeof link === 'object' && (link.self != null || link.related != null)) {\n return link\n } else {\n return { self: String(link) }\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -- Return type is inferred from class\nexport default function createPresenter(adapter: typeof Adapter) {\n class Presenter {\n declare ['constructor']: typeof Presenter\n\n static adapter = adapter\n static type = 'objects'\n static fields?: string[]\n\n scope: JsonApiDocument\n\n constructor(scope?: JsonApiDocument) {\n this.scope = scope ?? { data: null }\n }\n\n id(instance: ModelLike): string | undefined {\n return this.constructor.adapter.id(instance)\n }\n\n selfLinks(_instance: ModelLike): JsonApiLink | string | undefined {\n return undefined\n }\n\n links(_instance?: ModelLike): JsonApiLinks | undefined {\n return undefined\n }\n\n relationships(): Record<string, typeof Presenter | RelationshipConfig<typeof Presenter>> {\n return {}\n }\n\n attributes(instance: ModelLike | null): Record<string, unknown> {\n if (instance == null) {\n return {}\n }\n const attributes = { ...this.constructor.adapter.get(instance) }\n delete attributes['id']\n\n const relationships = this.relationships()\n if (relationships) {\n for (const key in relationships) {\n delete attributes[key]\n }\n }\n\n return filterByFields(attributes, this.constructor.fields)\n }\n\n includeRelationships(scope: JsonApiDocument, instance: ModelLike): unknown[] {\n const relationships = this.relationships()\n const result: unknown[] = []\n if (!relationships) {\n return result\n }\n\n for (const key in relationships) {\n const entry = relationships[key]\n if (!entry) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\n const factory = typeof entry === 'function' ? entry : entry.presenter\n\n const presenter = new factory(scope)\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null\n result.push(presenter.toJSON(data, { include: true }))\n }\n return result\n }\n\n buildRelationships(instance: ModelLike | null, options: { payload?: boolean } = {}): JsonApiRelationships | null {\n if (instance == null) {\n return null\n }\n const rels = this.relationships()\n const links = this.links(instance) || {}\n const isPayload = options.payload === true\n let relationships: JsonApiRelationships | null = null\n\n if (!rels) {\n return null\n }\n\n for (const key in rels) {\n const entry = rels[key]\n if (!entry) continue\n\n const isConfig = typeof entry !== 'function'\n const presenter = isConfig ? entry.presenter : entry\n const hasMany = isConfig ? entry.hasMany : undefined\n const optional = isConfig ? (entry.optional ?? false) : false\n\n const linkValue = links[key]\n const hasLinks = linkValue != null\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- unknown from adapter.get\n const data = this.constructor.adapter.get(instance, key) as ModelLike | ModelLike[] | null | undefined\n const keyPresent = this.constructor.adapter.has(instance, key)\n\n const buildData = (d: ModelLike): JsonApiResourceIdentifier => {\n const id = this.constructor.adapter.id(d)\n if (!id) {\n throw new Error(\n `Model of type ${presenter.type} is missing an id (relationship '${key}' of ${this.constructor.type})`,\n )\n }\n return { id, type: presenter.type }\n }\n\n // Skip in payload mode: an omitted relationship in a write must not be\n // confused with the model simply not having loaded it.\n if (optional && !keyPresent && !isPayload) {\n if (hasLinks) {\n if (!relationships) relationships = {}\n relationships[key] = { links: buildLinks(linkValue) }\n }\n continue\n }\n\n if (!relationships) relationships = {}\n const rel: JsonApiRelationship = {}\n\n if (Array.isArray(data)) {\n rel.data = data.map(buildData)\n } else if (data != null) {\n rel.data = buildData(data)\n } else if (hasMany === true) {\n rel.data = []\n } else if (!hasLinks) {\n rel.data = null\n }\n\n if (hasLinks) {\n rel.links = buildLinks(linkValue)\n }\n\n relationships[key] = rel\n }\n return relationships\n }\n\n buildSelfLink(instance: ModelLike): JsonApiLink | undefined {\n return buildLinks(this.selfLinks(instance))\n }\n\n toJSON(\n instanceOrCollection: ModelLike | ModelLike[] | null | undefined,\n options?: PresenterOptions,\n ): JsonApiDocument {\n const opts = options ?? {}\n if (opts.meta != null) {\n this.scope.meta = opts.meta\n }\n if (opts.links != null) {\n this.scope.links = opts.links\n }\n if (!this.scope.data) {\n this.scope.data = null\n }\n\n if (instanceOrCollection == null) {\n return this.scope\n }\n\n if (Array.isArray(instanceOrCollection)) {\n const collection = instanceOrCollection\n if (!this.scope.data) {\n this.scope.data = []\n }\n collection.forEach((instance: ModelLike) => {\n return this.toJSON(instance, options)\n })\n } else {\n const instance = instanceOrCollection\n let added = true\n const model: JsonApiResource = {\n id: this.id(instance),\n type: this.constructor.type,\n attributes: this.attributes(instance),\n }\n if (model.id === undefined) {\n delete model.id\n }\n const relationships = this.buildRelationships(instance)\n if (relationships != null) {\n model.relationships = relationships\n }\n const links = this.buildSelfLink(instance)\n if (links != null) {\n model.links = links\n }\n\n if (opts.include) {\n if (!this.scope.included) {\n this.scope.included = []\n }\n const allResources = (this.scope.included || []).concat(\n Array.isArray(this.scope.data) ? this.scope.data : this.scope.data ? [this.scope.data] : [],\n )\n if (!allResources.some((i) => i.id === model.id && i.type === model.type)) {\n this.scope.included.push(model)\n } else {\n added = false\n }\n } else if (this.scope.data != null) {\n if (Array.isArray(this.scope.data)) {\n if (!this.scope.data.some((i) => i.id === model.id && i.type === model.type)) {\n this.scope.data.push(model)\n } else {\n added = false\n }\n } else {\n // data is a single object, convert to array if needed\n this.scope.data = model\n }\n } else {\n this.scope.data = model\n }\n\n if (added) {\n this.includeRelationships(this.scope, instance)\n }\n }\n return this.scope\n }\n\n payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument {\n if (Array.isArray(instance)) {\n throw new Error('payload() expects a single resource, not an array')\n }\n if (instance == null) {\n throw new Error('payload() requires a resource, got null')\n }\n const model: JsonApiResource = {\n type: this.constructor.type,\n attributes: this.attributes(instance),\n }\n const id = this.id(instance)\n if (id != null) {\n model.id = id\n }\n const relationships = this.buildRelationships(instance, { payload: true })\n if (relationships != null) {\n model.relationships = relationships\n }\n const result: JsonApiDocument = { data: model }\n const opts = options ?? {}\n if (opts.meta != null) result.meta = opts.meta\n if (opts.links != null) result.links = opts.links\n return result\n }\n\n render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return this.toJSON(instanceOrCollection, options)\n }\n\n static toJSON(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return new this().toJSON(instanceOrCollection, options)\n }\n\n static render(instanceOrCollection: ModelLike | ModelLike[] | null, options?: PresenterOptions): JsonApiDocument {\n return new this().render(instanceOrCollection, options)\n }\n\n static payload(instance: ModelLike, options?: PresenterOptions): JsonApiDocument {\n return new this().payload(instance, options)\n }\n }\n\n return Presenter\n}\n\nexport type Presenter = ReturnType<typeof createPresenter>\n","/**\n * Interface for Zod-like schema objects.\n * Any schema library that implements `parse` and `safeParse` methods will work.\n */\nexport interface ZodLikeSchema {\n parse: (data: unknown) => unknown\n safeParse: (data: unknown) => { success: true; data: unknown } | { success: false; error: unknown }\n}\n\nexport function isZodLikeSchema(schema: unknown): schema is ZodLikeSchema {\n return (\n schema != null &&\n typeof schema === 'object' &&\n 'parse' in schema &&\n typeof schema.parse === 'function' &&\n 'safeParse' in schema &&\n typeof schema.safeParse === 'function'\n )\n}\n\nexport interface ValidationResult {\n valid: boolean\n data: unknown\n error?: unknown\n}\n\nexport function validate(schema: unknown, data: unknown, strict: boolean): ValidationResult {\n if (!isZodLikeSchema(schema)) {\n throw new Error('Invalid schema: must have parse and safeParse methods')\n }\n\n if (strict) {\n const validData = schema.parse(data)\n return { valid: true, data: validData }\n } else {\n const result = schema.safeParse(data)\n if (result.success) {\n return { valid: true, data: result.data }\n } else {\n return { valid: false, data, error: result.error }\n }\n }\n}\n","import type {\n InferModelType,\n JsonApiDocument,\n JsonApiLink,\n JsonApiRelationships,\n JsonApiResourceIdentifier,\n SchemaRegistry,\n StoreModel,\n StoreModelWithOptionalId,\n StoreModels,\n StoreOptions,\n StoreRecord as StoreRecordType,\n StoreResult,\n ValidationError,\n} from './types.js'\nimport { TYPE, LINKS, META, REL_LINKS, REL_META } from './symbols.js'\nimport { validate } from './schema.js'\n\nfunction hasId<T extends StoreModelWithOptionalId>(model: T): model is T & { id: string | number } {\n return model.id != null\n}\n\nclass StoreRecord implements StoreRecordType {\n id: string | number\n type: string\n attributes?: Record<string, unknown>\n relationships?: JsonApiRelationships\n links?: JsonApiLink\n meta?: Record<string, unknown>\n\n constructor(options: StoreRecordType) {\n this.id = options.id\n this.type = options.type\n this.attributes = options.attributes\n this.relationships = options.relationships\n this.links = options.links\n this.meta = options.meta\n }\n}\n\nexport default class Store<S extends SchemaRegistry = SchemaRegistry> {\n records: StoreRecord[] = []\n schemas?: S\n strict: boolean\n validationErrors: ValidationError[] = []\n\n constructor(options?: StoreOptions<S>) {\n this.schemas = options?.schemas\n this.strict = options?.strict ?? false\n this.reset()\n }\n\n reset(): void {\n this.records = []\n this.validationErrors = []\n }\n\n #createStub(type: string, id: string | number): StoreModel {\n const stub: StoreModel = { id }\n stub[TYPE] = type\n return stub\n }\n\n #createModel(\n resource: {\n type: string\n id?: string | number | null\n attributes?: Record<string, unknown> | null\n relationships?: JsonApiRelationships | null\n meta?: Record<string, unknown> | null\n links?: JsonApiLink | null\n },\n options?: {\n models?: StoreModels\n includeRelMeta?: boolean\n },\n ): StoreModelWithOptionalId {\n const models = options?.models ?? {}\n\n const model: StoreModelWithOptionalId = { ...(resource.attributes || {}) }\n if (resource.id != null) {\n model.id = resource.id\n }\n const type = resource.type\n model[TYPE] = type\n if (resource.meta != null) {\n model[META] = resource.meta\n }\n if (resource.links != null) {\n model[LINKS] = resource.links\n }\n\n // Cache before resolving relationships (for circular refs)\n if (hasId(model)) {\n const idStr = String(model.id)\n if (!models[type]) {\n models[type] = {}\n }\n if (!models[type][idStr]) {\n models[type][idStr] = model\n }\n }\n\n if (resource.relationships != null) {\n const resolver = (ref: JsonApiResourceIdentifier): StoreModel => {\n return this.#findModel(ref.type, ref.id, models) ?? this.#createStub(ref.type, ref.id)\n }\n this.#resolveRelationships(model, resource.relationships, resolver, {\n includeRelMeta: options?.includeRelMeta,\n })\n }\n return model\n }\n\n #resolveRelationships(\n model: StoreModel | StoreModelWithOptionalId,\n relationships: JsonApiRelationships,\n resolver: (ref: JsonApiResourceIdentifier) => StoreModel | StoreModelWithOptionalId,\n options?: { includeRelMeta?: boolean },\n ): void {\n const includeRelMeta = options?.includeRelMeta ?? true\n\n for (const key in relationships) {\n const rel = relationships[key]\n const { data, links, meta } = rel\n\n model[key] = null\n if (data == null && links == null) {\n continue\n }\n\n if (Array.isArray(data)) {\n model[key] = data.filter((item) => item.id != null).map(resolver)\n } else if (data != null && data.id != null) {\n const relModel = resolver(data)\n if (includeRelMeta) {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- REL_LINKS/REL_META only used when resolver returns StoreModel\n const modelWithMeta = relModel as StoreModel\n modelWithMeta[REL_LINKS] = links || {}\n modelWithMeta[REL_META] = meta || {}\n }\n model[key] = relModel\n } else if (data == null && (links != null || meta != null) && includeRelMeta) {\n const relModel: StoreModel = { id: '' }\n relModel[REL_LINKS] = links || {}\n relModel[REL_META] = meta || {}\n model[key] = relModel\n }\n }\n }\n\n toModel(rec: StoreRecord, type: string, models: StoreModels): StoreModel {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- StoreRecord always has id\n const model = this.#createModel(rec, { models }) as StoreModel\n\n // Validate with schema if provided\n if (this.schemas && this.schemas[rec.type]) {\n const schema = this.schemas[rec.type]\n const result = validate(schema, model, this.strict)\n\n if (!result.valid) {\n this.validationErrors.push({\n type: rec.type,\n id: rec.id,\n error: result.error,\n })\n }\n\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Schema validation returns unknown, cast to StoreModel after validation\n const validatedModel = result.data as StoreModel\n\n // Preserve symbol keys from original model (schema validation may not preserve them)\n validatedModel[TYPE] = model[TYPE]\n validatedModel[LINKS] = model[LINKS]\n validatedModel[META] = model[META]\n\n return validatedModel\n }\n\n return model\n }\n\n findRecord(type: string, id: string | number): StoreRecord | undefined {\n const idStr = String(id)\n return this.records.find((r) => r.type === type && String(r.id) === idStr)\n }\n\n findRecords(type: string): StoreRecord[] {\n return this.records.filter((r) => r.type === type)\n }\n\n #findModel(type: string, id: string | number, models: StoreModels): StoreModel | null {\n const idStr = String(id)\n const cached = models[type]?.[idStr]\n if (cached) {\n return cached\n }\n const rec = this.findRecord(type, id)\n if (rec == null) {\n return null\n }\n return this.toModel(rec, type, models)\n }\n\n find<T extends string>(type: T, id: string | number, models?: StoreModels): InferModelType<S, T> | null {\n const result = this.#findModel(type, id, models ?? {})\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from schema registry\n return result as InferModelType<S, T> | null\n }\n\n findAll<T extends string>(type: T, models?: StoreModels): InferModelType<S, T>[] {\n const modelsObj = models ?? {}\n const recs = this.findRecords(type)\n if (recs == null) {\n return []\n }\n recs.forEach((rec) => {\n if (!modelsObj[type]) {\n modelsObj[type] = {}\n }\n return this.toModel(rec, type, modelsObj)\n })\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from schema registry\n return Object.values(modelsObj[type] || {}) as InferModelType<S, T>[]\n }\n\n remove(type: string, id?: string | number): void {\n const removeOne = (record: StoreRecord): void => {\n const index = this.records.indexOf(record)\n if (!(index < 0)) {\n this.records.splice(index, 1)\n }\n }\n\n if (id != null) {\n const record = this.findRecord(type, String(id))\n if (record) {\n removeOne(record)\n }\n } else {\n this.findRecords(type).forEach(removeOne)\n }\n }\n\n syncAll(body: JsonApiDocument): StoreResult {\n // Clear previous validation errors\n this.validationErrors = []\n\n // Snapshot for rollback if strict validation throws\n const previousRecords = [...this.records]\n\n const syncData = (data: JsonApiDocument['data'] | JsonApiDocument['included']): StoreRecord[] => {\n if (data == null) {\n return []\n }\n const add = (obj: StoreRecordType): StoreRecord => {\n const { type, id } = obj\n this.remove(type, id)\n const rec = new StoreRecord(obj)\n this.records.push(rec)\n return rec\n }\n\n if (Array.isArray(data)) {\n return data.map((item) => {\n if (!item.id) {\n throw new Error(`Resource of type ${item.type} is missing an id`)\n }\n return add({\n ...item,\n attributes: item.attributes ?? undefined,\n relationships: item.relationships ?? undefined,\n id: item.id,\n })\n })\n } else {\n if (!data.id) {\n throw new Error(`Resource of type ${data.type} is missing an id`)\n }\n return [\n add({\n ...data,\n attributes: data.attributes ?? undefined,\n relationships: data.relationships ?? undefined,\n id: data.id,\n }),\n ]\n }\n }\n\n try {\n syncData(body.included)\n const recs = syncData(body.data)\n\n const models: StoreModels = {}\n const result: StoreResult = recs.map((rec) => this.toModel(rec, rec.type, models))\n if (body.meta != null) {\n result[META] = body.meta\n }\n return result\n } catch (e) {\n this.records = previousRecords\n throw e\n }\n }\n\n sync(body: JsonApiDocument): StoreModel | StoreResult {\n const result = this.syncAll(body)\n if (!Array.isArray(body.data) && body.data != null) {\n const model = result[0]\n if (result[META]) {\n model[META] = result[META]\n }\n return model\n }\n return result\n }\n\n /**\n * Build a model from a JSON:API document without storing it.\n * Useful for create payloads where id may be absent.\n *\n * Per JSON:API spec: \"The id member is not required when the resource object\n * originates at the client and represents a new resource to be created on the server.\"\n */\n static build(body: JsonApiDocument): StoreModelWithOptionalId {\n return new Store().build(body)\n }\n\n build(body: JsonApiDocument): StoreModelWithOptionalId {\n const { data } = body\n if (data == null || Array.isArray(data)) {\n throw new Error('build() expects a single resource in data, not null or an array')\n }\n return this.#createModel(data)\n }\n\n retrieve<T extends string>(type: T, body: JsonApiDocument): InferModelType<S, T> | null {\n const synced = this.syncAll(body)\n const model = synced.find((m) => m[TYPE] === type)\n if (!model) return null\n if (synced[META]) {\n model[META] = synced[META]\n }\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n return model as InferModelType<S, T>\n }\n\n retrieveAll<T extends string>(type: T, body: JsonApiDocument): StoreResult<InferModelType<S, T>> {\n const synced = this.syncAll(body)\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Enable type inference from type parameter\n const result: StoreResult<InferModelType<S, T>> = synced.filter((model) => model[TYPE] === type) as StoreResult<\n InferModelType<S, T>\n >\n result[META] = synced[META]\n return result\n }\n}\n","import Adapter from './yayson/adapter.js'\nimport * as adapters from './yayson/adapters/index.js'\nimport createPresenter, { Presenter } from './yayson/presenter.js'\nimport Store from './yayson/store.js'\nimport type {\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyStoreOptions,\n PresenterOptions,\n SchemaRegistry,\n StoreOptions,\n ValidationError,\n} from './yayson/types.js'\nimport type { ZodLikeSchema } from './yayson/schema.js'\n\ntype AdapterOption = string | typeof Adapter\n\ninterface YaysonOptions {\n adapter?: AdapterOption\n}\n\ninterface YaysonResult {\n Store: typeof Store\n Presenter: Presenter\n Adapter: typeof Adapter\n}\n\nfunction lookupAdapter(nameOrAdapter?: AdapterOption): typeof Adapter {\n if (nameOrAdapter === 'default' || !nameOrAdapter) {\n return Adapter\n } else if (typeof nameOrAdapter === 'string') {\n if (nameOrAdapter === 'sequelize') {\n return adapters.sequelize\n } else {\n throw new Error('Adapter not found: ' + nameOrAdapter)\n }\n }\n return nameOrAdapter\n}\n\nfunction yayson(options?: YaysonOptions): YaysonResult {\n const adapter = lookupAdapter(options?.adapter)\n const Presenter = createPresenter(adapter)\n\n return {\n Store,\n Presenter,\n Adapter,\n }\n}\n\nexport default yayson\nexport type {\n Adapter,\n JsonApiDocument,\n JsonApiLink,\n JsonApiLinks,\n JsonApiRelationship,\n JsonApiRelationships,\n JsonApiResource,\n LegacyStoreOptions,\n PresenterOptions,\n SchemaRegistry,\n StoreOptions,\n ValidationError,\n YaysonOptions,\n YaysonResult,\n ZodLikeSchema,\n}\n"],"mappings":"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"}
|