@haddowg/json-api-client 1.0.0 → 1.2.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/README.md CHANGED
@@ -132,7 +132,7 @@ const albums = await client.albums.list({ withCount: ['tracks'] })
132
132
  All three collection surfaces (top-level lists, related collections, to-many relationship arrays)
133
133
  expose the same `$page` + `$next()` / `$prev()`. Navigation is **count-free-safe** — driven by
134
134
  link presence, not a total. Cursor pagination is just a paginator `kind`; page with
135
- `page[cursor]` / `page[size]` query params and walk it with `$next()`:
135
+ `page[after]` / `page[before]` / `page[size]` query params and walk it with `$next()`:
136
136
 
137
137
  ```ts
138
138
  let page = await client.tracks.list({ page: { size: 50 } })
@@ -262,6 +262,10 @@ Status matchers: `hasStatus(n)`, `is4xx()`, `is5xx()`, `isBadRequest()` /400,
262
262
  `parameter`) — the payoff for form/validation UX. Each error keeps its raw `source.pointer` as an
263
263
  escape hatch; atomic errors also carry an `opIndex`.
264
264
 
265
+ `hasErrorCode(err, code)` is true when `err` is a `JsonApiError` and any of its error objects
266
+ carries `code`. A generated client exports a version bound to its server's documented `ErrorCode`
267
+ union, so a misspelt code fails to compile and a match narrows to `JsonApiError<ErrorCode>`.
268
+
265
269
  > A response that parses but violates the JSON:API envelope shape (not a document, a member
266
270
  > missing `type`/`id`) throws a `StructuralGuardError` — distinct from a server-reported
267
271
  > `JsonApiError`. These light structural guards are always on; full per-field validation is opt-in
@@ -289,6 +293,10 @@ const client = createClient({ baseUrl: 'https://music.example', transport })
289
293
 
290
294
  Retries are deliberately out of scope here — the transport (or the TanStack layer) owns them.
291
295
 
296
+ `req.signal` is set when the caller passed a `signal` to a read (`client.albums.list({ signal })`
297
+ or `$next({ signal })`). Forward it to your HTTP library so the request can be cancelled; the
298
+ default `fetch` transport passes it to `fetch`.
299
+
292
300
  ## Opt-in validation
293
301
 
294
302
  The core runtime trusts the wire (you own both ends; the envelope is invariant) and only runs the
package/dist/ajv.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Validator, n as SchemaMap } from "./validate-BmyPbJCK.cjs";
1
+ import { a as Validator, n as SchemaMap } from "./validate-DgCUbzgT.cjs";
2
2
  import { ValidateFunction } from "ajv";
3
3
 
4
4
  //#region src/ajv.d.ts
package/dist/ajv.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as Validator, n as SchemaMap } from "./validate-BmyPbJCK.mjs";
1
+ import { a as Validator, n as SchemaMap } from "./validate-DgCUbzgT.mjs";
2
2
  import { ValidateFunction } from "ajv";
3
3
 
4
4
  //#region src/ajv.d.ts
package/dist/index.cjs CHANGED
@@ -16,6 +16,9 @@ var StructuralGuardError = class extends Error {
16
16
  /**
17
17
  * Thrown for any non-2xx JSON:API response. Carries the parsed error document plus
18
18
  * expressive status matchers and pointer-grouping helpers.
19
+ *
20
+ * `C` types each error object's `code` (see {@link JsonApiErrorObject}). It is a compile-time
21
+ * hint only: the runtime never checks a code against it.
19
22
  */
20
23
  var JsonApiError = class extends Error {
21
24
  status;
@@ -80,6 +83,60 @@ var JsonApiError = class extends Error {
80
83
  return out;
81
84
  }
82
85
  };
86
+ /**
87
+ * True when `err` is a {@link JsonApiError} and any of its error objects carries `code`. Takes
88
+ * any string, so it also matches codes the server never documented. A generated client exports a
89
+ * `hasErrorCode` bound to its server's `ErrorCode` union, which rejects a misspelt code at
90
+ * compile time; reach for this one only to match an undocumented code.
91
+ */
92
+ function hasErrorCode(err, code) {
93
+ return err instanceof JsonApiError && err.errors.some((e) => e.code === code);
94
+ }
95
+ //#endregion
96
+ //#region src/pagination.ts
97
+ /** The wire key for each role when the server keeps the default names. */
98
+ const CANONICAL_PAGE_KEYS = {
99
+ page: {
100
+ number: "number",
101
+ size: "size"
102
+ },
103
+ offset: {
104
+ offset: "offset",
105
+ limit: "limit"
106
+ },
107
+ cursor: {
108
+ after: "after",
109
+ before: "before",
110
+ size: "size"
111
+ },
112
+ fixed: { number: "number" },
113
+ none: {}
114
+ };
115
+ /**
116
+ * Resolve the strategy that answers a read from the endpoint's paginator and the `page` the
117
+ * request sends. A menu answers with the arm named by `page.kind`, else its `default`.
118
+ */
119
+ function resolvePaginator(paginator, page) {
120
+ if (paginator === void 0) return {
121
+ kind: "none",
122
+ keys: {}
123
+ };
124
+ if (typeof paginator === "string") return {
125
+ kind: paginator,
126
+ keys: CANONICAL_PAGE_KEYS[paginator]
127
+ };
128
+ if (paginator.strategy !== "multi") return {
129
+ kind: paginator.strategy,
130
+ keys: paginator.keys
131
+ };
132
+ const picked = page?.["kind"];
133
+ const arm = typeof picked === "string" && Object.hasOwn(paginator.arms, picked) ? picked : void 0;
134
+ const resolved = resolvePaginator(paginator.arms[arm ?? paginator.default]);
135
+ return arm === void 0 ? resolved : {
136
+ ...resolved,
137
+ arm
138
+ };
139
+ }
83
140
  //#endregion
84
141
  //#region src/validate.ts
85
142
  /** Whether a `validate` option is the schema-driven config (vs a bare validator function). */
@@ -192,9 +249,10 @@ const defineGetter = (target, key, get) => {
192
249
  * full resource) — a structural guess can't tell them apart for an attribute-less,
193
250
  * relation-less resource, so the caller passes the surface it issued.
194
251
  *
195
- * `paginatorOverride` sets the top-level array's `$page.kind` for a related/relationship read,
196
- * where the paginator is the RELATION's (which may diverge from the related type's collection —
197
- * D6a) and an empty page carries no member to sniff a type from. `primaryType` is preferred for a
252
+ * `paginatorOverride` sets the top-level array's `$page` for a related/relationship read, where the
253
+ * paginator is the RELATION's (which may diverge from the related type's collection — D6a), for a
254
+ * menu read that picked an arm, and where an empty page carries no member to sniff a type from. A
255
+ * bare kind is read with its canonical wire keys. `primaryType` is preferred for a
198
256
  * top-level collection read (statically-known); both override the sniff-from-`data[0]` fallback.
199
257
  */
200
258
  function materialise(doc, ctx, linkage = false, primaryType, paginatorOverride) {
@@ -247,7 +305,7 @@ function buildNode(raw, env, index, nodes, ctx) {
247
305
  for (const [name, rel] of Object.entries(rels)) {
248
306
  if (!("data" in rel)) continue;
249
307
  const relDesc = resType?.relations[name];
250
- node[name] = hydrateRelation(rel, relDesc?.cardinality, relatedPaginatorKind(relDesc, ctx), env, index, nodes, ctx);
308
+ node[name] = hydrateRelation(rel, relDesc?.cardinality, resolvePaginator(relatedPaginator(relDesc, ctx)), env, index, nodes, ctx);
251
309
  }
252
310
  attachResourceEnvelope(node, raw, env, rels);
253
311
  return node;
@@ -257,13 +315,13 @@ function buildNode(raw, env, index, nodes, ctx) {
257
315
  * linked-but-not-included member stays an identifier, an empty to-one is `null`, and a
258
316
  * to-many is always an augmented array (of views and/or identifiers).
259
317
  *
260
- * `relatedKind` is the related type's paginator kind (from the descriptor), threaded so a
261
- * to-many array reports the same `$page.kind` it would on its dedicated endpoint.
318
+ * `related` is the relation's paginator (from the descriptor), threaded so a to-many array
319
+ * reports the same `$page` it would on its dedicated endpoint without a `page` argument.
262
320
  */
263
- function hydrateRelation(rel, cardinality, relatedKind, env, index, nodes, ctx) {
321
+ function hydrateRelation(rel, cardinality, related, env, index, nodes, ctx) {
264
322
  const data = rel.data;
265
- if (Array.isArray(data)) return augmentRelationArray(data.map((member) => resolveMember(member, env, index, nodes, ctx)), rel, relatedKind, ctx);
266
- if (data === void 0 && cardinality === "many") return augmentRelationArray([], rel, relatedKind, ctx);
323
+ if (Array.isArray(data)) return augmentRelationArray(data.map((member) => resolveMember(member, env, index, nodes, ctx)), rel, related, ctx);
324
+ if (data === void 0 && cardinality === "many") return augmentRelationArray([], rel, related, ctx);
267
325
  if (data === null || data === void 0) return data === null ? null : void 0;
268
326
  if (isObject$2(data)) return resolveMember(data, env, index, nodes, ctx, {
269
327
  links: rel.links,
@@ -370,35 +428,40 @@ function augmentArray(members, doc, ctx, linkage, primaryType, paginatorOverride
370
428
  const links = doc.links;
371
429
  defineGetter(arr, "$links", () => links);
372
430
  defineGetter(arr, "$meta", () => doc.meta);
373
- attachPage(arr, paginatorOverride ?? paginatorKind(doc, ctx, primaryType), pageMeta(doc.meta), links, ctx, linkage);
431
+ attachPage(arr, paginatorOverride === void 0 ? resolvePaginator(primaryPaginator(doc, ctx, primaryType)) : typeof paginatorOverride === "string" ? resolvePaginator(paginatorOverride) : paginatorOverride, pageMeta(doc.meta), links, ctx, linkage);
374
432
  return arr;
375
433
  }
376
434
  /**
377
- * A to-many relationship array: `$page`/links/meta come from the relationship object. `kind`
378
- * is the related type's paginator (so an in-document compound-include to-many reports the same
435
+ * A to-many relationship array: `$page`/links/meta come from the relationship object.
436
+ * `paginator` is the relation's (so an in-document compound-include to-many reports the same
379
437
  * discriminant it would when fetched at its own relationship/related endpoint — "one model,
380
438
  * three surfaces").
381
439
  */
382
- function augmentRelationArray(members, rel, kind, ctx) {
440
+ function augmentRelationArray(members, rel, paginator, ctx) {
383
441
  const arr = [...members];
384
442
  const links = rel.links;
385
443
  defineGetter(arr, "$links", () => links);
386
444
  defineGetter(arr, "$meta", () => rel.meta);
387
- attachPage(arr, kind, pageMeta(rel.meta), links, ctx, false);
445
+ attachPage(arr, paginator, pageMeta(rel.meta), links, ctx, false);
388
446
  return arr;
389
447
  }
390
448
  /** Attach `$page` + `$next()`/`$prev()` driven by link presence (count-free-safe). */
391
- function attachPage(arr, kind, meta, links, ctx, linkage) {
449
+ function attachPage(arr, paginator, meta, links, ctx, linkage) {
392
450
  const page = {
393
- kind,
451
+ kind: paginator.kind,
452
+ keys: paginator.keys,
394
453
  links: pageLinks(links)
395
454
  };
455
+ if (paginator.arm !== void 0) page.arm = paginator.arm;
396
456
  if (meta !== void 0) page.meta = meta;
397
457
  defineGetter(arr, "$page", () => page);
398
- define(arr, "$next", () => navigateLink(page.links.next, ctx, linkage, kind));
399
- define(arr, "$prev", () => navigateLink(page.links.prev, ctx, linkage, kind));
458
+ define(arr, "$next", (options) => navigateLink(page.links.next, ctx, linkage, paginator, options?.signal));
459
+ define(arr, "$prev", (options) => navigateLink(page.links.prev, ctx, linkage, paginator, options?.signal));
400
460
  }
401
- const navigateLink = (link, ctx, linkage, paginator) => link === void 0 ? Promise.resolve(void 0) : ctx.navigate(link, linkage, paginator);
461
+ const navigateLink = (link, ctx, linkage, paginator, signal) => {
462
+ if (link === void 0) return Promise.resolve(void 0);
463
+ return signal === void 0 ? ctx.navigate(link, linkage, paginator) : ctx.navigate(link, linkage, paginator, signal);
464
+ };
402
465
  /** Extract the navigation links (a link may be a string or a `{href}` object). */
403
466
  function pageLinks(links) {
404
467
  const out = {};
@@ -420,18 +483,18 @@ const linkHref = (link) => {
420
483
  };
421
484
  const pageMeta = (meta) => isObject$2(meta?.["page"]) ? meta["page"] : void 0;
422
485
  /**
423
- * The document's paginator kind (from the primary type's descriptor; default `none`). Prefers the
424
- * statically-known `primaryType` (passed by the descriptor binding at the call site) so an EMPTY
425
- * page still reports the collection's real kind; falls back to sniffing the first member's type
426
- * (for a re-materialised `$next()` page or a related read, where the primary type isn't threaded).
486
+ * The document's paginator (from the primary type's descriptor). Prefers the statically-known
487
+ * `primaryType` (passed by the descriptor binding at the call site) so an EMPTY page still reports
488
+ * the collection's real kind; falls back to sniffing the first member's type (for a re-materialised
489
+ * `$next()` page or a related read, where the primary type isn't threaded).
427
490
  */
428
- function paginatorKind(doc, ctx, primaryType) {
491
+ function primaryPaginator(doc, ctx, primaryType) {
429
492
  const first = Array.isArray(doc.data) ? doc.data[0] : doc.data;
430
493
  const type = primaryType ?? (isObject$2(first) && typeof first["type"] === "string" ? first["type"] : void 0);
431
- return type !== void 0 ? ctx.descriptor[type]?.paginator ?? "none" : "none";
494
+ return type !== void 0 ? ctx.descriptor[type]?.paginator : void 0;
432
495
  }
433
496
  /**
434
- * A to-many relation's paginator kind. The relation's OWN related/relationship endpoint may
497
+ * A to-many relation's paginator. The relation's OWN related/relationship endpoint may
435
498
  * paginate differently than the related type's top-level collection (D6a), so prefer the
436
499
  * per-relation `paginator` (carried in the descriptor only when it diverges); otherwise fall back
437
500
  * to the related type's own paginator (the relationship and related endpoints both paginate that
@@ -439,11 +502,14 @@ function paginatorKind(doc, ctx, primaryType) {
439
502
  * resolves off its first declared related type (its members span types, matching the relationship
440
503
  * endpoint's first-member resolution).
441
504
  */
442
- function relatedPaginatorKind(relation, ctx) {
505
+ function relatedPaginator(relation, ctx) {
443
506
  if (relation?.paginator !== void 0) return relation.paginator;
444
507
  const relatedType = relation?.types[0];
445
- if (relatedType === void 0) return "none";
446
- return ctx.descriptor[relatedType]?.paginator ?? "none";
508
+ return relatedType === void 0 ? void 0 : ctx.descriptor[relatedType]?.paginator;
509
+ }
510
+ /** The kind a relation's related read answers with when it sends no `page`. See {@link relatedPaginator}. */
511
+ function relatedPaginatorKind(relation, ctx) {
512
+ return resolvePaginator(relatedPaginator(relation, ctx)).kind;
447
513
  }
448
514
  //#endregion
449
515
  //#region src/types.ts
@@ -473,6 +539,14 @@ const ATOMIC_MEDIA_TYPE = mediaType({ ext: [ATOMIC_EXT] });
473
539
  //#endregion
474
540
  //#region src/request.ts
475
541
  const isAbsolute = (path) => /^https?:\/\//i.test(path);
542
+ const RELATIVE_ORIGIN = "http://relative.invalid";
543
+ /** Resolve a server link against `baseUrl` per RFC 3986. An absolute link is kept verbatim. */
544
+ function resolveLink(link, baseUrl) {
545
+ if (isAbsolute(link)) return link;
546
+ if (isAbsolute(baseUrl)) return new URL(link, baseUrl).href;
547
+ const resolved = new URL(link, new URL(baseUrl, RELATIVE_ORIGIN));
548
+ return resolved.origin === RELATIVE_ORIGIN ? resolved.pathname + resolved.search + resolved.hash : resolved.href;
549
+ }
476
550
  const append = (parts, key, value) => {
477
551
  if (value === void 0 || value === null || value === "") return;
478
552
  parts.push(`${key}=${encodeURIComponent(String(value))}`);
@@ -509,14 +583,14 @@ function serializeQuery(query) {
509
583
  return parts.join("&");
510
584
  }
511
585
  /**
512
- * Execute a request: build the URL (verbatim when already absolute — for page links —
513
- * else `baseUrl + path`), apply content negotiation and any async per-request headers,
586
+ * Execute a request: build the URL (a server link resolved against `baseUrl`, an absolute path
587
+ * verbatim, else `baseUrl + path`), apply content negotiation and any async per-request headers,
514
588
  * then drive the transport. A 2xx with a body parses to a {@link Document}; an empty /
515
589
  * 204 body resolves to `undefined`. A non-2xx throws a {@link JsonApiError} carrying the
516
590
  * parsed error objects (tolerating a non-JSON error body with an empty list).
517
591
  */
518
592
  async function execute(ctx, req) {
519
- let url = isAbsolute(req.path) ? req.path : ctx.baseUrl + req.path;
593
+ let url = req.link ? resolveLink(req.path, ctx.baseUrl) : isAbsolute(req.path) ? req.path : ctx.baseUrl + req.path;
520
594
  if (req.query) {
521
595
  const qs = serializeQuery(req.query);
522
596
  if (qs) url += (url.includes("?") ? "&" : "?") + qs;
@@ -531,6 +605,7 @@ async function execute(ctx, req) {
531
605
  url,
532
606
  headers
533
607
  };
608
+ if (req.signal !== void 0) transportReq.signal = req.signal;
534
609
  if (req.body !== void 0) {
535
610
  headers["Content-Type"] = req.contentType ?? negotiated;
536
611
  transportReq.body = req.raw && typeof req.body === "string" ? req.body : JSON.stringify(req.body);
@@ -928,6 +1003,7 @@ const fetchTransport = async (req) => {
928
1003
  headers: req.headers
929
1004
  };
930
1005
  if (req.body !== void 0) init.body = req.body;
1006
+ if (req.signal !== void 0) init.signal = req.signal;
931
1007
  const res = await fetch(req.url, init);
932
1008
  const headers = {};
933
1009
  res.headers.forEach((value, key) => {
@@ -959,12 +1035,16 @@ async function run(ctx, type, operation, vars, query, linkage = false, relationF
959
1035
  path: fill(template, vars)
960
1036
  };
961
1037
  if (query !== void 0) {
962
- req.query = query;
963
- negotiateProfiles(ctx, type, query, req, relationForCount);
1038
+ const { signal, ...params } = query;
1039
+ req.query = params;
1040
+ if (signal !== void 0) req.signal = signal;
1041
+ negotiateProfiles(ctx, type, params, req, relationForCount);
964
1042
  }
965
1043
  const doc = await execute(ctx.request, req);
1044
+ const relation = (operation === "fetchRelated" || operation === "fetchRelationship") && vars["rel"] !== void 0 ? ctx.descriptor[type]?.relations[vars["rel"]] : void 0;
1045
+ const paginator = operation === "fetchMany" ? ctx.descriptor[type]?.paginator : relation !== void 0 ? relatedPaginator(relation, ctx.materialise) : void 0;
966
1046
  const primaryType = operation === "fetchMany" ? type : void 0;
967
- const paginatorOverride = (operation === "fetchRelated" || operation === "fetchRelationship") && vars["rel"] !== void 0 ? relatedPaginatorKind(ctx.descriptor[type]?.relations[vars["rel"]], ctx.materialise) : void 0;
1047
+ const paginatorOverride = paginator === void 0 ? void 0 : resolvePaginator(paginator, query?.page);
968
1048
  return doc === void 0 ? void 0 : materialise(doc, ctx.materialise, linkage, primaryType, paginatorOverride);
969
1049
  }
970
1050
  /**
@@ -1181,7 +1261,7 @@ function typeAccessor(ctx, type) {
1181
1261
  * not per-type codegen: `client.<type>` yields a {@link TypeAccessor}, `.id(id)` a handle,
1182
1262
  * and a handle's relation accessors drive the relationship/related endpoints. Navigation
1183
1263
  * (`$next()`/`$prev()`, related links) is wired through `materialise`'s `navigate` seam,
1184
- * which executes the (absolute) link and re-materialises.
1264
+ * which resolves the server's link against `baseUrl`, executes it and re-materialises.
1185
1265
  */
1186
1266
  function createClient(descriptor, options) {
1187
1267
  const request = {
@@ -1195,10 +1275,12 @@ function createClient(descriptor, options) {
1195
1275
  descriptor,
1196
1276
  materialise: {
1197
1277
  descriptor,
1198
- navigate: async (url, linkage = false, paginator) => {
1278
+ navigate: async (url, linkage = false, paginator, signal) => {
1199
1279
  const doc = await execute(request, {
1200
1280
  method: "GET",
1201
- path: url
1281
+ path: url,
1282
+ link: true,
1283
+ ...signal !== void 0 ? { signal } : {}
1202
1284
  });
1203
1285
  return doc === void 0 ? void 0 : materialise(doc, ctx.materialise, linkage, void 0, paginator);
1204
1286
  },
@@ -1230,6 +1312,7 @@ function createClient(descriptor, options) {
1230
1312
  //#endregion
1231
1313
  exports.ATOMIC_EXT = ATOMIC_EXT;
1232
1314
  exports.ATOMIC_MEDIA_TYPE = ATOMIC_MEDIA_TYPE;
1315
+ exports.CANONICAL_PAGE_KEYS = CANONICAL_PAGE_KEYS;
1233
1316
  exports.HANDLE_RESERVED = HANDLE_RESERVED;
1234
1317
  exports.JSON_API_MEDIA_TYPE = JSON_API_MEDIA_TYPE;
1235
1318
  exports.JsonApiError = JsonApiError;
@@ -1238,11 +1321,14 @@ exports.assertJsonApiDocument = assertJsonApiDocument;
1238
1321
  exports.createClient = createClient;
1239
1322
  exports.execute = execute;
1240
1323
  exports.fetchTransport = fetchTransport;
1324
+ exports.hasErrorCode = hasErrorCode;
1241
1325
  exports.materialise = materialise;
1242
1326
  exports.mediaType = mediaType;
1327
+ exports.relatedPaginator = relatedPaginator;
1243
1328
  exports.relatedPaginatorKind = relatedPaginatorKind;
1244
1329
  exports.remapPointer = remapPointer;
1245
1330
  exports.remapRelationshipPointer = remapRelationshipPointer;
1331
+ exports.resolvePaginator = resolvePaginator;
1246
1332
  exports.resolveValidator = resolveValidator;
1247
1333
  exports.runAtomic = runAtomic;
1248
1334
  exports.serializeQuery = serializeQuery;
package/dist/index.d.cts CHANGED
@@ -1,11 +1,17 @@
1
- import { $ as SortQuery, A as DefaultActionTypes, At as RelationView, B as IncludePath, Bt as AtomicDescriptor, C as fetchTransport, Ct as mediaType, D as Collection, Dt as EdgeEnvelope, E as Client, Et as Edge, F as FieldsMap, Ft as ActionDescriptor, G as ReadResult, Gt as RelationDescriptor, H as LinkageRef, Ht as ClientIdPolicy, I as FilterKey, It as ActionInput, J as RelationshipAccessor, K as RelationName, Kt as RelationMutations, L as FilterQuery, Lt as ActionOutput, M as DefaultWriteAttributes, Mt as ResourceLinks, N as EdgeMembers, Nt as materialise, O as CountToken, Ot as MaterialiseContext, P as FieldSelectionMap, Pt as relatedPaginatorKind, Q as SingleReadQuery, R as HydratedMember, Rt as ActionScope, S as TransportResponse, St as ResourceIdentifier, T as AtomicResultOf, Tt as DocumentEnvelope, U as MemberName, Ut as CountableDescriptor, V as IncludedRelations, Vt as Cardinality, W as PivotInput, Wt as PaginatorKind, X as ResourceHandle, Y as ResourceAccessors, Z as ResourceObjectView, _ as HANDLE_RESERVED, _t as ATOMIC_EXT, a as Validator, at as WriteOptions, b as JsonApiTransport, bt as LocalIdentifier, c as resolveValidator, ct as AtomicDeleteHandle, d as JsonApiContext, dt as AtomicRef, et as SortToken, f as JsonApiRequest, ft as AtomicResult, g as ClientOptions, gt as runAtomic, h as serializeQuery, ht as AtomicUpdateInput, i as ValidationOption, it as UpdateInput, j as DefaultAttributes, jt as ResourceEnvelope, k as CreateInput, kt as Page, l as validateDocument, lt as AtomicHandle, m as execute, mt as AtomicUpdateHandle, n as SchemaMap, nt as TypeName, o as WireResource, ot as AtomicCreateHandle, p as ReadQuery, pt as AtomicResults, q as RelationReadQuery, qt as ResourceDescriptor, r as ValidationConfig, rt as TypedReadQuery, s as assertJsonApiDocument, st as AtomicCreateInput, t as ResolvedValidator, tt as TypeAccessor, u as Document, ut as AtomicRecorder, v as HeadersInit, vt as ATOMIC_MEDIA_TYPE, w as ActionsAccessor, wt as ArrayEnvelope, x as TransportRequest, xt as MediaTypeParams, y as createClient, yt as JSON_API_MEDIA_TYPE, z as IdentifierMember, zt as ApiDescriptor } from "./validate-BmyPbJCK.cjs";
1
+ import { $ as ResourceAccessors, $t as ActionInput, A as DefaultActionTypes, At as Edge, B as IdentifierMember, Bt as CANONICAL_PAGE_KEYS, C as fetchTransport, Ct as JSON_API_MEDIA_TYPE, D as Collection, Dt as mediaType, E as Client, Et as ResourceIdentifier, F as FieldSelectionMap, Ft as ResourceEnvelope, G as MemberName, Gt as PageMeta, H as IncludedRelations, Ht as Page, I as FieldsMap, It as ResourceLinks, J as RelationName, Jt as PageParamsOf, K as PivotInput, Kt as PageOf, L as FilterKey, Lt as materialise, M as DefaultWriteAttributes, Mt as MaterialiseContext, N as EdgeMembers, Nt as NavigateOptions, O as CountToken, Ot as ArrayEnvelope, P as ErrorCodeOf, Pt as RelationView, Q as RelationshipAccessor, Qt as ActionDescriptor, R as FilterQuery, Rt as relatedPaginator, S as TransportResponse, St as ATOMIC_MEDIA_TYPE, T as AtomicResultOf, Tt as MediaTypeParams, U as LinkageRef, Ut as PageKeys, V as IncludePath, Vt as ExactPageParams, W as ListPageParams, Wt as PageLinks, X as RelationPaginator, Xt as TypedPage, Y as RelationPageParams, Yt as ResolvedPaginator, Z as RelationReadQuery, Zt as resolvePaginator, _ as HANDLE_RESERVED, _t as AtomicResults, a as Validator, an as ClientIdPolicy, at as TypeAccessor, b as JsonApiTransport, bt as runAtomic, c as resolveValidator, cn as PaginatorDescriptor, ct as UpdateInput, d as JsonApiContext, dn as PaginatorStrategy, dt as AtomicCreateInput, en as ActionOutput, et as ResourceHandle, f as JsonApiRequest, fn as RelationDescriptor, ft as AtomicDeleteHandle, g as ClientOptions, gt as AtomicResult, h as serializeQuery, hn as StrategyDescriptor, ht as AtomicRef, i as ValidationOption, in as Cardinality, it as SortToken, j as DefaultAttributes, jt as EdgeEnvelope, k as CreateInput, kt as DocumentEnvelope, l as validateDocument, ln as PaginatorKind, lt as WriteOptions, m as execute, mn as ResourceDescriptor, mt as AtomicRecorder, n as SchemaMap, nn as ApiDescriptor, nt as SingleReadQuery, o as WireResource, on as CountableDescriptor, ot as TypeName, p as ReadQuery, pn as RelationMutations, pt as AtomicHandle, q as ReadResult, qt as PageParams, r as ValidationConfig, rn as AtomicDescriptor, rt as SortQuery, s as assertJsonApiDocument, sn as MenuDescriptor, st as TypedReadQuery, t as ResolvedValidator, tn as ActionScope, tt as ResourceObjectView, u as Document, un as PaginatorRole, ut as AtomicCreateHandle, v as HeadersInit, vt as AtomicUpdateHandle, w as ActionsAccessor, wt as LocalIdentifier, x as TransportRequest, xt as ATOMIC_EXT, y as createClient, yt as AtomicUpdateInput, z as HydratedMember, zt as relatedPaginatorKind } from "./validate-DgCUbzgT.cjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
- /** A single JSON:API error object (spec: error objects). */
5
- interface JsonApiErrorObject {
4
+ /**
5
+ * A single JSON:API error object (spec: error objects).
6
+ *
7
+ * `C` is the server's documented error-code union (a generated client's `ErrorCode`). `code` is
8
+ * typed `C | (string & {})`: editors suggest the documented codes, yet any other string still
9
+ * fits, because the catalogue is open and a server may send a code it never documented.
10
+ */
11
+ interface JsonApiErrorObject<C extends string = string> {
6
12
  id?: string;
7
13
  status?: string;
8
- code?: string;
14
+ code?: C | (string & {});
9
15
  title?: string;
10
16
  detail?: string;
11
17
  source?: {
@@ -40,11 +46,14 @@ declare class StructuralGuardError extends Error {
40
46
  /**
41
47
  * Thrown for any non-2xx JSON:API response. Carries the parsed error document plus
42
48
  * expressive status matchers and pointer-grouping helpers.
49
+ *
50
+ * `C` types each error object's `code` (see {@link JsonApiErrorObject}). It is a compile-time
51
+ * hint only: the runtime never checks a code against it.
43
52
  */
44
- declare class JsonApiError extends Error {
53
+ declare class JsonApiError<C extends string = string> extends Error {
45
54
  readonly status: number;
46
- readonly errors: JsonApiErrorObject[];
47
- constructor(status: number, errors: JsonApiErrorObject[], message?: string);
55
+ readonly errors: JsonApiErrorObject<C>[];
56
+ constructor(status: number, errors: JsonApiErrorObject<C>[], message?: string);
48
57
  hasStatus(status: number): boolean;
49
58
  is4xx(): boolean;
50
59
  is5xx(): boolean;
@@ -64,8 +73,21 @@ declare class JsonApiError extends Error {
64
73
  * query parameter). The payoff for form/validation UX — 422 `source.pointer`s are
65
74
  * remapped to the flat shape the caller actually supplied.
66
75
  */
67
- byPath(): Record<string, JsonApiErrorObject[]>;
76
+ byPath(): Record<string, JsonApiErrorObject<C>[]>;
68
77
  }
78
+ /**
79
+ * True when `err` is a {@link JsonApiError} and any of its error objects carries `code`. Takes
80
+ * any string, so it also matches codes the server never documented. A generated client exports a
81
+ * `hasErrorCode` bound to its server's `ErrorCode` union, which rejects a misspelt code at
82
+ * compile time; reach for this one only to match an undocumented code.
83
+ */
84
+ declare function hasErrorCode(err: unknown, code: string): err is JsonApiError;
85
+ /**
86
+ * {@link hasErrorCode} restricted to one server's documented codes. A generated client binds it:
87
+ * `export const hasErrorCode = hasErrorCodeRuntime as ErrorCodeGuard<ErrorCode>`. The cast is
88
+ * needed because `JsonApiError<string>` doesn't assign to `JsonApiError<ErrorCode>`.
89
+ */
90
+ type ErrorCodeGuard<C extends string> = (err: unknown, code: C) => err is JsonApiError<C>;
69
91
  //#endregion
70
92
  //#region src/serialize-write.d.ts
71
93
  /**
@@ -194,5 +216,5 @@ declare function withRemappedRelationshipPaths(error: JsonApiError, rel: string,
194
216
  */
195
217
  declare function withRemappedAtomicPaths(error: JsonApiError, descriptor: ApiDescriptor, typeForOp: (opIndex: number) => string | undefined): JsonApiError;
196
218
  //#endregion
197
- export { ATOMIC_EXT, ATOMIC_MEDIA_TYPE, ActionDescriptor, ActionInput, ActionOutput, ActionScope, ActionsAccessor, ApiDescriptor, ArrayEnvelope, AtomicCreateHandle, AtomicCreateInput, AtomicDeleteHandle, AtomicDescriptor, AtomicHandle, AtomicRecorder, AtomicRef, AtomicResult, AtomicResultOf, AtomicResults, AtomicUpdateHandle, AtomicUpdateInput, Cardinality, Client, ClientIdPolicy, ClientOptions, Collection, CountToken, CountableDescriptor, CreateInput, DefaultActionTypes, DefaultAttributes, DefaultWriteAttributes, Document, DocumentEnvelope, Edge, EdgeEnvelope, EdgeMembers, FieldSelectionMap, FieldsMap, FilterKey, FilterQuery, HANDLE_RESERVED, HeadersInit, HydratedMember, IdentifierMember, IncludePath, IncludedRelations, JSON_API_MEDIA_TYPE, JsonApiContext, JsonApiError, JsonApiErrorObject, JsonApiRequest, JsonApiTransport, LinkageRef, LocalIdentifier, MaterialiseContext, MediaTypeParams, MemberName, Page, PaginatorKind, PivotInput, ReadQuery, ReadResult, RelationDescriptor, RelationMutations, RelationName, RelationReadQuery, RelationView, RelationshipAccessor, RelationshipDocument, ResolvedValidator, ResourceAccessors, ResourceDescriptor, ResourceEnvelope, ResourceHandle, ResourceIdentifier, ResourceLinks, ResourceObjectView, SchemaMap, SingleReadQuery, SortQuery, SortToken, StructuralGuardError, ToDocumentOptions, TransportRequest, TransportResponse, TypeAccessor, TypeName, TypedReadQuery, UpdateInput, ValidationConfig, ValidationOption, Validator, WireResource, WriteDocument, WriteOptions, assertJsonApiDocument, createClient, execute, fetchTransport, materialise, mediaType, relatedPaginatorKind, remapPointer, remapRelationshipPointer, resolveValidator, runAtomic, serializeQuery, toDocument, toRelationshipDocument, validateDocument, withRemappedAtomicPaths, withRemappedPaths, withRemappedRelationshipPaths };
219
+ export { ATOMIC_EXT, ATOMIC_MEDIA_TYPE, ActionDescriptor, ActionInput, ActionOutput, ActionScope, ActionsAccessor, ApiDescriptor, ArrayEnvelope, AtomicCreateHandle, AtomicCreateInput, AtomicDeleteHandle, AtomicDescriptor, AtomicHandle, AtomicRecorder, AtomicRef, AtomicResult, AtomicResultOf, AtomicResults, AtomicUpdateHandle, AtomicUpdateInput, CANONICAL_PAGE_KEYS, Cardinality, Client, ClientIdPolicy, ClientOptions, Collection, CountToken, CountableDescriptor, CreateInput, DefaultActionTypes, DefaultAttributes, DefaultWriteAttributes, Document, DocumentEnvelope, Edge, EdgeEnvelope, EdgeMembers, ErrorCodeGuard, ErrorCodeOf, ExactPageParams, FieldSelectionMap, FieldsMap, FilterKey, FilterQuery, HANDLE_RESERVED, HeadersInit, HydratedMember, IdentifierMember, IncludePath, IncludedRelations, JSON_API_MEDIA_TYPE, JsonApiContext, JsonApiError, JsonApiErrorObject, JsonApiRequest, JsonApiTransport, LinkageRef, ListPageParams, LocalIdentifier, MaterialiseContext, MediaTypeParams, MemberName, MenuDescriptor, NavigateOptions, Page, PageKeys, PageLinks, PageMeta, PageOf, PageParams, PageParamsOf, PaginatorDescriptor, PaginatorKind, PaginatorRole, PaginatorStrategy, PivotInput, ReadQuery, ReadResult, RelationDescriptor, RelationMutations, RelationName, RelationPageParams, RelationPaginator, RelationReadQuery, RelationView, RelationshipAccessor, RelationshipDocument, ResolvedPaginator, ResolvedValidator, ResourceAccessors, ResourceDescriptor, ResourceEnvelope, ResourceHandle, ResourceIdentifier, ResourceLinks, ResourceObjectView, SchemaMap, SingleReadQuery, SortQuery, SortToken, StrategyDescriptor, StructuralGuardError, ToDocumentOptions, TransportRequest, TransportResponse, TypeAccessor, TypeName, TypedPage, TypedReadQuery, UpdateInput, ValidationConfig, ValidationOption, Validator, WireResource, WriteDocument, WriteOptions, assertJsonApiDocument, createClient, execute, fetchTransport, hasErrorCode, materialise, mediaType, relatedPaginator, relatedPaginatorKind, remapPointer, remapRelationshipPointer, resolvePaginator, resolveValidator, runAtomic, serializeQuery, toDocument, toRelationshipDocument, validateDocument, withRemappedAtomicPaths, withRemappedPaths, withRemappedRelationshipPaths };
198
220
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/serialize-write.ts"],"mappings":";;;;UACiB,kBAAA;EACf,EAAA;EACA,MAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;IAAW,OAAA;IAAkB,SAAA;IAAoB,MAAA;EAAA;EACjD,IAAA,GAAO,MAAM;EADF;;;;;EAOX,IAAA;EAMA;;AAAO;AAUT;;EAVE,OAAA;AAAA;;;;;AAW2B;AAU7B;;cAXa,oBAAA,SAA6B,KAAK;cACjC,OAAA;AAAA;;;;;cAUD,YAAA,SAAqB,KAAA;EAAA,SACvB,MAAA;EAAA,SACA,MAAA,EAAQ,kBAAA;cAEL,MAAA,UAAgB,MAAA,EAAQ,kBAAA,IAAsB,OAAA;EAO1D,SAAA,CAAU,MAAA;EAIV,KAAA;EAIA,KAAA;EAIA,YAAA;EAIA,cAAA;EAIA,WAAA;EAIA,UAAA;EAIA,eAAA;EAIA,UAAA;EAIA,sBAAA;EAIA,eAAA;EAxBA;EA6BA,iBAAA;EAIA,aAAA;EArBA;;;;;EA8BA,MAAA,IAAU,MAAA,SAAe,kBAAA;AAAA;;;;;;;;UClFjB,eAAA;EACR,IAAA;EACA,EAAA;EACA,GAAA;EACA,IAAA;IAAS,KAAA,EAAO,MAAA;EAAA,IAA4B,MAAM;AAAA;;UAInC,oBAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAe;AAAA;ADNZ;AAAA,UCUZ,aAAA;EACf,IAAA;IACE,IAAA;IACA,EAAA;IACA,UAAA,GAAa,MAAA;IACb,aAAA,GAAgB,MAAA,SAAe,oBAAA;EAAA;AAAA;;UAKlB,iBAAA;EDViB;;;;;ECgBhC,EAAE;AAAA;;;;;;;;;;;;;;;iBAiBY,UAAA,CACd,UAAA,EAAY,aAAA,EACZ,IAAA,UACA,KAAA,EAAO,MAAA,mBACP,IAAA,GAAO,iBAAA,GACN,aAAA;;;;;;AD+B0C;;;;AClGmB;;;iBAmHhD,sBAAA,CACd,IAAA,WACA,WAAA,mBACC,oBAAoB;;;;;;;;;AAlG6B;AAIpD;;;;;;;;AACyC;iBAwLzB,YAAA,CAAa,UAAA,EAAY,aAAa,EAAE,IAAA,UAAc,OAAA;;;;;;;;;;;;;;;;;AA/Kf;iBA+PvC,wBAAA,CAAyB,GAAA,UAAa,QAAA,WAAmB,OAAA;;;;AApPrE;AAiBJ;;iBAqPgB,iBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,IAAA,WACC,YAAA;;;;;;;;iBAWa,6BAAA,CACd,KAAA,EAAO,YAAA,EACP,GAAA,UACA,QAAA,YACC,YAAY;;;;;;;;AAnQC;AAgDhB;iBAgOgB,uBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,SAAA,GAAY,OAAA,kCACX,YAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/serialize-write.ts"],"mappings":";;;;;;AAOA;;;;UAAiB,kBAAA;EACf,EAAA;EACA,MAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;EACA,MAAA;EACA,MAAA;IAAW,OAAA;IAAkB,SAAA;IAAoB,MAAA;EAAA;EACjD,IAAA,GAAO,MAAM;EAAN;;;;AAYA;EANP,IAAA;EAgBgC;;;;;EAVhC,OAAA;AAAA;AAW2B;AAa7B;;;;;;AAb6B,cADhB,oBAAA,SAA6B,KAAK;cACjC,OAAA;AAAA;;;;;;;;cAaD,YAAA,oCAAgD,KAAA;EAAA,SAClD,MAAA;EAAA,SACA,MAAA,EAAQ,kBAAA,CAAmB,CAAA;cAExB,MAAA,UAAgB,MAAA,EAAQ,kBAAA,CAAmB,CAAA,KAAM,OAAA;EAO7D,SAAA,CAAU,MAAA;EAIV,KAAA;EAIA,KAAA;EAIA,YAAA;EAIA,cAAA;EAIA,WAAA;EAIA,UAAA;EAIA,eAAA;EAIA,UAAA;EAIA,sBAAA;EAIA,eAAA;EApBA;EAyBA,iBAAA;EAIA,aAAA;EAjBA;;;;;EA0BA,MAAA,IAAU,MAAA,SAAe,kBAAA,CAAmB,CAAA;AAAA;;;;AAAC;AAgB/C;;iBAAgB,YAAA,CAAa,GAAA,WAAc,IAAA,WAAe,GAAA,IAAO,YAAY;;;;;;KASjE,cAAA,sBAAoC,GAAA,WAAc,IAAA,EAAM,CAAA,KAAM,GAAA,IAAO,YAAA,CAAa,CAAA;;;;;;;;UCpHpF,eAAA;EACR,IAAA;EACA,EAAA;EACA,GAAA;EACA,IAAA;IAAS,KAAA,EAAO,MAAA;EAAA,IAA4B,MAAM;AAAA;;UAInC,oBAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAe;AAAA;;UAIxB,aAAA;EACf,IAAA;IACE,IAAA;IACA,EAAA;IACA,UAAA,GAAa,MAAA;IACb,aAAA,GAAgB,MAAA,SAAe,oBAAA;EAAA;AAAA;;UAKlB,iBAAA;EDoEU;;;;;EC9DzB,EAAE;AAAA;;;;;;;;;;;;;;;iBAiBY,UAAA,CACd,UAAA,EAAY,aAAA,EACZ,IAAA,UACA,KAAA,EAAO,MAAA,mBACP,IAAA,GAAO,iBAAA,GACN,aAAA;;;;;;;;;;;;;iBAgDa,sBAAA,CACd,IAAA,WACA,WAAA,mBACC,oBAAoB;;ADXwB;AAgB/C;;;;;;;;;AAA6E;AAS7E;;;;;;iBC6EgB,YAAA,CAAa,UAAA,EAAY,aAAa,EAAE,IAAA,UAAc,OAAA;;;;;;;;;;AD7EyB;;;;ACpI/B;;;;iBAiShD,wBAAA,CAAyB,GAAA,UAAa,QAAA,WAAmB,OAAA;;;;;;;iBAkBzD,iBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,IAAA,WACC,YAAA;AAnSiD;AAIpD;;;;;;AAJoD,iBA8SpC,6BAAA,CACd,KAAA,EAAO,YAAA,EACP,GAAA,UACA,QAAA,YACC,YAAY;;AA7S0B;AAIzC;;;;;;;iBAsTgB,uBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,SAAA,GAAY,OAAA,kCACX,YAAA"}
package/dist/index.d.mts CHANGED
@@ -1,11 +1,17 @@
1
- import { $ as SortQuery, A as DefaultActionTypes, At as RelationView, B as IncludePath, Bt as AtomicDescriptor, C as fetchTransport, Ct as mediaType, D as Collection, Dt as EdgeEnvelope, E as Client, Et as Edge, F as FieldsMap, Ft as ActionDescriptor, G as ReadResult, Gt as RelationDescriptor, H as LinkageRef, Ht as ClientIdPolicy, I as FilterKey, It as ActionInput, J as RelationshipAccessor, K as RelationName, Kt as RelationMutations, L as FilterQuery, Lt as ActionOutput, M as DefaultWriteAttributes, Mt as ResourceLinks, N as EdgeMembers, Nt as materialise, O as CountToken, Ot as MaterialiseContext, P as FieldSelectionMap, Pt as relatedPaginatorKind, Q as SingleReadQuery, R as HydratedMember, Rt as ActionScope, S as TransportResponse, St as ResourceIdentifier, T as AtomicResultOf, Tt as DocumentEnvelope, U as MemberName, Ut as CountableDescriptor, V as IncludedRelations, Vt as Cardinality, W as PivotInput, Wt as PaginatorKind, X as ResourceHandle, Y as ResourceAccessors, Z as ResourceObjectView, _ as HANDLE_RESERVED, _t as ATOMIC_EXT, a as Validator, at as WriteOptions, b as JsonApiTransport, bt as LocalIdentifier, c as resolveValidator, ct as AtomicDeleteHandle, d as JsonApiContext, dt as AtomicRef, et as SortToken, f as JsonApiRequest, ft as AtomicResult, g as ClientOptions, gt as runAtomic, h as serializeQuery, ht as AtomicUpdateInput, i as ValidationOption, it as UpdateInput, j as DefaultAttributes, jt as ResourceEnvelope, k as CreateInput, kt as Page, l as validateDocument, lt as AtomicHandle, m as execute, mt as AtomicUpdateHandle, n as SchemaMap, nt as TypeName, o as WireResource, ot as AtomicCreateHandle, p as ReadQuery, pt as AtomicResults, q as RelationReadQuery, qt as ResourceDescriptor, r as ValidationConfig, rt as TypedReadQuery, s as assertJsonApiDocument, st as AtomicCreateInput, t as ResolvedValidator, tt as TypeAccessor, u as Document, ut as AtomicRecorder, v as HeadersInit, vt as ATOMIC_MEDIA_TYPE, w as ActionsAccessor, wt as ArrayEnvelope, x as TransportRequest, xt as MediaTypeParams, y as createClient, yt as JSON_API_MEDIA_TYPE, z as IdentifierMember, zt as ApiDescriptor } from "./validate-BmyPbJCK.mjs";
1
+ import { $ as ResourceAccessors, $t as ActionInput, A as DefaultActionTypes, At as Edge, B as IdentifierMember, Bt as CANONICAL_PAGE_KEYS, C as fetchTransport, Ct as JSON_API_MEDIA_TYPE, D as Collection, Dt as mediaType, E as Client, Et as ResourceIdentifier, F as FieldSelectionMap, Ft as ResourceEnvelope, G as MemberName, Gt as PageMeta, H as IncludedRelations, Ht as Page, I as FieldsMap, It as ResourceLinks, J as RelationName, Jt as PageParamsOf, K as PivotInput, Kt as PageOf, L as FilterKey, Lt as materialise, M as DefaultWriteAttributes, Mt as MaterialiseContext, N as EdgeMembers, Nt as NavigateOptions, O as CountToken, Ot as ArrayEnvelope, P as ErrorCodeOf, Pt as RelationView, Q as RelationshipAccessor, Qt as ActionDescriptor, R as FilterQuery, Rt as relatedPaginator, S as TransportResponse, St as ATOMIC_MEDIA_TYPE, T as AtomicResultOf, Tt as MediaTypeParams, U as LinkageRef, Ut as PageKeys, V as IncludePath, Vt as ExactPageParams, W as ListPageParams, Wt as PageLinks, X as RelationPaginator, Xt as TypedPage, Y as RelationPageParams, Yt as ResolvedPaginator, Z as RelationReadQuery, Zt as resolvePaginator, _ as HANDLE_RESERVED, _t as AtomicResults, a as Validator, an as ClientIdPolicy, at as TypeAccessor, b as JsonApiTransport, bt as runAtomic, c as resolveValidator, cn as PaginatorDescriptor, ct as UpdateInput, d as JsonApiContext, dn as PaginatorStrategy, dt as AtomicCreateInput, en as ActionOutput, et as ResourceHandle, f as JsonApiRequest, fn as RelationDescriptor, ft as AtomicDeleteHandle, g as ClientOptions, gt as AtomicResult, h as serializeQuery, hn as StrategyDescriptor, ht as AtomicRef, i as ValidationOption, in as Cardinality, it as SortToken, j as DefaultAttributes, jt as EdgeEnvelope, k as CreateInput, kt as DocumentEnvelope, l as validateDocument, ln as PaginatorKind, lt as WriteOptions, m as execute, mn as ResourceDescriptor, mt as AtomicRecorder, n as SchemaMap, nn as ApiDescriptor, nt as SingleReadQuery, o as WireResource, on as CountableDescriptor, ot as TypeName, p as ReadQuery, pn as RelationMutations, pt as AtomicHandle, q as ReadResult, qt as PageParams, r as ValidationConfig, rn as AtomicDescriptor, rt as SortQuery, s as assertJsonApiDocument, sn as MenuDescriptor, st as TypedReadQuery, t as ResolvedValidator, tn as ActionScope, tt as ResourceObjectView, u as Document, un as PaginatorRole, ut as AtomicCreateHandle, v as HeadersInit, vt as AtomicUpdateHandle, w as ActionsAccessor, wt as LocalIdentifier, x as TransportRequest, xt as ATOMIC_EXT, y as createClient, yt as AtomicUpdateInput, z as HydratedMember, zt as relatedPaginatorKind } from "./validate-DgCUbzgT.mjs";
2
2
 
3
3
  //#region src/errors.d.ts
4
- /** A single JSON:API error object (spec: error objects). */
5
- interface JsonApiErrorObject {
4
+ /**
5
+ * A single JSON:API error object (spec: error objects).
6
+ *
7
+ * `C` is the server's documented error-code union (a generated client's `ErrorCode`). `code` is
8
+ * typed `C | (string & {})`: editors suggest the documented codes, yet any other string still
9
+ * fits, because the catalogue is open and a server may send a code it never documented.
10
+ */
11
+ interface JsonApiErrorObject<C extends string = string> {
6
12
  id?: string;
7
13
  status?: string;
8
- code?: string;
14
+ code?: C | (string & {});
9
15
  title?: string;
10
16
  detail?: string;
11
17
  source?: {
@@ -40,11 +46,14 @@ declare class StructuralGuardError extends Error {
40
46
  /**
41
47
  * Thrown for any non-2xx JSON:API response. Carries the parsed error document plus
42
48
  * expressive status matchers and pointer-grouping helpers.
49
+ *
50
+ * `C` types each error object's `code` (see {@link JsonApiErrorObject}). It is a compile-time
51
+ * hint only: the runtime never checks a code against it.
43
52
  */
44
- declare class JsonApiError extends Error {
53
+ declare class JsonApiError<C extends string = string> extends Error {
45
54
  readonly status: number;
46
- readonly errors: JsonApiErrorObject[];
47
- constructor(status: number, errors: JsonApiErrorObject[], message?: string);
55
+ readonly errors: JsonApiErrorObject<C>[];
56
+ constructor(status: number, errors: JsonApiErrorObject<C>[], message?: string);
48
57
  hasStatus(status: number): boolean;
49
58
  is4xx(): boolean;
50
59
  is5xx(): boolean;
@@ -64,8 +73,21 @@ declare class JsonApiError extends Error {
64
73
  * query parameter). The payoff for form/validation UX — 422 `source.pointer`s are
65
74
  * remapped to the flat shape the caller actually supplied.
66
75
  */
67
- byPath(): Record<string, JsonApiErrorObject[]>;
76
+ byPath(): Record<string, JsonApiErrorObject<C>[]>;
68
77
  }
78
+ /**
79
+ * True when `err` is a {@link JsonApiError} and any of its error objects carries `code`. Takes
80
+ * any string, so it also matches codes the server never documented. A generated client exports a
81
+ * `hasErrorCode` bound to its server's `ErrorCode` union, which rejects a misspelt code at
82
+ * compile time; reach for this one only to match an undocumented code.
83
+ */
84
+ declare function hasErrorCode(err: unknown, code: string): err is JsonApiError;
85
+ /**
86
+ * {@link hasErrorCode} restricted to one server's documented codes. A generated client binds it:
87
+ * `export const hasErrorCode = hasErrorCodeRuntime as ErrorCodeGuard<ErrorCode>`. The cast is
88
+ * needed because `JsonApiError<string>` doesn't assign to `JsonApiError<ErrorCode>`.
89
+ */
90
+ type ErrorCodeGuard<C extends string> = (err: unknown, code: C) => err is JsonApiError<C>;
69
91
  //#endregion
70
92
  //#region src/serialize-write.d.ts
71
93
  /**
@@ -194,5 +216,5 @@ declare function withRemappedRelationshipPaths(error: JsonApiError, rel: string,
194
216
  */
195
217
  declare function withRemappedAtomicPaths(error: JsonApiError, descriptor: ApiDescriptor, typeForOp: (opIndex: number) => string | undefined): JsonApiError;
196
218
  //#endregion
197
- export { ATOMIC_EXT, ATOMIC_MEDIA_TYPE, ActionDescriptor, ActionInput, ActionOutput, ActionScope, ActionsAccessor, ApiDescriptor, ArrayEnvelope, AtomicCreateHandle, AtomicCreateInput, AtomicDeleteHandle, AtomicDescriptor, AtomicHandle, AtomicRecorder, AtomicRef, AtomicResult, AtomicResultOf, AtomicResults, AtomicUpdateHandle, AtomicUpdateInput, Cardinality, Client, ClientIdPolicy, ClientOptions, Collection, CountToken, CountableDescriptor, CreateInput, DefaultActionTypes, DefaultAttributes, DefaultWriteAttributes, Document, DocumentEnvelope, Edge, EdgeEnvelope, EdgeMembers, FieldSelectionMap, FieldsMap, FilterKey, FilterQuery, HANDLE_RESERVED, HeadersInit, HydratedMember, IdentifierMember, IncludePath, IncludedRelations, JSON_API_MEDIA_TYPE, JsonApiContext, JsonApiError, JsonApiErrorObject, JsonApiRequest, JsonApiTransport, LinkageRef, LocalIdentifier, MaterialiseContext, MediaTypeParams, MemberName, Page, PaginatorKind, PivotInput, ReadQuery, ReadResult, RelationDescriptor, RelationMutations, RelationName, RelationReadQuery, RelationView, RelationshipAccessor, RelationshipDocument, ResolvedValidator, ResourceAccessors, ResourceDescriptor, ResourceEnvelope, ResourceHandle, ResourceIdentifier, ResourceLinks, ResourceObjectView, SchemaMap, SingleReadQuery, SortQuery, SortToken, StructuralGuardError, ToDocumentOptions, TransportRequest, TransportResponse, TypeAccessor, TypeName, TypedReadQuery, UpdateInput, ValidationConfig, ValidationOption, Validator, WireResource, WriteDocument, WriteOptions, assertJsonApiDocument, createClient, execute, fetchTransport, materialise, mediaType, relatedPaginatorKind, remapPointer, remapRelationshipPointer, resolveValidator, runAtomic, serializeQuery, toDocument, toRelationshipDocument, validateDocument, withRemappedAtomicPaths, withRemappedPaths, withRemappedRelationshipPaths };
219
+ export { ATOMIC_EXT, ATOMIC_MEDIA_TYPE, ActionDescriptor, ActionInput, ActionOutput, ActionScope, ActionsAccessor, ApiDescriptor, ArrayEnvelope, AtomicCreateHandle, AtomicCreateInput, AtomicDeleteHandle, AtomicDescriptor, AtomicHandle, AtomicRecorder, AtomicRef, AtomicResult, AtomicResultOf, AtomicResults, AtomicUpdateHandle, AtomicUpdateInput, CANONICAL_PAGE_KEYS, Cardinality, Client, ClientIdPolicy, ClientOptions, Collection, CountToken, CountableDescriptor, CreateInput, DefaultActionTypes, DefaultAttributes, DefaultWriteAttributes, Document, DocumentEnvelope, Edge, EdgeEnvelope, EdgeMembers, ErrorCodeGuard, ErrorCodeOf, ExactPageParams, FieldSelectionMap, FieldsMap, FilterKey, FilterQuery, HANDLE_RESERVED, HeadersInit, HydratedMember, IdentifierMember, IncludePath, IncludedRelations, JSON_API_MEDIA_TYPE, JsonApiContext, JsonApiError, JsonApiErrorObject, JsonApiRequest, JsonApiTransport, LinkageRef, ListPageParams, LocalIdentifier, MaterialiseContext, MediaTypeParams, MemberName, MenuDescriptor, NavigateOptions, Page, PageKeys, PageLinks, PageMeta, PageOf, PageParams, PageParamsOf, PaginatorDescriptor, PaginatorKind, PaginatorRole, PaginatorStrategy, PivotInput, ReadQuery, ReadResult, RelationDescriptor, RelationMutations, RelationName, RelationPageParams, RelationPaginator, RelationReadQuery, RelationView, RelationshipAccessor, RelationshipDocument, ResolvedPaginator, ResolvedValidator, ResourceAccessors, ResourceDescriptor, ResourceEnvelope, ResourceHandle, ResourceIdentifier, ResourceLinks, ResourceObjectView, SchemaMap, SingleReadQuery, SortQuery, SortToken, StrategyDescriptor, StructuralGuardError, ToDocumentOptions, TransportRequest, TransportResponse, TypeAccessor, TypeName, TypedPage, TypedReadQuery, UpdateInput, ValidationConfig, ValidationOption, Validator, WireResource, WriteDocument, WriteOptions, assertJsonApiDocument, createClient, execute, fetchTransport, hasErrorCode, materialise, mediaType, relatedPaginator, relatedPaginatorKind, remapPointer, remapRelationshipPointer, resolvePaginator, resolveValidator, runAtomic, serializeQuery, toDocument, toRelationshipDocument, validateDocument, withRemappedAtomicPaths, withRemappedPaths, withRemappedRelationshipPaths };
198
220
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/serialize-write.ts"],"mappings":";;;;UACiB,kBAAA;EACf,EAAA;EACA,MAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;EACA,MAAA;IAAW,OAAA;IAAkB,SAAA;IAAoB,MAAA;EAAA;EACjD,IAAA,GAAO,MAAM;EADF;;;;;EAOX,IAAA;EAMA;;AAAO;AAUT;;EAVE,OAAA;AAAA;;;;;AAW2B;AAU7B;;cAXa,oBAAA,SAA6B,KAAK;cACjC,OAAA;AAAA;;;;;cAUD,YAAA,SAAqB,KAAA;EAAA,SACvB,MAAA;EAAA,SACA,MAAA,EAAQ,kBAAA;cAEL,MAAA,UAAgB,MAAA,EAAQ,kBAAA,IAAsB,OAAA;EAO1D,SAAA,CAAU,MAAA;EAIV,KAAA;EAIA,KAAA;EAIA,YAAA;EAIA,cAAA;EAIA,WAAA;EAIA,UAAA;EAIA,eAAA;EAIA,UAAA;EAIA,sBAAA;EAIA,eAAA;EAxBA;EA6BA,iBAAA;EAIA,aAAA;EArBA;;;;;EA8BA,MAAA,IAAU,MAAA,SAAe,kBAAA;AAAA;;;;;;;;UClFjB,eAAA;EACR,IAAA;EACA,EAAA;EACA,GAAA;EACA,IAAA;IAAS,KAAA,EAAO,MAAA;EAAA,IAA4B,MAAM;AAAA;;UAInC,oBAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAe;AAAA;ADNZ;AAAA,UCUZ,aAAA;EACf,IAAA;IACE,IAAA;IACA,EAAA;IACA,UAAA,GAAa,MAAA;IACb,aAAA,GAAgB,MAAA,SAAe,oBAAA;EAAA;AAAA;;UAKlB,iBAAA;EDViB;;;;;ECgBhC,EAAE;AAAA;;;;;;;;;;;;;;;iBAiBY,UAAA,CACd,UAAA,EAAY,aAAA,EACZ,IAAA,UACA,KAAA,EAAO,MAAA,mBACP,IAAA,GAAO,iBAAA,GACN,aAAA;;;;;;AD+B0C;;;;AClGmB;;;iBAmHhD,sBAAA,CACd,IAAA,WACA,WAAA,mBACC,oBAAoB;;;;;;;;;AAlG6B;AAIpD;;;;;;;;AACyC;iBAwLzB,YAAA,CAAa,UAAA,EAAY,aAAa,EAAE,IAAA,UAAc,OAAA;;;;;;;;;;;;;;;;;AA/Kf;iBA+PvC,wBAAA,CAAyB,GAAA,UAAa,QAAA,WAAmB,OAAA;;;;AApPrE;AAiBJ;;iBAqPgB,iBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,IAAA,WACC,YAAA;;;;;;;;iBAWa,6BAAA,CACd,KAAA,EAAO,YAAA,EACP,GAAA,UACA,QAAA,YACC,YAAY;;;;;;;;AAnQC;AAgDhB;iBAgOgB,uBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,SAAA,GAAY,OAAA,kCACX,YAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/serialize-write.ts"],"mappings":";;;;;;AAOA;;;;UAAiB,kBAAA;EACf,EAAA;EACA,MAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;EACA,MAAA;EACA,MAAA;IAAW,OAAA;IAAkB,SAAA;IAAoB,MAAA;EAAA;EACjD,IAAA,GAAO,MAAM;EAAN;;;;AAYA;EANP,IAAA;EAgBgC;;;;;EAVhC,OAAA;AAAA;AAW2B;AAa7B;;;;;;AAb6B,cADhB,oBAAA,SAA6B,KAAK;cACjC,OAAA;AAAA;;;;;;;;cAaD,YAAA,oCAAgD,KAAA;EAAA,SAClD,MAAA;EAAA,SACA,MAAA,EAAQ,kBAAA,CAAmB,CAAA;cAExB,MAAA,UAAgB,MAAA,EAAQ,kBAAA,CAAmB,CAAA,KAAM,OAAA;EAO7D,SAAA,CAAU,MAAA;EAIV,KAAA;EAIA,KAAA;EAIA,YAAA;EAIA,cAAA;EAIA,WAAA;EAIA,UAAA;EAIA,eAAA;EAIA,UAAA;EAIA,sBAAA;EAIA,eAAA;EApBA;EAyBA,iBAAA;EAIA,aAAA;EAjBA;;;;;EA0BA,MAAA,IAAU,MAAA,SAAe,kBAAA,CAAmB,CAAA;AAAA;;;;AAAC;AAgB/C;;iBAAgB,YAAA,CAAa,GAAA,WAAc,IAAA,WAAe,GAAA,IAAO,YAAY;;;;;;KASjE,cAAA,sBAAoC,GAAA,WAAc,IAAA,EAAM,CAAA,KAAM,GAAA,IAAO,YAAA,CAAa,CAAA;;;;;;;;UCpHpF,eAAA;EACR,IAAA;EACA,EAAA;EACA,GAAA;EACA,IAAA;IAAS,KAAA,EAAO,MAAA;EAAA,IAA4B,MAAM;AAAA;;UAInC,oBAAA;EACf,IAAA,EAAM,eAAA,GAAkB,eAAe;AAAA;;UAIxB,aAAA;EACf,IAAA;IACE,IAAA;IACA,EAAA;IACA,UAAA,GAAa,MAAA;IACb,aAAA,GAAgB,MAAA,SAAe,oBAAA;EAAA;AAAA;;UAKlB,iBAAA;EDoEU;;;;;EC9DzB,EAAE;AAAA;;;;;;;;;;;;;;;iBAiBY,UAAA,CACd,UAAA,EAAY,aAAA,EACZ,IAAA,UACA,KAAA,EAAO,MAAA,mBACP,IAAA,GAAO,iBAAA,GACN,aAAA;;;;;;;;;;;;;iBAgDa,sBAAA,CACd,IAAA,WACA,WAAA,mBACC,oBAAoB;;ADXwB;AAgB/C;;;;;;;;;AAA6E;AAS7E;;;;;;iBC6EgB,YAAA,CAAa,UAAA,EAAY,aAAa,EAAE,IAAA,UAAc,OAAA;;;;;;;;;;AD7EyB;;;;ACpI/B;;;;iBAiShD,wBAAA,CAAyB,GAAA,UAAa,QAAA,WAAmB,OAAA;;;;;;;iBAkBzD,iBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,IAAA,WACC,YAAA;AAnSiD;AAIpD;;;;;;AAJoD,iBA8SpC,6BAAA,CACd,KAAA,EAAO,YAAA,EACP,GAAA,UACA,QAAA,YACC,YAAY;;AA7S0B;AAIzC;;;;;;;iBAsTgB,uBAAA,CACd,KAAA,EAAO,YAAA,EACP,UAAA,EAAY,aAAA,EACZ,SAAA,GAAY,OAAA,kCACX,YAAA"}