yayson 4.1.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.
Files changed (39) hide show
  1. package/README.md +43 -0
  2. package/build/legacy.cjs +27 -23
  3. package/build/legacy.d.cts +35 -7
  4. package/build/legacy.d.cts.map +1 -1
  5. package/build/legacy.d.mts +35 -7
  6. package/build/legacy.d.mts.map +1 -1
  7. package/build/legacy.mjs +27 -23
  8. package/build/legacy.mjs.map +1 -1
  9. package/build/{symbols-nFs99aEX.cjs → symbols-B--FS78o.cjs} +3 -0
  10. package/build/{symbols-DSjKJ8vh.mjs → symbols-BfU4k1el.mjs} +4 -1
  11. package/build/symbols-BfU4k1el.mjs.map +1 -0
  12. package/build/{types-NiKV-lj-.d.cts → types-KZiF6x7A.d.mts} +14 -2
  13. package/build/types-KZiF6x7A.d.mts.map +1 -0
  14. package/build/{types-Do2flKZX.d.mts → types-iC38_iCI.d.cts} +14 -2
  15. package/build/types-iC38_iCI.d.cts.map +1 -0
  16. package/build/utils.cjs +1 -1
  17. package/build/utils.d.cts +1 -1
  18. package/build/utils.d.mts +1 -1
  19. package/build/utils.mjs +1 -1
  20. package/build/{yayson-l2JKseMH.cjs → yayson-B51EJfRP.cjs} +97 -27
  21. package/build/{yayson-3UYKq2H5.d.cts → yayson-BvwMr4Ad.d.mts} +6 -4
  22. package/build/yayson-BvwMr4Ad.d.mts.map +1 -0
  23. package/build/{yayson-Ce5uGpgU.d.mts → yayson-DTMLeA5k.d.cts} +6 -4
  24. package/build/yayson-DTMLeA5k.d.cts.map +1 -0
  25. package/build/{yayson-CwZg5FNt.mjs → yayson-RzT9zsdx.mjs} +81 -29
  26. package/build/yayson-RzT9zsdx.mjs.map +1 -0
  27. package/build/yayson.cjs +1 -1
  28. package/build/yayson.d.cts +2 -2
  29. package/build/yayson.d.mts +2 -2
  30. package/build/yayson.mjs +1 -1
  31. package/package.json +1 -1
  32. package/skill/yayson/SKILL.md +20 -0
  33. package/skill/yayson/references/api.md +27 -2
  34. package/build/symbols-DSjKJ8vh.mjs.map +0 -1
  35. package/build/types-Do2flKZX.d.mts.map +0 -1
  36. package/build/types-NiKV-lj-.d.cts.map +0 -1
  37. package/build/yayson-3UYKq2H5.d.cts.map +0 -1
  38. package/build/yayson-Ce5uGpgU.d.mts.map +0 -1
  39. package/build/yayson-CwZg5FNt.mjs.map +0 -1
@@ -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
@@ -1,3 +1,3 @@
1
- const require_yayson = require('./yayson-l2JKseMH.cjs');
1
+ const require_yayson = require('./yayson-B51EJfRP.cjs');
2
2
 
3
3
  module.exports = require_yayson.yayson_default;
@@ -1,3 +1,3 @@
1
- import { T as Adapter, a as JsonApiRelationship, d as SchemaRegistry, h as StoreOptions, i as JsonApiLinks, l as LegacyStoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, v as ValidationError, y as ZodLikeSchema } from "./types-NiKV-lj-.cjs";
2
- import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-3UYKq2H5.cjs";
1
+ import { E as Adapter, a as JsonApiRelationship, b as ZodLikeSchema, f as SchemaRegistry, g as StoreOptions, i as JsonApiLinks, l as LegacyStoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, y as ValidationError } from "./types-iC38_iCI.cjs";
2
+ import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-DTMLeA5k.cjs";
3
3
  export { Adapter, JsonApiDocument, JsonApiLink, JsonApiLinks, JsonApiRelationship, JsonApiRelationships, JsonApiResource, LegacyStoreOptions, PresenterOptions, SchemaRegistry, StoreOptions, ValidationError, YaysonOptions, YaysonResult, ZodLikeSchema, yayson as default };
@@ -1,3 +1,3 @@
1
- import { T as Adapter, a as JsonApiRelationship, d as SchemaRegistry, h as StoreOptions, i as JsonApiLinks, l as LegacyStoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, v as ValidationError, y as ZodLikeSchema } from "./types-Do2flKZX.mjs";
2
- import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-Ce5uGpgU.mjs";
1
+ import { E as Adapter, a as JsonApiRelationship, b as ZodLikeSchema, f as SchemaRegistry, g as StoreOptions, i as JsonApiLinks, l as LegacyStoreOptions, n as JsonApiDocument, o as JsonApiRelationships, r as JsonApiLink, s as JsonApiResource, u as PresenterOptions, y as ValidationError } from "./types-KZiF6x7A.mjs";
2
+ import { n as YaysonResult, r as yayson, t as YaysonOptions } from "./yayson-BvwMr4Ad.mjs";
3
3
  export { Adapter, JsonApiDocument, JsonApiLink, JsonApiLinks, JsonApiRelationship, JsonApiRelationships, JsonApiResource, LegacyStoreOptions, PresenterOptions, SchemaRegistry, StoreOptions, ValidationError, YaysonOptions, YaysonResult, ZodLikeSchema, yayson as default };
package/build/yayson.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { t as yayson_default } from "./yayson-CwZg5FNt.mjs";
1
+ import { t as yayson_default } from "./yayson-RzT9zsdx.mjs";
2
2
 
3
3
  export { yayson_default as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yayson",
3
- "version": "4.1.0",
3
+ "version": "4.3.0",
4
4
  "description": "A library for serializing and reading JSON API standardized data in JavaScript.",
5
5
  "type": "module",
6
6
  "main": "./build/yayson.cjs",
@@ -68,6 +68,26 @@ BikePresenter.render({ id: 1, wheels: [{ id: 10 }, { id: 11 }] })
68
68
  // included = [{ type: 'wheels', id: '10', ... }, ...]
69
69
  ```
70
70
 
71
+ For to-many relationships and conditionally loaded (`?include=`) responses, declare cardinality and/or optional semantics via the config form:
72
+
73
+ ```typescript
74
+ class TicketPresenter extends Presenter {
75
+ static type = 'tickets'
76
+ relationships() {
77
+ return {
78
+ addons: { presenter: AddonPresenter, hasMany: true }, // empty → data: []
79
+ parentTicket: { presenter: TicketPresenter, optional: true }, // key absent → omitted
80
+ guestTickets: { presenter: TicketPresenter, hasMany: true, optional: true },
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ - `hasMany: true` → empty/missing data renders as `data: []` instead of `data: null` (spec-compliant for to-many).
87
+ - `optional: true` → when the relationship key is absent from the instance, the relationship is omitted from output entirely (or rendered as `{ links }` only if `links()` configures one for that key). An explicit `null` on the instance still renders as `data: null` — `optional` distinguishes "not loaded" from "explicitly empty".
88
+
89
+ The bare-class form is unchanged.
90
+
71
91
  ### Custom attributes
72
92
 
73
93
  Override `attributes()` to transform or compute attributes.
@@ -35,9 +35,9 @@ function yayson(options?: { adapter?: 'default' | 'sequelize' | AdapterClass }):
35
35
 
36
36
  ### Instance Methods
37
37
 
38
- #### `relationships(): Record<string, typeof Presenter>`
38
+ #### `relationships(): Record<string, typeof Presenter | RelationshipConfig>`
39
39
 
40
- Return map of property names to their Presenter classes. Relationship keys are automatically excluded from attributes.
40
+ Return map of property names to their Presenter classes (or a config object). Relationship keys are automatically excluded from attributes.
41
41
 
42
42
  ```typescript
43
43
  relationships() {
@@ -45,6 +45,27 @@ relationships() {
45
45
  }
46
46
  ```
47
47
 
48
+ Use the config form to declare cardinality or conditional-include semantics:
49
+
50
+ ```typescript
51
+ relationships() {
52
+ return {
53
+ addons: { presenter: AddonPresenter, hasMany: true },
54
+ parentTicket: { presenter: TicketPresenter, optional: true },
55
+ guestTickets: { presenter: TicketPresenter, hasMany: true, optional: true },
56
+ }
57
+ }
58
+ ```
59
+
60
+ | Flag | Type | Effect |
61
+ | ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
62
+ | `hasMany` | `boolean` | Declares a to-many relationship. Empty/missing data renders as `data: []` (JSON:API requires `[]`, not `null`, for empty to-many). |
63
+ | `optional` | `boolean` | When the key is absent from the instance, the relationship is omitted entirely (or rendered with only `links` if `links()` provides them for the key). Explicit `null`/`[]` values on the instance still render normally — the distinction is "absent" vs "empty". |
64
+
65
+ The bare-class form (`Presenter` directly) is unchanged: missing data renders as `data: null` regardless of cardinality.
66
+
67
+ In `payload()` output, `optional` omission is disabled (a write request asserts state, so dropping a relationship would be misleading), but `hasMany: true` still applies so a client can correctly clear a to-many relationship with `data: []`.
68
+
48
69
  #### `attributes(instance): Record<string, unknown>`
49
70
 
50
71
  Return attributes for the resource. Default strips `id` and relationship keys, then applies `fields` filter. Override to customize.
@@ -221,6 +242,7 @@ Works with plain JS objects.
221
242
  Adapter.get(model) // returns shallow copy of all properties
222
243
  Adapter.get(model, 'key') // returns single property value
223
244
  Adapter.id(model) // returns model.id as string
245
+ Adapter.has(model, 'key') // returns true if key is present on the model (used by optional relationships)
224
246
  ```
225
247
 
226
248
  ### Sequelize Adapter
@@ -240,10 +262,13 @@ const { Presenter } = yayson({
240
262
  adapter: {
241
263
  id: (model) => String(model.pk),
242
264
  get: (model, key) => (key ? model.attrs[key] : model.attrs),
265
+ has: (model, key) => key in model.attrs,
243
266
  },
244
267
  })
245
268
  ```
246
269
 
270
+ Implementing `has(model, key)` is only required when using `optional: true` relationships. It tells the presenter whether a relationship key is actually present on the model (so an unloaded relationship can be omitted) versus loaded-but-null. The default adapter uses `key in model`; custom adapters that store data on a sub-property (like `model.attrs` above) need to override it.
271
+
247
272
  ## Type Inference
248
273
 
249
274
  With schema registry, store methods infer TypeScript types automatically:
@@ -1 +0,0 @@
1
- {"version":3,"file":"symbols-DSjKJ8vh.mjs","names":[],"sources":["../src/yayson/adapter.ts","../src/yayson/symbols.ts"],"sourcesContent":["export type ModelLike = object\n\nclass Adapter {\n static get(model: ModelLike): Record<string, unknown>\n static get(model: ModelLike, key: string): unknown\n static get(model: ModelLike, key?: string): unknown {\n // eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- ModelLike is object for flexibility, cast for dynamic access\n const obj = model as Record<string, unknown>\n if (key) {\n return obj[key]\n }\n return obj\n }\n\n static id(model: ModelLike): string | undefined {\n const id = this.get(model, 'id')\n if (id == null) {\n return undefined\n }\n return `${id}`\n }\n}\n\nexport default Adapter\n","export const TYPE: unique symbol = Symbol('yayson.type')\nexport const LINKS: unique symbol = Symbol('yayson.links')\nexport const META: unique symbol = Symbol('yayson.meta')\nexport const REL_LINKS: unique symbol = Symbol('yayson.rel-links')\nexport const REL_META: unique symbol = Symbol('yayson.rel-meta')\n"],"mappings":";AAEA,IAAM,UAAN,MAAc;CAGZ,OAAO,IAAI,OAAkB,KAAuB;EAElD,MAAM,MAAM;AACZ,MAAI,IACF,QAAO,IAAI;AAEb,SAAO;;CAGT,OAAO,GAAG,OAAsC;EAC9C,MAAM,KAAK,KAAK,IAAI,OAAO,KAAK;AAChC,MAAI,MAAM,KACR;AAEF,SAAO,GAAG;;;AAId,sBAAe;;;;ACvBf,MAAa,OAAsB,OAAO,cAAc;AACxD,MAAa,QAAuB,OAAO,eAAe;AAC1D,MAAa,OAAsB,OAAO,cAAc;AACxD,MAAa,YAA2B,OAAO,mBAAmB;AAClE,MAAa,WAA0B,OAAO,kBAAkB"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-Do2flKZX.d.mts","names":[],"sources":["../../../../../../yayson/adapter.ts","../../../../../../yayson/symbols.ts","../../../../../../yayson/schema.ts","../../../../../../yayson/types.ts"],"mappings":";KAAY,SAAA;AAAA,cAEN,OAAA;EAAA,OACG,GAAA,CAAI,KAAA,EAAO,SAAA,GAAY,MAAA;EAAA,OACvB,GAAA,CAAI,KAAA,EAAO,SAAA,EAAW,GAAA;EAAA,OAUtB,EAAA,CAAG,KAAA,EAAO,SAAA;AAAA;;;cCdN,IAAA;AAAA,cACA,KAAA;AAAA,cACA,IAAA;AAAA,cACA,SAAA;AAAA,cACA,QAAA;;;;ADJb;;;UEIiB,aAAA;EACf,KAAA,GAAQ,IAAA;EACR,SAAA,GAAY,IAAA;IAAoB,OAAA;IAAe,IAAA;EAAA;IAAoB,OAAA;IAAgB,KAAA;EAAA;AAAA;;;UCHpE,WAAA,SAAoB,MAAA;EACnC,IAAA;EACA,OAAA;AAAA;AAAA,UAGe,YAAA;EAAA,CACd,GAAA,WAAc,WAAA;AAAA;AAAA,UAGA,yBAAA;EACf,EAAA;EACA,IAAA;AAAA;AAAA,UAGe,mBAAA;EACf,IAAA,GAAO,yBAAA,GAA4B,yBAAA;EACnC,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,oBAAA;EAAA,CACd,GAAA,WAAc,mBAAA;AAAA;AAAA,UAGA,eAAA;EACf,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,eAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAA;EACxB,QAAA,GAAW,eAAA;EACX,KAAA,GAAQ,YAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,gBAAA;EACf,IAAA,GAAO,MAAA;EACP,KAAA,GAAQ,YAAA;EACR,OAAA;AAAA;AAAA,UAGe,sBAAA,SAA+B,gBAAA;EAC9C,aAAA;AAAA;AAAA,UAGe,WAAA;EACf,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,UAAA,SAAmB,MAAA;EAClC,EAAA;EAAA,CACC,IAAA;EAAA,CACA,KAAA,IAAS,WAAA;EAAA,CACT,IAAA,IAAQ,MAAA;EAAA,CACR,SAAA,IAAa,WAAA;EAAA,CACb,QAAA,IAAY,MAAA;AAAA;ADhEf;AAAA,UCoEiB,wBAAA,SAAiC,MAAA;EAChD,EAAA;EAAA,CACC,IAAA;EAAA,CACA,KAAA,IAAS,WAAA;EAAA,CACT,IAAA,IAAQ,MAAA;AAAA;AAAA,UAGM,WAAA;EAAA,CACd,IAAA;IAAA,CACE,EAAA,WAAa,UAAA;EAAA;AAAA;AAAA,UAID,cAAA;EAAA,CACd,IAAA,WAAe,aAAA;AAAA;AAAA,KAIN,eAAA,WAA0B,MAAA;EACpC,KAAA,GAAQ,IAAA;EACR,SAAA,GAAY,IAAA;AAAA,IAEV,UAAA;AAAA,KAGQ,cAAA,sCAAoD,QAAA,SAAiB,cAAA,GAC7E,QAAA,eAAuB,QAAA,GACrB,eAAA,CAAgB,QAAA,CAAS,QAAA,KACzB,UAAA,GACF,UAAA;AAAA,UAEa,WAAA,KAAgB,UAAA,UAAoB,KAAA,CAAM,CAAA;EAAA,CACxD,IAAA,IAAQ,MAAA;AAAA;AAAA,UAGM,YAAA,WAAuB,cAAA,GAAiB,cAAA;EACvD,OAAA,GAAU,CAAA;EACV,MAAA;AAAA;AAAA,UAGe,eAAA;EACf,IAAA;EACA,EAAA;EACA,KAAA;AAAA;AAAA,UAGe,kBAAA,WAA6B,cAAA,GAAiB,cAAA;EAC7D,KAAA,GAAQ,MAAA;EACR,OAAA,GAAU,CAAA;EACV,MAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-NiKV-lj-.d.cts","names":[],"sources":["../../../../../../yayson/adapter.ts","../../../../../../yayson/symbols.ts","../../../../../../yayson/schema.ts","../../../../../../yayson/types.ts"],"mappings":";KAAY,SAAA;AAAA,cAEN,OAAA;EAAA,OACG,GAAA,CAAI,KAAA,EAAO,SAAA,GAAY,MAAA;EAAA,OACvB,GAAA,CAAI,KAAA,EAAO,SAAA,EAAW,GAAA;EAAA,OAUtB,EAAA,CAAG,KAAA,EAAO,SAAA;AAAA;;;cCdN,IAAA;AAAA,cACA,KAAA;AAAA,cACA,IAAA;AAAA,cACA,SAAA;AAAA,cACA,QAAA;;;;ADJb;;;UEIiB,aAAA;EACf,KAAA,GAAQ,IAAA;EACR,SAAA,GAAY,IAAA;IAAoB,OAAA;IAAe,IAAA;EAAA;IAAoB,OAAA;IAAgB,KAAA;EAAA;AAAA;;;UCHpE,WAAA,SAAoB,MAAA;EACnC,IAAA;EACA,OAAA;AAAA;AAAA,UAGe,YAAA;EAAA,CACd,GAAA,WAAc,WAAA;AAAA;AAAA,UAGA,yBAAA;EACf,EAAA;EACA,IAAA;AAAA;AAAA,UAGe,mBAAA;EACf,IAAA,GAAO,yBAAA,GAA4B,yBAAA;EACnC,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,oBAAA;EAAA,CACd,GAAA,WAAc,mBAAA;AAAA;AAAA,UAGA,eAAA;EACf,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,eAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAA;EACxB,QAAA,GAAW,eAAA;EACX,KAAA,GAAQ,YAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,gBAAA;EACf,IAAA,GAAO,MAAA;EACP,KAAA,GAAQ,YAAA;EACR,OAAA;AAAA;AAAA,UAGe,sBAAA,SAA+B,gBAAA;EAC9C,aAAA;AAAA;AAAA,UAGe,WAAA;EACf,EAAA;EACA,IAAA;EACA,UAAA,GAAa,MAAA;EACb,aAAA,GAAgB,oBAAA;EAChB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,MAAA;AAAA;AAAA,UAGQ,UAAA,SAAmB,MAAA;EAClC,EAAA;EAAA,CACC,IAAA;EAAA,CACA,KAAA,IAAS,WAAA;EAAA,CACT,IAAA,IAAQ,MAAA;EAAA,CACR,SAAA,IAAa,WAAA;EAAA,CACb,QAAA,IAAY,MAAA;AAAA;ADhEf;AAAA,UCoEiB,wBAAA,SAAiC,MAAA;EAChD,EAAA;EAAA,CACC,IAAA;EAAA,CACA,KAAA,IAAS,WAAA;EAAA,CACT,IAAA,IAAQ,MAAA;AAAA;AAAA,UAGM,WAAA;EAAA,CACd,IAAA;IAAA,CACE,EAAA,WAAa,UAAA;EAAA;AAAA;AAAA,UAID,cAAA;EAAA,CACd,IAAA,WAAe,aAAA;AAAA;AAAA,KAIN,eAAA,WAA0B,MAAA;EACpC,KAAA,GAAQ,IAAA;EACR,SAAA,GAAY,IAAA;AAAA,IAEV,UAAA;AAAA,KAGQ,cAAA,sCAAoD,QAAA,SAAiB,cAAA,GAC7E,QAAA,eAAuB,QAAA,GACrB,eAAA,CAAgB,QAAA,CAAS,QAAA,KACzB,UAAA,GACF,UAAA;AAAA,UAEa,WAAA,KAAgB,UAAA,UAAoB,KAAA,CAAM,CAAA;EAAA,CACxD,IAAA,IAAQ,MAAA;AAAA;AAAA,UAGM,YAAA,WAAuB,cAAA,GAAiB,cAAA;EACvD,OAAA,GAAU,CAAA;EACV,MAAA;AAAA;AAAA,UAGe,eAAA;EACf,IAAA;EACA,EAAA;EACA,KAAA;AAAA;AAAA,UAGe,kBAAA,WAA6B,cAAA,GAAiB,cAAA;EAC7D,KAAA,GAAQ,MAAA;EACR,OAAA,GAAU,CAAA;EACV,MAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"yayson-3UYKq2H5.d.cts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBAyBwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAoB1B,SAAA,UAAmB,oBAAA;4BA0DxB,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;;;cCnQpC,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;EAmGA,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;EDrJrC;;;;;;;EAAA,OCwKE,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;;;KCzU1F,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 +0,0 @@
1
- {"version":3,"file":"yayson-Ce5uGpgU.d.mts","names":[],"sources":["../../../../../../yayson/presenter.ts","../../../../../../yayson/store.ts","../../../../../../yayson.ts"],"mappings":";;;iBAyBwB,eAAA,CAAgB,OAAA,SAAgB,OAAA;EAAA,aAUhC,eAAA;iBAVe;WAQ5B,eAAA;iBAMM,SAAA;yBAIQ,SAAA,GAAY,WAAA;sBAIf,SAAA,GAAY,YAAA;qBAIb,MAAA,SAZJ;yBAgBQ,SAAA,UAAmB,MAAA;gCAiBZ,eAAA,EAAe,QAAA,EAAY,SAAA;iCAoB1B,SAAA,UAAmB,oBAAA;4BA0DxB,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;;;cCnQpC,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;EAmGA,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;EDrJrC;;;;;;;EAAA,OCwKE,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;;;KCzU1F,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 +0,0 @@
1
- {"version":3,"file":"yayson-CwZg5FNt.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 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} 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> {\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 factory = relationships[key]\n if (!factory) throw new Error(`Presenter for ${key} in ${this.constructor.type} is not defined`)\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): JsonApiRelationships | null {\n if (instance == null) {\n return null\n }\n const rels = this.relationships()\n const links = this.links(instance) || {}\n let relationships: JsonApiRelationships | null = null\n\n if (!rels) {\n return null\n }\n\n for (const key in rels) {\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 presenter = rels[key]\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 {\n id,\n type: presenter.type,\n }\n }\n const build = (d: ModelLike | null | undefined): JsonApiRelationship => {\n const rel: JsonApiRelationship = {}\n if (d != null) {\n rel.data = buildData(d)\n }\n if (links[key] != null) {\n rel.links = buildLinks(links[key])\n } else if (d == null) {\n rel.data = null\n }\n return rel\n }\n if (!relationships) {\n relationships = {}\n }\n if (!relationships[key]) {\n relationships[key] = {}\n }\n if (Array.isArray(data)) {\n relationships[key].data = data.map(buildData)\n if (links[key] != null) {\n relationships[key].links = buildLinks(links[key])\n }\n } else {\n relationships[key] = build(data)\n }\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)\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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"}