@zeroxsolutions/response 0.14.5 → 0.14.7

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/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.14.7 (2026-10-21)
2
+
3
+ ### 🚀 Features
4
+
5
+ - **response:** let an upstream answer state its own source ([fdc8078](https://github.com/zeroxsolutions/zeroxsolutions/commit/fdc8078))
6
+
7
+ ### ❤️ Thank You
8
+
9
+ - Lương Văn Tú
10
+
11
+ ## 0.14.6 (2026-10-21)
12
+
13
+ ### 🚀 Features
14
+
15
+ - **response:** type a resource's data.id through a declared id schema ([3dd4f2c](https://github.com/zeroxsolutions/zeroxsolutions/commit/3dd4f2c))
16
+
17
+ ### ❤️ Thank You
18
+
19
+ - luongvantuit
20
+
1
21
  ## 0.14.5 (2026-10-19)
2
22
 
3
23
  ### 🚀 Features
@@ -69,31 +89,31 @@
69
89
  ### 🚀 Features
70
90
 
71
91
  - **response:** answer a created resource with its location ([e9c0086](https://github.com/zeroxsolutions/zeroxsolutions/commit/e9c0086))
72
- - ⚠️ **response:** refuse a declaration the standard's field rules forbid ([30e6b77](https://github.com/zeroxsolutions/zeroxsolutions/commit/30e6b77))
92
+ - ⚠️ **response:** refuse a declaration the standard's field rules forbid ([30e6b77](https://github.com/zeroxsolutions/zeroxsolutions/commit/30e6b77))
73
93
 
74
94
  ### 🩹 Fixes
75
95
 
76
- - ⚠️ **response:** walk a pipe's input when checking member names ([0949d22](https://github.com/zeroxsolutions/zeroxsolutions/commit/0949d22))
96
+ - ⚠️ **response:** walk a pipe's input when checking member names ([0949d22](https://github.com/zeroxsolutions/zeroxsolutions/commit/0949d22))
77
97
  - **response:** match link types to their schemas ([0f7c79b](https://github.com/zeroxsolutions/zeroxsolutions/commit/0f7c79b))
78
- - ⚠️ **response:** refuse a resource id that is not a string ([57f60ab](https://github.com/zeroxsolutions/zeroxsolutions/commit/57f60ab))
98
+ - ⚠️ **response:** refuse a resource id that is not a string ([57f60ab](https://github.com/zeroxsolutions/zeroxsolutions/commit/57f60ab))
79
99
  - **response:** keep a primary resource out of included ([c38859f](https://github.com/zeroxsolutions/zeroxsolutions/commit/c38859f))
80
- - ⚠️ **response:** read only the document members the standard defines ([fc5c51a](https://github.com/zeroxsolutions/zeroxsolutions/commit/fc5c51a))
81
- - ⚠️ **response:** refuse an error object that carries no member ([7d888ed](https://github.com/zeroxsolutions/zeroxsolutions/commit/7d888ed))
100
+ - ⚠️ **response:** read only the document members the standard defines ([fc5c51a](https://github.com/zeroxsolutions/zeroxsolutions/commit/fc5c51a))
101
+ - ⚠️ **response:** refuse an error object that carries no member ([7d888ed](https://github.com/zeroxsolutions/zeroxsolutions/commit/7d888ed))
82
102
 
83
- ### ⚠️ Breaking Changes
103
+ ### ⚠️ Breaking Changes
84
104
 
85
- - **response:** walk a pipe's input when checking member names ([0949d22](https://github.com/zeroxsolutions/zeroxsolutions/commit/0949d22))
105
+ - **response:** walk a pipe's input when checking member names ([0949d22](https://github.com/zeroxsolutions/zeroxsolutions/commit/0949d22))
86
106
  a nested attribute member name that breaks the
87
107
  standard's member-name rule, and sits behind a .transform() or
88
108
  .pipe(), now throws at jsonApiResource's own declaration where it
89
109
  previously passed unchecked.
90
- - **response:** refuse a declaration the standard's field rules forbid ([30e6b77](https://github.com/zeroxsolutions/zeroxsolutions/commit/30e6b77))
110
+ - **response:** refuse a declaration the standard's field rules forbid ([30e6b77](https://github.com/zeroxsolutions/zeroxsolutions/commit/30e6b77))
91
111
  jsonApiResource throws, and fails to compile, on a field named type or id, a name shared by an attribute and a relationship, an illegal member name, or a foreign-key attribute beside its relationship.
92
- - **response:** refuse a resource id that is not a string ([57f60ab](https://github.com/zeroxsolutions/zeroxsolutions/commit/57f60ab))
112
+ - **response:** refuse a resource id that is not a string ([57f60ab](https://github.com/zeroxsolutions/zeroxsolutions/commit/57f60ab))
93
113
  Row['id'] is typed string, and serializing a row, embedded row or foreign key whose id is not a string throws TypeError.
94
- - **response:** read only the document members the standard defines ([fc5c51a](https://github.com/zeroxsolutions/zeroxsolutions/commit/fc5c51a))
114
+ - **response:** read only the document members the standard defines ([fc5c51a](https://github.com/zeroxsolutions/zeroxsolutions/commit/fc5c51a))
95
115
  a data document carrying errors, an error document carrying data, and an empty relationship object are refused.
96
- - **response:** refuse an error object that carries no member ([7d888ed](https://github.com/zeroxsolutions/zeroxsolutions/commit/7d888ed))
116
+ - **response:** refuse an error object that carries no member ([7d888ed](https://github.com/zeroxsolutions/zeroxsolutions/commit/7d888ed))
97
117
  toErrorDocument throws on an empty error object.
98
118
 
99
119
  ### ❤️ Thank You
@@ -105,28 +125,28 @@
105
125
 
106
126
  ### 🚀 Features
107
127
 
108
- - ⚠️ **response:** type the fieldsets and include paths a document answers ([98bbb58](https://github.com/zeroxsolutions/zeroxsolutions/commit/98bbb58))
109
- - ⚠️ **response:** keep a resource's type, attributes and relationships as literals ([738889e](https://github.com/zeroxsolutions/zeroxsolutions/commit/738889e))
128
+ - ⚠️ **response:** type the fieldsets and include paths a document answers ([98bbb58](https://github.com/zeroxsolutions/zeroxsolutions/commit/98bbb58))
129
+ - ⚠️ **response:** keep a resource's type, attributes and relationships as literals ([738889e](https://github.com/zeroxsolutions/zeroxsolutions/commit/738889e))
110
130
 
111
131
  ### 🩹 Fixes
112
132
 
113
- - ⚠️ **response:** pin an include path stopping at a wide edge ([515a3e9](https://github.com/zeroxsolutions/zeroxsolutions/commit/515a3e9))
133
+ - ⚠️ **response:** pin an include path stopping at a wide edge ([515a3e9](https://github.com/zeroxsolutions/zeroxsolutions/commit/515a3e9))
114
134
 
115
- ### ⚠️ Breaking Changes
135
+ ### ⚠️ Breaking Changes
116
136
 
117
- - **response:** pin an include path stopping at a wide edge ([515a3e9](https://github.com/zeroxsolutions/zeroxsolutions/commit/515a3e9))
137
+ - **response:** pin an include path stopping at a wide edge ([515a3e9](https://github.com/zeroxsolutions/zeroxsolutions/commit/515a3e9))
118
138
  jsonApiResource's type parameters moved from <A, C> to
119
139
  <T, A, R, C>, so an explicit `jsonApiResource<typeof attrs, Ctx>` no
120
140
  longer compiles; remove the type arguments and let inference type it.
121
141
  The exported ResourceOptions<C> is now ResourceOptions<R>.
122
142
  BREAKING CHANGE: an explicit toOne<Ctx> or toMany<Ctx> no longer
123
143
  compiles; remove the type argument.
124
- - **response:** type the fieldsets and include paths a document answers ([98bbb58](https://github.com/zeroxsolutions/zeroxsolutions/commit/98bbb58))
144
+ - **response:** type the fieldsets and include paths a document answers ([98bbb58](https://github.com/zeroxsolutions/zeroxsolutions/commit/98bbb58))
125
145
  declaredDocumentShape answers typed fieldsets and include
126
146
  paths, walks at most three relationships by default, and answers a fieldset
127
147
  only for a type a kept path reaches. DeclaredDocumentShape is removed;
128
148
  TypedDocumentShape replaces it.
129
- - **response:** keep a resource's type, attributes and relationships as literals ([738889e](https://github.com/zeroxsolutions/zeroxsolutions/commit/738889e))
149
+ - **response:** keep a resource's type, attributes and relationships as literals ([738889e](https://github.com/zeroxsolutions/zeroxsolutions/commit/738889e))
130
150
  toOne and toMany take the related resource as their first type
131
151
  parameter and infer the loader context; a call passing the context explicitly,
132
152
  toOne<Ctx>(...), no longer compiles and drops the explicit argument.
@@ -164,13 +184,13 @@
164
184
 
165
185
  ### 💅 Refactors
166
186
 
167
- - ⚠️ **response:** list the names the package root publishes ([7b8a95d](https://github.com/zeroxsolutions/zeroxsolutions/commit/7b8a95d))
168
- - ⚠️ **response:** answer mapped errors with links and meta ([b78bc08](https://github.com/zeroxsolutions/zeroxsolutions/commit/b78bc08))
169
- - ⚠️ **response:** render every member of a JSON:API error object ([ca0c551](https://github.com/zeroxsolutions/zeroxsolutions/commit/ca0c551))
187
+ - ⚠️ **response:** list the names the package root publishes ([7b8a95d](https://github.com/zeroxsolutions/zeroxsolutions/commit/7b8a95d))
188
+ - ⚠️ **response:** answer mapped errors with links and meta ([b78bc08](https://github.com/zeroxsolutions/zeroxsolutions/commit/b78bc08))
189
+ - ⚠️ **response:** render every member of a JSON:API error object ([ca0c551](https://github.com/zeroxsolutions/zeroxsolutions/commit/ca0c551))
170
190
 
171
- ### ⚠️ Breaking Changes
191
+ ### ⚠️ Breaking Changes
172
192
 
173
- - **response:** list the names the package root publishes ([7b8a95d](https://github.com/zeroxsolutions/zeroxsolutions/commit/7b8a95d))
193
+ - **response:** list the names the package root publishes ([7b8a95d](https://github.com/zeroxsolutions/zeroxsolutions/commit/7b8a95d))
174
194
  the root no longer exports `createSerializer`,
175
195
  `serializeResource`, `serializeCollection`, `reachableResources`,
176
196
  `resourceObjectSchema`, `resourceDocumentSchema`,
@@ -180,7 +200,7 @@
180
200
  `errorObjectSchema`. Their inferred types stay listed. A resource's own
181
201
  `document`, `collectionDocument`, `serialize` and `serializeMany` declare
182
202
  and render its documents; the schema consts have no public replacement.
183
- - **response:** answer mapped errors with links and meta ([b78bc08](https://github.com/zeroxsolutions/zeroxsolutions/commit/b78bc08))
203
+ - **response:** answer mapped errors with links and meta ([b78bc08](https://github.com/zeroxsolutions/zeroxsolutions/commit/b78bc08))
184
204
  `ErrorMeta` is `DomainErrorAnswer`, whose `code` is
185
205
  required. `defineErrorMap` takes `DomainErrorEntry` objects, which
186
206
  `errorEntry(type, answer)` builds, in place of `[type, meta]` tuples.
@@ -188,7 +208,7 @@
188
208
  type argument. `UpstreamErrorMeta` is `UpstreamErrorAnswer`, and
189
209
  `toUpstreamError(map, document, fallback)` is
190
210
  `createUpstreamErrorTranslator(map, fallback)(document)`.
191
- - **response:** render every member of a JSON:API error object ([ca0c551](https://github.com/zeroxsolutions/zeroxsolutions/commit/ca0c551))
211
+ - **response:** render every member of a JSON:API error object ([ca0c551](https://github.com/zeroxsolutions/zeroxsolutions/commit/ca0c551))
192
212
  `buildErrorDocument` is `toErrorDocument`, and the
193
213
  document it renders carries `jsonapi: { version: '1.1' }`.
194
214
  `ErrorCodeMeta` is `ErrorStatus`; `ErrorRegistry` and `ErrorLike` are
@@ -236,19 +256,19 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
236
256
 
237
257
  ### 🚀 Features
238
258
 
239
- - ⚠️ **server,jsonapi:** one surface, one error-code vocabulary ([32b4aed](https://github.com/zeroxsolutions/zeroxsolutions/commit/32b4aed))
259
+ - ⚠️ **server,jsonapi:** one surface, one error-code vocabulary ([32b4aed](https://github.com/zeroxsolutions/zeroxsolutions/commit/32b4aed))
240
260
 
241
261
  ### 💅 Refactors
242
262
 
243
- - ⚠️ **query,response:** drop the seams the second spelling paid for ([40f1bca](https://github.com/zeroxsolutions/zeroxsolutions/commit/40f1bca))
263
+ - ⚠️ **query,response:** drop the seams the second spelling paid for ([40f1bca](https://github.com/zeroxsolutions/zeroxsolutions/commit/40f1bca))
244
264
 
245
- ### ⚠️ Breaking Changes
265
+ ### ⚠️ Breaking Changes
246
266
 
247
- - **server,jsonapi:** one surface, one error-code vocabulary ([32b4aed](https://github.com/zeroxsolutions/zeroxsolutions/commit/32b4aed))
267
+ - **server,jsonapi:** one surface, one error-code vocabulary ([32b4aed](https://github.com/zeroxsolutions/zeroxsolutions/commit/32b4aed))
248
268
  createErrorHandler, createValidationHook and
249
269
  jsonApiContentNegotiation take a required `namespace`; negotiateJsonApi takes it
250
270
  as a third argument. Codes these mint are now `<namespace>.<name>`.
251
- - **query,response:** drop the seams the second spelling paid for ([40f1bca](https://github.com/zeroxsolutions/zeroxsolutions/commit/40f1bca))
271
+ - **query,response:** drop the seams the second spelling paid for ([40f1bca](https://github.com/zeroxsolutions/zeroxsolutions/commit/40f1bca))
252
272
  @zeroxsolutions/query no longer exports CollectionQueryParser,
253
273
  CollectionQueryRenderer, collectionLinksWith, collectionQueryParser, parseSort,
254
274
  parseFields, parseInclude or parsePagination. collectionLinks and
@@ -264,11 +284,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
264
284
 
265
285
  ### 💅 Refactors
266
286
 
267
- - ⚠️ **query,response,server:** one wire spelling, flat exports ([5c57b3a](https://github.com/zeroxsolutions/zeroxsolutions/commit/5c57b3a))
287
+ - ⚠️ **query,response,server:** one wire spelling, flat exports ([5c57b3a](https://github.com/zeroxsolutions/zeroxsolutions/commit/5c57b3a))
268
288
 
269
- ### ⚠️ Breaking Changes
289
+ ### ⚠️ Breaking Changes
270
290
 
271
- - **query,response,server:** one wire spelling, flat exports ([5c57b3a](https://github.com/zeroxsolutions/zeroxsolutions/commit/5c57b3a))
291
+ - **query,response,server:** one wire spelling, flat exports ([5c57b3a](https://github.com/zeroxsolutions/zeroxsolutions/commit/5c57b3a))
272
292
  `@zeroxsolutions/response/http`, `@zeroxsolutions/query/http`
273
293
  and `@zeroxsolutions/server/hono/http` are gone, and the surviving `/jsonapi`
274
294
  and `/hono` subpaths move to the package root. Every import drops its subpath.
@@ -281,11 +301,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
281
301
 
282
302
  ### 💅 Refactors
283
303
 
284
- - ⚠️ **response:** key the upstream map by string, drop its builder ([d5c5e6b](https://github.com/zeroxsolutions/zeroxsolutions/commit/d5c5e6b))
304
+ - ⚠️ **response:** key the upstream map by string, drop its builder ([d5c5e6b](https://github.com/zeroxsolutions/zeroxsolutions/commit/d5c5e6b))
285
305
 
286
- ### ⚠️ Breaking Changes
306
+ ### ⚠️ Breaking Changes
287
307
 
288
- - **response:** key the upstream map by string, drop its builder ([d5c5e6b](https://github.com/zeroxsolutions/zeroxsolutions/commit/d5c5e6b))
308
+ - **response:** key the upstream map by string, drop its builder ([d5c5e6b](https://github.com/zeroxsolutions/zeroxsolutions/commit/d5c5e6b))
289
309
  defineUpstreamErrorMap is gone from both spellings. Declare the
290
310
  map as an object literal with `satisfies UpstreamErrorMap<UpstreamErrorMeta>`;
291
311
  toUpstreamError takes it unchanged.
@@ -299,11 +319,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
299
319
 
300
320
  ### 💅 Refactors
301
321
 
302
- - ⚠️ **response:** move the Hono handlers out, translate upstream errors ([ce60636](https://github.com/zeroxsolutions/zeroxsolutions/commit/ce60636))
322
+ - ⚠️ **response:** move the Hono handlers out, translate upstream errors ([ce60636](https://github.com/zeroxsolutions/zeroxsolutions/commit/ce60636))
303
323
 
304
- ### ⚠️ Breaking Changes
324
+ ### ⚠️ Breaking Changes
305
325
 
306
- - **response:** move the Hono handlers out, translate upstream errors ([ce60636](https://github.com/zeroxsolutions/zeroxsolutions/commit/ce60636))
326
+ - **response:** move the Hono handlers out, translate upstream errors ([ce60636](https://github.com/zeroxsolutions/zeroxsolutions/commit/ce60636))
307
327
  the ./http/server and ./jsonapi/server subpaths are gone -
308
328
  createErrorHandler and createValidationHook are @zeroxsolutions/server/http
309
329
  and @zeroxsolutions/server. Both remaining subpaths resolve to
@@ -351,11 +371,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
351
371
 
352
372
  ### 🚀 Features
353
373
 
354
- - ⚠️ **response:** type /jsonapi's documents off the resource's attributes ([1dcf923](https://github.com/zeroxsolutions/zeroxsolutions/commit/1dcf923))
374
+ - ⚠️ **response:** type /jsonapi's documents off the resource's attributes ([1dcf923](https://github.com/zeroxsolutions/zeroxsolutions/commit/1dcf923))
355
375
 
356
- ### ⚠️ Breaking Changes
376
+ ### ⚠️ Breaking Changes
357
377
 
358
- - **response:** type /jsonapi's documents off the resource's attributes ([1dcf923](https://github.com/zeroxsolutions/zeroxsolutions/commit/1dcf923))
378
+ - **response:** type /jsonapi's documents off the resource's attributes ([1dcf923](https://github.com/zeroxsolutions/zeroxsolutions/commit/1dcf923))
359
379
  `serialize` returns `ResourceDocument<A>` and `serializeMany`
360
380
  `CollectionDocument<A>` instead of `Row`, and `okResponse`/`listResponse` are
361
381
  generic in the resource's attribute schema.
@@ -379,11 +399,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
379
399
 
380
400
  ### 🚀 Features
381
401
 
382
- - ⚠️ **response:** bring /jsonapi's server half up to /http's ([a40fed4](https://github.com/zeroxsolutions/zeroxsolutions/commit/a40fed4))
402
+ - ⚠️ **response:** bring /jsonapi's server half up to /http's ([a40fed4](https://github.com/zeroxsolutions/zeroxsolutions/commit/a40fed4))
383
403
 
384
- ### ⚠️ Breaking Changes
404
+ ### ⚠️ Breaking Changes
385
405
 
386
- - **response:** bring /jsonapi's server half up to /http's ([a40fed4](https://github.com/zeroxsolutions/zeroxsolutions/commit/a40fed4))
406
+ - **response:** bring /jsonapi's server half up to /http's ([a40fed4](https://github.com/zeroxsolutions/zeroxsolutions/commit/a40fed4))
387
407
  /jsonapi/server's createErrorHandler now requires `category`.
388
408
 
389
409
  ### ❤️ Thank You
@@ -395,19 +415,19 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
395
415
 
396
416
  ### 🚀 Features
397
417
 
398
- - ⚠️ **response:** declare each JSON:API resource once ([748e006](https://github.com/zeroxsolutions/zeroxsolutions/commit/748e006))
399
- - ⚠️ **db:** let each table declare its own id column ([eca4aca](https://github.com/zeroxsolutions/zeroxsolutions/commit/eca4aca))
418
+ - ⚠️ **response:** declare each JSON:API resource once ([748e006](https://github.com/zeroxsolutions/zeroxsolutions/commit/748e006))
419
+ - ⚠️ **db:** let each table declare its own id column ([eca4aca](https://github.com/zeroxsolutions/zeroxsolutions/commit/eca4aca))
400
420
 
401
- ### ⚠️ Breaking Changes
421
+ ### ⚠️ Breaking Changes
402
422
 
403
- - **response:** declare each JSON:API resource once ([748e006](https://github.com/zeroxsolutions/zeroxsolutions/commit/748e006))
423
+ - **response:** declare each JSON:API resource once ([748e006](https://github.com/zeroxsolutions/zeroxsolutions/commit/748e006))
404
424
  `/jsonapi`'s `okResponse` / `listResponse` take a resource
405
425
  declaration instead of `(type, attributesSchema)`. `resourceDocument`,
406
426
  `resourceCollectionDocument`, `applyFields`, `mergeIncluded`,
407
427
  `documentResources` and `ResourceObject` are removed - the descriptor covers
408
428
  them. `/jsonapi/server` now exports only `createErrorHandler`; the serializer
409
429
  entry points moved behind the descriptor.
410
- - **db:** let each table declare its own id column ([eca4aca](https://github.com/zeroxsolutions/zeroxsolutions/commit/eca4aca))
430
+ - **db:** let each table declare its own id column ([eca4aca](https://github.com/zeroxsolutions/zeroxsolutions/commit/eca4aca))
411
431
  `baseTable` is removed - take `idColumn` and spread
412
432
  `timestamps`. `defaultIndexedBaseColumns` is now `timestampIndexes` and
413
433
  `BaseTableShape` is `TimestampColumns`; both were named for the removed concept.
@@ -421,11 +441,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
421
441
 
422
442
  ### 🚀 Features
423
443
 
424
- - ⚠️ **response:** take the isolate's own logging category, not the library's ([3409798](https://github.com/zeroxsolutions/zeroxsolutions/commit/3409798))
444
+ - ⚠️ **response:** take the isolate's own logging category, not the library's ([3409798](https://github.com/zeroxsolutions/zeroxsolutions/commit/3409798))
425
445
 
426
- ### ⚠️ Breaking Changes
446
+ ### ⚠️ Breaking Changes
427
447
 
428
- - **response:** take the isolate's own logging category, not the library's ([3409798](https://github.com/zeroxsolutions/zeroxsolutions/commit/3409798))
448
+ - **response:** take the isolate's own logging category, not the library's ([3409798](https://github.com/zeroxsolutions/zeroxsolutions/commit/3409798))
429
449
  `createErrorHandler` takes one options object and `category` is
430
450
  required - `createErrorHandler(errors)` becomes
431
451
  `createErrorHandler({ category, errors })`. Required rather than defaulted
@@ -440,11 +460,11 @@ Repackaged only, no source change: the previous tarball still carried the pre-fl
440
460
 
441
461
  ### 🚀 Features
442
462
 
443
- - ⚠️ **response:** write the unhandled 500 through logtape, under the caller's id ([fdcb75b](https://github.com/zeroxsolutions/zeroxsolutions/commit/fdcb75b))
463
+ - ⚠️ **response:** write the unhandled 500 through logtape, under the caller's id ([fdcb75b](https://github.com/zeroxsolutions/zeroxsolutions/commit/fdcb75b))
444
464
 
445
- ### ⚠️ Breaking Changes
465
+ ### ⚠️ Breaking Changes
446
466
 
447
- - **response:** write the unhandled 500 through logtape, under the caller's id ([fdcb75b](https://github.com/zeroxsolutions/zeroxsolutions/commit/fdcb75b))
467
+ - **response:** write the unhandled 500 through logtape, under the caller's id ([fdcb75b](https://github.com/zeroxsolutions/zeroxsolutions/commit/fdcb75b))
448
468
  `@logtape/logtape` is a new peer of `./http/server`, and the
449
469
  unhandled-500 line is silent in an isolate that never calls `configureSync`.
450
470
  It previously always reached stdout.
package/README.md CHANGED
@@ -67,8 +67,8 @@ them, and the serializer calls that loader when a request includes it. Nothing c
67
67
  export const trips = jsonApiResource('trips', tripAttributesSchema, {
68
68
  relationships: {
69
69
  place: toOne(
70
- () => places, // the resource the loaded rows are published as
71
- (row) => row.placeId, // beside a loader this reads the ID off the row, not the row
70
+ () => places, // the resource the loaded rows are published as
71
+ (row) => row.placeId, // beside a loader this reads the ID off the row, not the row
72
72
  { load: (ids, context: TripDocumentContext) => context.catalogue.places.byIds(ids) },
73
73
  ),
74
74
  },
@@ -83,11 +83,11 @@ deduplicated and in no order, so a page of fifty trips costs one call upstream r
83
83
  called only where the request's `include` names the relationship: a document that includes nothing makes
84
84
  no call at all, and still publishes the identifier, which is the key its own row carried.
85
85
 
86
- | The loader | What the document carries |
87
- | --- | --- |
88
- | answers a row for an id | that identifier, and the row under `included` |
89
- | answers no row for an id it was given | that identifier, and nothing under `included` |
90
- | throws | nothing; the failure comes out of `serialize` for the route to answer |
86
+ | The loader | What the document carries |
87
+ | ------------------------------------- | --------------------------------------------------------------------- |
88
+ | answers a row for an id | that identifier, and the row under `included` |
89
+ | answers no row for an id it was given | that identifier, and nothing under `included` |
90
+ | throws | nothing; the failure comes out of `serialize` for the route to answer |
91
91
 
92
92
  An id with no row back is how a row this caller may not see stays out of the document. Dropping the
93
93
  identifier with it would tell the client the trip has no place, which the row it was read off does not
@@ -117,7 +117,7 @@ export const academicsErrors = defineErrorMap([
117
117
  status: 409,
118
118
  title: 'Conflict',
119
119
  code: 'academics.class.full',
120
- meta: (error) => ({ capacity: error.capacity }), // `capacity` is typed off ClassFull
120
+ meta: (error) => ({ capacity: error.capacity }), // `capacity` is typed off ClassFull
121
121
  }),
122
122
  ]);
123
123
  ```
@@ -148,7 +148,7 @@ import { createErrorHandler } from '@zeroxsolutions/server';
148
148
 
149
149
  app.onError(
150
150
  createErrorHandler({
151
- namespace: 'academics', // every code THESE handlers mint carries it, so one surface has one vocabulary
151
+ namespace: 'academics', // every code THESE handlers mint carries it, so one surface has one vocabulary
152
152
  category: ['academics', 'http'],
153
153
  resolve: createDomainErrorResolver(academicsErrors),
154
154
  authenticationChallenge: 'Bearer',
@@ -213,13 +213,16 @@ export const PLACE_UPSTREAM_ERRORS = {
213
213
  // the return type is spelled: a callback in an object checked by `satisfies` alone is not a typed function
214
214
  // expression to @typescript-eslint/explicit-function-return-type
215
215
  meta: (upstream): Meta | undefined => {
216
- const parsed = placeFullMetaSchema.safeParse(upstream); // what the service promises, and nothing else
216
+ const parsed = placeFullMetaSchema.safeParse(upstream); // what the service promises, and nothing else
217
217
  return parsed.success ? parsed.data : undefined;
218
218
  },
219
219
  },
220
220
  } satisfies UpstreamErrorMap;
221
221
 
222
- export const translatePlaceUpstreamError = createUpstreamErrorTranslator(PLACE_UPSTREAM_ERRORS, PLACE_UPSTREAM_FALLBACK);
222
+ export const translatePlaceUpstreamError = createUpstreamErrorTranslator(
223
+ PLACE_UPSTREAM_ERRORS,
224
+ PLACE_UPSTREAM_FALLBACK,
225
+ );
223
226
  ```
224
227
 
225
228
  A route throws what the translator returns, so the one `onError` renders it like every other failure:
@@ -243,6 +246,11 @@ exactly one error per failure. Of that error it keeps only what an answer's `met
243
246
  pointers name the SERVICE's request shape, not the one this caller sent, so echoing them would point a
244
247
  client at members it has no way to correct.
245
248
 
249
+ An answer can state a `source` of its own instead, in this transport's request terms. It is fixed per
250
+ upstream code, so it suits a refusal whose slot is the same on every occurrence; a slot that varies per
251
+ occurrence (one member of a list, say) has no way through, since the upstream error's `source` is the only
252
+ place that varies and it describes the wrong request. The fallback states none.
253
+
246
254
  A `meta` callback returns its parse, never `upstream` as received - the schema is what keeps a member the
247
255
  service adds later from crossing. Returning `undefined` answers the fallback: a mapped code missing the
248
256
  data its contract promises is an answer the gateway does not recognise.
@@ -295,6 +303,30 @@ export const translateCatalogueError = translator(
295
303
  throw error({ ...BASE_ERROR_CODES.FORBIDDEN, code: 'api.forbidden' });
296
304
  ```
297
305
 
306
+ A mapped answer states where in the client's request the refusal belongs with `source`, one of the
307
+ standard's `pointer`, `parameter` or `header`. JSON:API holds a `pointer` to "a value in the request
308
+ document that exists", so it names the member this transport's client sent, never the one the service
309
+ was sent:
310
+
311
+ ```ts
312
+ // entrypoints/http/error-map.ts - the client names the place by its slug; the service was sent its id
313
+ export const translateCatalogueWriteError = translator(
314
+ CATALOGUE_ERROR_CODES,
315
+ {
316
+ 'catalogue.place.not_found': {
317
+ status: 422,
318
+ title: 'Unprocessable Entity',
319
+ code: 'api.place.not_found',
320
+ source: { pointer: '/data/attributes/placeSlug' },
321
+ },
322
+ },
323
+ { status: 502, title: 'Bad Gateway', code: 'api.upstream_failed' },
324
+ );
325
+ ```
326
+
327
+ The translated error renders `source: { pointer: '/data/attributes/placeSlug' }` whatever `source` the
328
+ service's error carried, and a member the standard does not define, `pointr`, does not compile.
329
+
298
330
  The lists are values rather than type arguments: with nothing passed there is no list to fall back on,
299
331
  where a type argument left out would widen to `string`. Neither is read at runtime. `error` also refuses
300
332
  a key its answer does not declare, so a misspelled `detial` does not compile, and a thrown answer's `meta`
@@ -3,6 +3,7 @@ import { type CollectionDocument, type ResourceDocument } from './document.js';
3
3
  import { errorDocumentSchema } from './errors/index.js';
4
4
  import { JSON_API_MEDIA_TYPE } from './media-type.js';
5
5
  import type { Meta, PaginationLinks } from './primitives.js';
6
+ import type { RelationshipDef } from './relationship.js';
6
7
  import type { JsonApiResource } from './resource.js';
7
8
  /**
8
9
  * An OpenAPI response object for this spelling - one media type, one schema, and the `Retry-After` a
@@ -45,7 +46,7 @@ export declare function errorResponse(description: string, options?: {
45
46
  retryAfterSeconds: number;
46
47
  }): JsonApiResponse<typeof errorDocumentSchema>;
47
48
  /** The response object for a single resource, off the resource's own declaration. */
48
- export declare function okResponse<A extends ZodObject, C = unknown>(description: string, resource: JsonApiResource<A, C>): JsonApiResponse<ZodType<ResourceDocument<output<A>>>>;
49
+ export declare function okResponse<A extends ZodObject, C = unknown, I extends string = string>(description: string, resource: JsonApiResource<A, C, string, Readonly<Record<string, RelationshipDef<C>>>, I>): JsonApiResponse<ZodType<ResourceDocument<output<A>, I>>>;
49
50
  /**
50
51
  * The response object for a collection, off the resource's own declaration.
51
52
  *
@@ -53,8 +54,8 @@ export declare function okResponse<A extends ZodObject, C = unknown>(description
53
54
  * as required and typed, so a client reads it without narrowing; one left out stays the standard's
54
55
  * optional, free-form member.
55
56
  */
56
- export declare function listResponse<A extends ZodObject, C = unknown, M extends ZodType<Meta> = never, L extends ZodType<PaginationLinks> = never>(description: string, resource: JsonApiResource<A, C>, members?: {
57
+ export declare function listResponse<A extends ZodObject, C = unknown, M extends ZodType<Meta> = never, L extends ZodType<PaginationLinks> = never, I extends string = string>(description: string, resource: JsonApiResource<A, C, string, Readonly<Record<string, RelationshipDef<C>>>, I>, members?: {
57
58
  meta?: M;
58
59
  links?: L;
59
- }): JsonApiResponse<ZodType<CollectionDocument<output<A>, output<M>, output<L>>>>;
60
+ }): JsonApiResponse<ZodType<CollectionDocument<output<A>, output<M>, output<L>, I>>>;
60
61
  //# sourceMappingURL=api-response.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-response.d.ts","sourceRoot":"","sources":["../src/api-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACtD,OAAO,EAA4B,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,OAAO;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,OAAO,mBAAmB,EAAE;QAAE,MAAM,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,aAAa,EAAE,gBAAgB,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,IAAI,CAAC;IACf,MAAM,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC;CACzC,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACtC,eAAe,CAAC,OAAO,mBAAmB,CAAC,CAqB7C;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,GAAG,OAAO,EACzD,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAC9B,eAAe,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,SAAS,EACnB,CAAC,GAAG,OAAO,EACX,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,EAC/B,CAAC,SAAS,OAAO,CAAC,eAAe,CAAC,GAAG,KAAK,EAE1C,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,EAC/B,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,CAAA;CAAO,GACpC,eAAe,CAAC,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAQ/E"}
1
+ {"version":3,"file":"api-response.d.ts","sourceRoot":"","sources":["../src/api-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACtD,OAAO,EAA4B,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,OAAO;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,OAAO,mBAAmB,EAAE;QAAE,MAAM,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,EAAE;QAAE,aAAa,EAAE,gBAAgB,CAAA;KAAE,CAAC;CAC/C;AAED;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,IAAI,CAAC;IACf,MAAM,EAAE;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC;CACzC,CAAC;AAOF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,iBAAiB,EAAE,MAAM,CAAA;CAAE,GACtC,eAAe,CAAC,OAAO,mBAAmB,CAAC,CAqB7C;AAED,qFAAqF;AACrF,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EACpF,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GACvF,eAAe,CAAC,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,CAAC,SAAS,SAAS,EACnB,CAAC,GAAG,OAAO,EACX,CAAC,SAAS,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,EAC/B,CAAC,SAAS,OAAO,CAAC,eAAe,CAAC,GAAG,KAAK,EAC1C,CAAC,SAAS,MAAM,GAAG,MAAM,EAEzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACxF,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,CAAA;CAAO,GACpC,eAAe,CAAC,OAAO,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAQlF"}
@@ -7,18 +7,18 @@ export interface Relationship {
7
7
  links?: RelationshipLinks;
8
8
  meta?: Meta;
9
9
  }
10
- /** A resource object, with `attributes` carrying the declared attribute type. */
11
- export interface ResourceObject<A> {
10
+ /** A resource object, with `attributes` carrying the declared attribute type and `id` the declared id type. */
11
+ export interface ResourceObject<A, I extends string = string> {
12
12
  type: string;
13
- id: string;
13
+ id: I;
14
14
  attributes: A;
15
15
  relationships?: Record<string, Relationship>;
16
16
  links?: ResourceLinks;
17
17
  meta?: Meta;
18
18
  }
19
19
  /** A single-resource document. `included` holds other resource types, so its attributes stay unknown. */
20
- export interface ResourceDocument<A> {
21
- data: ResourceObject<A>;
20
+ export interface ResourceDocument<A, I extends string = string> {
21
+ data: ResourceObject<A, I>;
22
22
  included?: ResourceObject<unknown>[];
23
23
  links?: TopLevelLinks;
24
24
  meta?: Meta;
@@ -38,8 +38,8 @@ type CollectionMember<K extends 'links' | 'meta', Declared, Loose> = [Declared]
38
38
  *
39
39
  * `M` and `L` are the `meta` and `links` a route declared, `never` where it declared none.
40
40
  */
41
- export type CollectionDocument<A, M = never, L = never> = {
42
- data: ResourceObject<A>[];
41
+ export type CollectionDocument<A, M = never, L = never, I extends string = string> = {
42
+ data: ResourceObject<A, I>[];
43
43
  included?: ResourceObject<unknown>[];
44
44
  jsonapi?: JsonApiObject;
45
45
  } & CollectionMember<'links', L, PaginationLinks> & CollectionMember<'meta', M, Meta>;
@@ -50,7 +50,7 @@ export type CollectionDocument<A, M = never, L = never> = {
50
50
  * Tuple-wrapped so it does not distribute: extras that carry `meta` on one branch of a union and not the
51
51
  * other may send none, and must not type it as present.
52
52
  */
53
- export type CollectionDocumentFor<A, X> = CollectionDocument<A, [
53
+ export type CollectionDocumentFor<A, X, I extends string = string> = CollectionDocument<A, [
54
54
  X
55
55
  ] extends [{
56
56
  meta: infer M;
@@ -58,14 +58,14 @@ export type CollectionDocumentFor<A, X> = CollectionDocument<A, [
58
58
  X
59
59
  ] extends [{
60
60
  links: infer L;
61
- }] ? L : never>;
61
+ }] ? L : never, I>;
62
62
  /**
63
63
  * Wraps `attributes` into a resource object - `{ type, id, attributes?, relationships?, links?, meta? }`.
64
64
  *
65
65
  * `attributes` parses as absent here, unlike {@link ResourceObject}'s own required member: this schema
66
66
  * also validates a document read off another server, which may publish a resource with none.
67
67
  */
68
- export declare function resourceObjectSchema<C>(type: string, attributes: ZodObject, relationships?: Readonly<Record<string, RelationshipDef<C>>>): ZodType;
68
+ export declare function resourceObjectSchema<C>(type: string, attributes: ZodObject, relationships?: Readonly<Record<string, RelationshipDef<C>>>, id?: ZodType<string, string>): ZodType;
69
69
  /**
70
70
  * The document for a SINGLE resource - `{ data, included?, links?, meta?, jsonapi? }`.
71
71
  *
@@ -76,16 +76,16 @@ export declare function resourceObjectSchema<C>(type: string, attributes: ZodObj
76
76
  * Strict at the top level: the standard forbids any top-level member beyond these (extension members
77
77
  * aside), which is what refuses a `data` document that also carries `errors`.
78
78
  */
79
- export declare function resourceDocumentSchema<A = unknown, C = unknown>(root: RelatedResource<C>): ZodType<ResourceDocument<A>>;
79
+ export declare function resourceDocumentSchema<A = unknown, C = unknown, I extends string = string>(root: RelatedResource<C>): ZodType<ResourceDocument<A, I>>;
80
80
  /**
81
81
  * The document for a COLLECTION - the same members, with `data` an array and paginated `links`.
82
82
  *
83
83
  * A member in `members` replaces the standard's optional one, so the route that declared it publishes it
84
84
  * as required. Strict at the top level for the same reason as {@link resourceDocumentSchema}.
85
85
  */
86
- export declare function collectionDocumentSchema<A = unknown, C = unknown, M = never, L = never>(root: RelatedResource<C>, members?: {
86
+ export declare function collectionDocumentSchema<A = unknown, C = unknown, M = never, L = never, I extends string = string>(root: RelatedResource<C>, members?: {
87
87
  meta?: ZodType;
88
88
  links?: ZodType;
89
- }): ZodType<CollectionDocument<A, M, L>>;
89
+ }): ZodType<CollectionDocument<A, M, L, I>>;
90
90
  export {};
91
91
  //# sourceMappingURL=document.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"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"}
package/dist/document.js CHANGED
@@ -7,11 +7,11 @@ import { relationshipsSchema, reachableResources } from './relationship.js';
7
7
  * `attributes` parses as absent here, unlike {@link ResourceObject}'s own required member: this schema
8
8
  * also validates a document read off another server, which may publish a resource with none.
9
9
  */
10
- export function resourceObjectSchema(type, attributes, relationships = {}) {
10
+ export function resourceObjectSchema(type, attributes, relationships = {}, id = z.string()) {
11
11
  const linkage = relationshipsSchema(relationships);
12
12
  return z.object({
13
13
  type: z.literal(type),
14
- id: z.string(),
14
+ id,
15
15
  attributes: attributes.optional(),
16
16
  ...(linkage ? { relationships: linkage.optional() } : {}),
17
17
  links: resourceLinksSchema.optional(),
@@ -5,9 +5,15 @@ import { type CollectionExtras, type RequestedDocumentShape, type Row } from './
5
5
  /** The context every loader in a relationship map runs under. */
6
6
  type ContextOfRelationships<R> = R[keyof R] extends RelationshipDef<infer C, any> ? C : unknown;
7
7
  /** Per-entity overrides for a resource declaration. */
8
- export interface ResourceOptions<R> {
8
+ export interface ResourceOptions<R, I extends string = string> {
9
9
  /** Relationships this resource declares, keyed by the member name they take in `relationships`. */
10
10
  relationships?: R;
11
+ /**
12
+ * The id as the wire carries it, which types `data.id` in every document and the `id` of every row serialized. Pass
13
+ * the wire half of a codec (a TypeID codec's `.in`), never the codec: a client reading the document back keeps the id
14
+ * it was sent. Omitted, the id is any text.
15
+ */
16
+ id?: ZodType<I, I>;
11
17
  }
12
18
  /**
13
19
  * One resource type declared once: the schemas a route answers with, and the serializer that produces
@@ -20,14 +26,14 @@ export interface ResourceOptions<R> {
20
26
  * `C` is the context its loaders are called with, inferred from the relationships it declares and from
21
27
  * the resources they point at, so every resource in one document's graph loads under one context.
22
28
  */
23
- export interface JsonApiResource<A extends ZodObject, C = unknown, T extends string = string, R extends Readonly<Record<string, RelationshipDef<any, any>>> = Readonly<Record<string, RelationshipDef<C>>>> extends RelatedResource<C> {
29
+ export interface JsonApiResource<A extends ZodObject, C = unknown, T extends string = string, R extends Readonly<Record<string, RelationshipDef<any, any>>> = Readonly<Record<string, RelationshipDef<C>>>, I extends string = string> extends RelatedResource<C> {
24
30
  readonly type: T;
25
31
  readonly attributes: A;
26
32
  readonly relationships: R;
27
33
  /** The single-resource document schema - `{ data, included?, links?, meta?, jsonapi? }`. */
28
- readonly document: ZodType<ResourceDocument<output<A>>>;
34
+ readonly document: ZodType<ResourceDocument<output<A>, I>>;
29
35
  /** The collection document schema - the same members with `data` an array. */
30
- readonly collectionDocument: ZodType<CollectionDocument<output<A>>>;
36
+ readonly collectionDocument: ZodType<CollectionDocument<output<A>, never, never, I>>;
31
37
  /**
32
38
  * Serializes one row into a single-resource document.
33
39
  *
@@ -35,7 +41,7 @@ export interface JsonApiResource<A extends ZodObject, C = unknown, T extends str
35
41
  * and an included relationship that declares a loader is loaded before the document is built
36
42
  * @param context - what the loaders are given; the call takes it only where a loader is reachable
37
43
  */
38
- serialize(row: Row, requested?: RequestedDocumentShape, ...context: LoadContextArguments<C>): Promise<ResourceDocument<output<A>>>;
44
+ serialize(row: Row<I>, requested?: RequestedDocumentShape, ...context: LoadContextArguments<C>): Promise<ResourceDocument<output<A>, I>>;
39
45
  /**
40
46
  * Serializes rows into a collection document, merging in pagination `links` and `meta`.
41
47
  *
@@ -43,7 +49,7 @@ export interface JsonApiResource<A extends ZodObject, C = unknown, T extends str
43
49
  * declared with `listResponse`. A key that is neither `links` nor `meta` is refused, since the
44
50
  * serializer drops it unsent.
45
51
  */
46
- serializeMany<X extends CollectionExtras = Record<never, never>>(rows: Row[], extras?: X & Record<Exclude<keyof X, keyof CollectionExtras>, never>, requested?: RequestedDocumentShape, ...context: LoadContextArguments<C>): Promise<CollectionDocumentFor<output<A>, X>>;
52
+ serializeMany<X extends CollectionExtras = Record<never, never>>(rows: Row<I>[], extras?: X & Record<Exclude<keyof X, keyof CollectionExtras>, never>, requested?: RequestedDocumentShape, ...context: LoadContextArguments<C>): Promise<CollectionDocumentFor<output<A>, X, I>>;
47
53
  }
48
54
  /** A relationship map's own names, and none where the map is the empty default. */
49
55
  type RelationshipName<R> = string extends keyof R ? never : keyof R & string;
@@ -55,6 +61,6 @@ type FieldNamespace<A extends ZodObject, R> = [
55
61
  (keyof A['shape'] & string & ('type' | 'id' | RelationshipName<R>)) | (RelationshipName<R> & ('type' | 'id'))
56
62
  ] extends [never] ? unknown : never;
57
63
  /** Declares a JSON:API resource type - its `type`, the schema of its `attributes`, and its relationships. */
58
- export declare function jsonApiResource<const T extends string, A extends ZodObject, const R extends Readonly<Record<string, RelationshipDef<any, any>>> = Readonly<Record<string, never>>, C = ContextOfRelationships<R>>(type: T, attributes: A & FieldNamespace<A, R>, options?: ResourceOptions<R>): JsonApiResource<A, C, T, R>;
64
+ export declare function jsonApiResource<const T extends string, A extends ZodObject, const R extends Readonly<Record<string, RelationshipDef<any, any>>> = Readonly<Record<string, never>>, C = ContextOfRelationships<R>, const I extends string = string>(type: T, attributes: A & FieldNamespace<A, R>, options?: ResourceOptions<R, I>): JsonApiResource<A, C, T, R, I>;
59
65
  export {};
60
66
  //# sourceMappingURL=resource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
package/dist/resource.js CHANGED
@@ -41,7 +41,10 @@ function membersOf(schema) {
41
41
  /** Every member name an attribute schema declares, at every depth. */
42
42
  function memberNames(schema) {
43
43
  return membersOf(schema).flatMap((member) => member instanceof z.ZodObject
44
- ? Object.entries(member.shape).flatMap(([name, inner]) => [name, ...memberNames(inner)])
44
+ ? Object.entries(member.shape).flatMap(([name, inner]) => [
45
+ name,
46
+ ...memberNames(inner),
47
+ ])
45
48
  : []);
46
49
  }
47
50
  /**
@@ -89,7 +92,7 @@ export function jsonApiResource(type, attributes, options = {}) {
89
92
  attributes,
90
93
  relationships,
91
94
  get resourceObject() {
92
- return (object ??= resourceObjectSchema(type, attributes, relationships));
95
+ return (object ??= resourceObjectSchema(type, attributes, relationships, options.id));
93
96
  },
94
97
  get document() {
95
98
  return (one ??= resourceDocumentSchema(resource));
@@ -1,8 +1,8 @@
1
1
  import { Serializer, type SerializerOptions } from 'ts-japi';
2
2
  import type { PaginationLinks } from './primitives.js';
3
3
  /** One row as a serializer hands it over. Its `id` is the resource id, which the standard makes a string. */
4
- export interface Row {
5
- id: string;
4
+ export interface Row<I extends string = string> {
5
+ id: I;
6
6
  [member: string]: unknown;
7
7
  }
8
8
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,UAAU,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,6GAA6G;AAC7G,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAK5D;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAEvE,sCAAsC;AACtC,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAEjD,KAAK,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,mFAAmF;IACnF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IACrD,mEAAmE;IACnE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAgCD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,EAC1B,SAAS,CAAC,EAAE,sBAAsB,GACjC,kBAAkB,CAgBpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AA8CD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,kBAAkB,EAC9B,IAAI,EAAE,GAAG,EACT,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAElC;AAED,0GAA0G;AAC1G,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,kBAAkB,EAC9B,KAAK,EAAE,GAAG,EAAE,EACZ,MAAM,GAAE,gBAAqB,EAC7B,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC"}
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,UAAU,EAAqB,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEzF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,6GAA6G;AAC7G,MAAM,WAAW,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IAC5C,EAAE,EAAE,CAAC,CAAC;IACN,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAK5D;AAED;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;AAEvE,sCAAsC;AACtC,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;AAEjD,KAAK,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,mFAAmF;IACnF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IACrD,mEAAmE;IACnE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAgCD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,gBAAgB,EAC1B,SAAS,CAAC,EAAE,sBAAsB,GACjC,kBAAkB,CAgBpB;AAED,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AA8CD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,kBAAkB,EAC9B,IAAI,EAAE,GAAG,EACT,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAElC;AAED,0GAA0G;AAC1G,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,kBAAkB,EAC9B,KAAK,EAAE,GAAG,EAAE,EACZ,MAAM,GAAE,gBAAqB,EAC7B,MAAM,CAAC,EAAE,UAAU,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC"}
@@ -1,5 +1,5 @@
1
1
  import type { UpstreamErrorMap } from './error-map.js';
2
- import type { ErrorDocument, ErrorLinks } from './errors/error-document.js';
2
+ import type { ErrorDocument, ErrorLinks, ErrorSource } from './errors/error-document.js';
3
3
  import type { ErrorStatus } from './errors/error-registry.js';
4
4
  import { JsonApiError } from './errors/jsonapi-error.js';
5
5
  import type { Meta } from './primitives.js';
@@ -11,6 +11,11 @@ export interface UpstreamErrorAnswer extends ErrorStatus {
11
11
  code: string;
12
12
  /** Human-readable and request-specific; the error's `message` falls back to the title without one. */
13
13
  detail?: string;
14
+ /**
15
+ * Where in this transport's own request the error originates, the same on every occurrence of the code - omit to render
16
+ * no `source`. The upstream error's own `source` is never read: it names a slot of the request the service received.
17
+ */
18
+ source?: ErrorSource;
14
19
  /** A page about this occurrence, and a page about its type of problem. */
15
20
  links?: ErrorLinks;
16
21
  /**
@@ -28,7 +33,8 @@ export interface UpstreamErrorAnswer extends ErrorStatus {
28
33
  *
29
34
  * The document's FIRST error decides, because `createErrorHandler` renders exactly one per failure. Nothing else of the
30
35
  * service's error survives unless an answer's `meta` reads it: its `code` names a namespace this surface's contract
31
- * never declared, and its `detail` and `source` describe a request this client never sent.
36
+ * never declared, and its `detail` and `source` describe a request this client never sent. An answer states its own
37
+ * `source` instead; the fallback states none, since the code it answers was not recognised.
32
38
  */
33
- export declare function createUpstreamErrorTranslator(answers: UpstreamErrorMap, fallback: Omit<UpstreamErrorAnswer, 'meta'>): (document: ErrorDocument) => JsonApiError;
39
+ export declare function createUpstreamErrorTranslator(answers: UpstreamErrorMap, fallback: Omit<UpstreamErrorAnswer, 'meta' | 'source'>): (document: ErrorDocument) => JsonApiError;
34
40
  //# sourceMappingURL=upstream-error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-error.d.ts","sourceRoot":"","sources":["../src/upstream-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,GAAG,SAAS,CAAC;CACzD;AAaD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAC,GAC1C,CAAC,QAAQ,EAAE,aAAa,KAAK,YAAY,CAa3C"}
1
+ {"version":3,"file":"upstream-error.d.ts","sourceRoot":"","sources":["../src/upstream-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,sGAAsG;IACtG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,GAAG,SAAS,CAAC;CACzD;AAcD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,QAAQ,CAAC,GACrD,CAAC,QAAQ,EAAE,aAAa,KAAK,YAAY,CAa3C"}
@@ -5,6 +5,7 @@ function toJsonApiError(answer, meta) {
5
5
  title: answer.title,
6
6
  code: answer.code,
7
7
  detail: answer.detail,
8
+ source: answer.source,
8
9
  links: answer.links,
9
10
  meta,
10
11
  });
@@ -15,7 +16,8 @@ function toJsonApiError(answer, meta) {
15
16
  *
16
17
  * The document's FIRST error decides, because `createErrorHandler` renders exactly one per failure. Nothing else of the
17
18
  * service's error survives unless an answer's `meta` reads it: its `code` names a namespace this surface's contract
18
- * never declared, and its `detail` and `source` describe a request this client never sent.
19
+ * never declared, and its `detail` and `source` describe a request this client never sent. An answer states its own
20
+ * `source` instead; the fallback states none, since the code it answers was not recognised.
19
21
  */
20
22
  export function createUpstreamErrorTranslator(answers, fallback) {
21
23
  return (document) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeroxsolutions/response",
3
- "version": "0.14.5",
3
+ "version": "0.14.7",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,7 +30,10 @@
30
30
  "zod": "^4.3.6"
31
31
  },
32
32
  "nx": {
33
- "name": "@zeroxsolutions/response"
33
+ "name": "@zeroxsolutions/response",
34
+ "targets": {
35
+ "lint-deps": {}
36
+ }
34
37
  },
35
38
  "main": "./dist/index.js",
36
39
  "module": "./dist/index.js",