@zeroxsolutions/response 0.12.2 → 0.14.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/CHANGELOG.md +72 -0
- package/README.md +1 -0
- package/dist/created-response.d.ts +23 -0
- package/dist/created-response.d.ts.map +1 -0
- package/dist/created-response.js +19 -0
- package/dist/document-graph.d.ts +58 -0
- package/dist/document-graph.d.ts.map +1 -0
- package/dist/document-graph.js +1 -0
- package/dist/document-load.d.ts +1 -1
- package/dist/document-load.d.ts.map +1 -1
- package/dist/document-load.js +20 -8
- package/dist/document-shape.d.ts +12 -10
- package/dist/document-shape.d.ts.map +1 -1
- package/dist/document-shape.js +21 -10
- package/dist/document.d.ts +17 -5
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +19 -7
- package/dist/errors/error-document.d.ts +7 -2
- package/dist/errors/error-document.d.ts.map +1 -1
- package/dist/errors/error-document.js +7 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/member-name.d.ts +9 -0
- package/dist/member-name.d.ts.map +1 -0
- package/dist/member-name.js +15 -0
- package/dist/primitives.d.ts +174 -2
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +14 -2
- package/dist/relationship.d.ts +13 -6
- package/dist/relationship.d.ts.map +1 -1
- package/dist/relationship.js +14 -5
- package/dist/resource.d.ts +18 -4
- package/dist/resource.d.ts.map +1 -1
- package/dist/resource.js +73 -3
- package/dist/serialize.d.ts +14 -4
- package/dist/serialize.d.ts.map +1 -1
- package/dist/serialize.js +32 -3
- package/package.json +1 -1
package/dist/primitives.d.ts
CHANGED
|
@@ -59,7 +59,60 @@ export declare const resourceLinksSchema: z.ZodObject<{
|
|
|
59
59
|
}, z.core.$strip>;
|
|
60
60
|
/** A resource object's links - inferred from {@link resourceLinksSchema}. */
|
|
61
61
|
export type ResourceLinks = z.infer<typeof resourceLinksSchema>;
|
|
62
|
-
/**
|
|
62
|
+
/** A document's own top-level `self`/`related`, plus the description of the document itself. */
|
|
63
|
+
export declare const topLevelLinksSchema: z.ZodObject<{
|
|
64
|
+
self: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
65
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
66
|
+
title: z.ZodOptional<z.ZodString>;
|
|
67
|
+
type: z.ZodOptional<z.ZodString>;
|
|
68
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
69
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
70
|
+
href: z.ZodString;
|
|
71
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
72
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
73
|
+
title: z.ZodOptional<z.ZodString>;
|
|
74
|
+
type: z.ZodOptional<z.ZodString>;
|
|
75
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
76
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
77
|
+
href: z.ZodString;
|
|
78
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
79
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
80
|
+
related: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
81
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
82
|
+
title: z.ZodOptional<z.ZodString>;
|
|
83
|
+
type: z.ZodOptional<z.ZodString>;
|
|
84
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
85
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
86
|
+
href: z.ZodString;
|
|
87
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
88
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
89
|
+
title: z.ZodOptional<z.ZodString>;
|
|
90
|
+
type: z.ZodOptional<z.ZodString>;
|
|
91
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
92
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
93
|
+
href: z.ZodString;
|
|
94
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
95
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
96
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
97
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
98
|
+
title: z.ZodOptional<z.ZodString>;
|
|
99
|
+
type: z.ZodOptional<z.ZodString>;
|
|
100
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
101
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
102
|
+
href: z.ZodString;
|
|
103
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
104
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
105
|
+
title: z.ZodOptional<z.ZodString>;
|
|
106
|
+
type: z.ZodOptional<z.ZodString>;
|
|
107
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
108
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
109
|
+
href: z.ZodString;
|
|
110
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
111
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
/** A single-resource document's top-level links - inferred from {@link topLevelLinksSchema}. */
|
|
114
|
+
export type TopLevelLinks = z.infer<typeof topLevelLinksSchema>;
|
|
115
|
+
/** Collection pagination links, plus the description of the document itself. */
|
|
63
116
|
export declare const paginationLinksSchema: z.ZodObject<{
|
|
64
117
|
self: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
65
118
|
rel: z.ZodOptional<z.ZodString>;
|
|
@@ -141,9 +194,126 @@ export declare const paginationLinksSchema: z.ZodObject<{
|
|
|
141
194
|
href: z.ZodString;
|
|
142
195
|
}, z.core.$strip>, z.ZodNull]>>;
|
|
143
196
|
}, z.core.$strip>, z.ZodNull]>>;
|
|
197
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
198
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
199
|
+
title: z.ZodOptional<z.ZodString>;
|
|
200
|
+
type: z.ZodOptional<z.ZodString>;
|
|
201
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
202
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
203
|
+
href: z.ZodString;
|
|
204
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
205
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
206
|
+
title: z.ZodOptional<z.ZodString>;
|
|
207
|
+
type: z.ZodOptional<z.ZodString>;
|
|
208
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
209
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
210
|
+
href: z.ZodString;
|
|
211
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
212
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
144
213
|
}, z.core.$strip>;
|
|
145
214
|
/** Collection pagination links - inferred from {@link paginationLinksSchema}. */
|
|
146
215
|
export type PaginationLinks = z.infer<typeof paginationLinksSchema>;
|
|
216
|
+
/** A relationship's links: its own `self`/`related`, and the pages of a to-many linkage. */
|
|
217
|
+
export declare const relationshipLinksSchema: z.ZodObject<{
|
|
218
|
+
self: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
219
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
220
|
+
title: z.ZodOptional<z.ZodString>;
|
|
221
|
+
type: z.ZodOptional<z.ZodString>;
|
|
222
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
223
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
224
|
+
href: z.ZodString;
|
|
225
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
226
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
227
|
+
title: z.ZodOptional<z.ZodString>;
|
|
228
|
+
type: z.ZodOptional<z.ZodString>;
|
|
229
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
230
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
231
|
+
href: z.ZodString;
|
|
232
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
233
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
234
|
+
related: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
235
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
236
|
+
title: z.ZodOptional<z.ZodString>;
|
|
237
|
+
type: z.ZodOptional<z.ZodString>;
|
|
238
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
239
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
240
|
+
href: z.ZodString;
|
|
241
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
242
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
243
|
+
title: z.ZodOptional<z.ZodString>;
|
|
244
|
+
type: z.ZodOptional<z.ZodString>;
|
|
245
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
246
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
247
|
+
href: z.ZodString;
|
|
248
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
249
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
250
|
+
first: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
251
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
252
|
+
title: z.ZodOptional<z.ZodString>;
|
|
253
|
+
type: z.ZodOptional<z.ZodString>;
|
|
254
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
255
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
256
|
+
href: z.ZodString;
|
|
257
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
258
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
259
|
+
title: z.ZodOptional<z.ZodString>;
|
|
260
|
+
type: z.ZodOptional<z.ZodString>;
|
|
261
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
262
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
263
|
+
href: z.ZodString;
|
|
264
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
265
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
266
|
+
last: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
267
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
268
|
+
title: z.ZodOptional<z.ZodString>;
|
|
269
|
+
type: z.ZodOptional<z.ZodString>;
|
|
270
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
271
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
272
|
+
href: z.ZodString;
|
|
273
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
274
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
275
|
+
title: z.ZodOptional<z.ZodString>;
|
|
276
|
+
type: z.ZodOptional<z.ZodString>;
|
|
277
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
278
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
279
|
+
href: z.ZodString;
|
|
280
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
281
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
282
|
+
prev: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
283
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
284
|
+
title: z.ZodOptional<z.ZodString>;
|
|
285
|
+
type: z.ZodOptional<z.ZodString>;
|
|
286
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
287
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
288
|
+
href: z.ZodString;
|
|
289
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
290
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
291
|
+
title: z.ZodOptional<z.ZodString>;
|
|
292
|
+
type: z.ZodOptional<z.ZodString>;
|
|
293
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
294
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
295
|
+
href: z.ZodString;
|
|
296
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
297
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
298
|
+
next: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
299
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
300
|
+
title: z.ZodOptional<z.ZodString>;
|
|
301
|
+
type: z.ZodOptional<z.ZodString>;
|
|
302
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
303
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
304
|
+
href: z.ZodString;
|
|
305
|
+
describedby: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
|
|
306
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
307
|
+
title: z.ZodOptional<z.ZodString>;
|
|
308
|
+
type: z.ZodOptional<z.ZodString>;
|
|
309
|
+
hreflang: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
310
|
+
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
311
|
+
href: z.ZodString;
|
|
312
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
313
|
+
}, z.core.$strip>, z.ZodNull]>>;
|
|
314
|
+
}, z.core.$strip>;
|
|
315
|
+
/** A relationship's links - inferred from {@link relationshipLinksSchema}. */
|
|
316
|
+
export type RelationshipLinks = z.infer<typeof relationshipLinksSchema>;
|
|
147
317
|
/** A resource identifier object - the `{ type, id }` linkage that points at another resource. */
|
|
148
318
|
export declare const resourceIdentifierSchema: z.ZodObject<{
|
|
149
319
|
type: z.ZodString;
|
|
@@ -151,9 +321,11 @@ export declare const resourceIdentifierSchema: z.ZodObject<{
|
|
|
151
321
|
}, z.core.$strip>;
|
|
152
322
|
/** A type-and-id resource identifier - inferred from {@link resourceIdentifierSchema}. */
|
|
153
323
|
export type ResourceIdentifier = z.infer<typeof resourceIdentifierSchema>;
|
|
154
|
-
/** The top-level `jsonapi` member
|
|
324
|
+
/** The top-level `jsonapi` member: the version this document is written to, the extensions and profiles it applies. */
|
|
155
325
|
export declare const jsonApiObjectSchema: z.ZodObject<{
|
|
156
326
|
version: z.ZodOptional<z.ZodString>;
|
|
327
|
+
ext: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
328
|
+
profile: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
157
329
|
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
158
330
|
}, z.core.$strip>;
|
|
159
331
|
/** The top-level `jsonapi` member - inferred from {@link jsonApiObjectSchema}. */
|
package/dist/primitives.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8DAA8D;AAC9D,eAAO,MAAM,UAAU,wCAAoC,CAAC;AAC5D,oEAAoE;AACpE,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAsB9C,iGAAiG;AACjG,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;8BAIrB,CAAC;AACH,gEAAgE;AAChE,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,iFAAiF;AACjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAG9B,CAAC;AACH,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../src/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8DAA8D;AAC9D,eAAO,MAAM,UAAU,wCAAoC,CAAC;AAC5D,oEAAoE;AACpE,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAsB9C,iGAAiG;AACjG,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;8BAIrB,CAAC;AACH,gEAAgE;AAChE,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,iFAAiF;AACjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAG9B,CAAC;AACH,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,gGAAgG;AAChG,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAqE,CAAC;AACtG,gGAAgG;AAChG,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,gFAAgF;AAChF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAC;AACH,iFAAiF;AACjF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,4FAA4F;AAC5F,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKlC,CAAC;AACH,8EAA8E;AAC9E,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,iGAAiG;AACjG,eAAO,MAAM,wBAAwB;;;iBAAiD,CAAC;AACvF,0FAA0F;AAC1F,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,uHAAuH;AACvH,eAAO,MAAM,mBAAmB;;;;;iBAK9B,CAAC;AACH,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
|
package/dist/primitives.js
CHANGED
|
@@ -30,18 +30,30 @@ export const resourceLinksSchema = z.object({
|
|
|
30
30
|
self: linkSchema.optional(),
|
|
31
31
|
related: linkSchema.optional(),
|
|
32
32
|
});
|
|
33
|
-
/**
|
|
33
|
+
/** A document's own top-level `self`/`related`, plus the description of the document itself. */
|
|
34
|
+
export const topLevelLinksSchema = resourceLinksSchema.extend({ describedby: linkSchema.optional() });
|
|
35
|
+
/** Collection pagination links, plus the description of the document itself. */
|
|
34
36
|
export const paginationLinksSchema = z.object({
|
|
35
37
|
self: linkSchema.optional(),
|
|
36
38
|
first: linkSchema.optional(),
|
|
37
39
|
prev: linkSchema.optional(),
|
|
38
40
|
next: linkSchema.optional(),
|
|
39
41
|
last: linkSchema.optional(),
|
|
42
|
+
describedby: linkSchema.optional(),
|
|
43
|
+
});
|
|
44
|
+
/** A relationship's links: its own `self`/`related`, and the pages of a to-many linkage. */
|
|
45
|
+
export const relationshipLinksSchema = resourceLinksSchema.extend({
|
|
46
|
+
first: linkSchema.optional(),
|
|
47
|
+
last: linkSchema.optional(),
|
|
48
|
+
prev: linkSchema.optional(),
|
|
49
|
+
next: linkSchema.optional(),
|
|
40
50
|
});
|
|
41
51
|
/** A resource identifier object - the `{ type, id }` linkage that points at another resource. */
|
|
42
52
|
export const resourceIdentifierSchema = z.object({ type: z.string(), id: z.string() });
|
|
43
|
-
/** The top-level `jsonapi` member
|
|
53
|
+
/** The top-level `jsonapi` member: the version this document is written to, the extensions and profiles it applies. */
|
|
44
54
|
export const jsonApiObjectSchema = z.object({
|
|
45
55
|
version: z.string().optional(),
|
|
56
|
+
ext: z.array(z.string()).optional(),
|
|
57
|
+
profile: z.array(z.string()).optional(),
|
|
46
58
|
meta: metaSchema.optional(),
|
|
47
59
|
});
|
package/dist/relationship.d.ts
CHANGED
|
@@ -44,20 +44,27 @@ export interface RelatedResource<C = unknown> {
|
|
|
44
44
|
*/
|
|
45
45
|
serializerFor(requested?: RequestedDocumentShape, loaded?: LoadedRows): ResourceSerializer;
|
|
46
46
|
}
|
|
47
|
+
/** The context a related resource's loaders run under, read off the resource so a caller never spells it. */
|
|
48
|
+
export type ContextOf<R> = R extends RelatedResource<infer C> ? C : unknown;
|
|
47
49
|
/** A relationship: the resource it points at, how many, how to read it off a row, and who loads it. */
|
|
48
|
-
export interface RelationshipDef<C = unknown> {
|
|
50
|
+
export interface RelationshipDef<C = unknown, R extends RelatedResource<never> = RelatedResource<C>> {
|
|
49
51
|
readonly cardinality: 'one' | 'many';
|
|
50
52
|
/** A thunk, so two resources may name each other without a module-evaluation cycle. */
|
|
51
|
-
readonly related: () =>
|
|
53
|
+
readonly related: () => R;
|
|
52
54
|
/** Reads the related row(s) off the primary row, or the related id(s) where a loader is declared. */
|
|
53
55
|
readonly read: (row: Row) => unknown;
|
|
54
56
|
/** Absent where the primary row already carries the related rows. */
|
|
55
57
|
readonly load?: RelationshipLoader<C>;
|
|
56
58
|
}
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Declares a to-one relationship - its `data` is a single identifier, or null.
|
|
61
|
+
*
|
|
62
|
+
* The context is inferred from the loader and from the related resource. An explicit `toOne<Ctx>(...)`
|
|
63
|
+
* would stop TypeScript inferring the related resource, which then widens and drops every literal below it.
|
|
64
|
+
*/
|
|
65
|
+
export declare function toOne<const R extends RelatedResource<never>, C = ContextOf<R>>(related: () => R, read: (row: Row) => unknown, options?: RelationshipOptions<C>): RelationshipDef<NoInfer<C>, R>;
|
|
66
|
+
/** Declares a to-many relationship - its `data` is an array of identifiers. The context is inferred as for `toOne`. */
|
|
67
|
+
export declare function toMany<const R extends RelatedResource<never>, C = ContextOf<R>>(related: () => R, read: (row: Row) => unknown, options?: RelationshipOptions<C>): RelationshipDef<NoInfer<C>, R>;
|
|
61
68
|
/** The linkage schema for one relationship, pinned to the related `type` so a wrong type fails the parse. */
|
|
62
69
|
export declare function relationshipSchema<C>(def: RelationshipDef<C>): ZodType;
|
|
63
70
|
/** The `relationships` member for a whole resource - one key per declaration, absent when it declares none. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../src/relationship.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAE9C,OAAO,KAAK,EAAE,UAAU,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAElG;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC;CAC/D;AAED,kGAAkG;AAClG,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,kHAAkH;IAClH,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC;CACtC;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAAI,OAAO,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAE/F,sFAAsF;AACtF,wBAAgB,WAAW,CAAC,CAAC,EAAE,gBAAgB,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,CAG3E;AAED,6GAA6G;AAC7G,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrE,gHAAgH;IAChH,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,wGAAwG;IACxG,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,SAAS,CAAC,EAAE,sBAAsB,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,kBAAkB,CAAC;CAC5F;AAED,uGAAuG;AACvG,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"relationship.d.ts","sourceRoot":"","sources":["../src/relationship.ts"],"names":[],"mappings":"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"}
|
package/dist/relationship.js
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { metaSchema,
|
|
2
|
+
import { metaSchema, relationshipLinksSchema, resourceIdentifierSchema } from './primitives.js';
|
|
3
3
|
/** The context a serialize call was handed, for the load pass to give the loaders. */
|
|
4
4
|
export function loadContext(contextArguments) {
|
|
5
5
|
// A conditional tuple's element does not narrow back to `C`, and this is the one place that reads it.
|
|
6
6
|
return contextArguments[0];
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* Declares a to-one relationship - its `data` is a single identifier, or null.
|
|
10
|
+
*
|
|
11
|
+
* The context is inferred from the loader and from the related resource. An explicit `toOne<Ctx>(...)`
|
|
12
|
+
* would stop TypeScript inferring the related resource, which then widens and drops every literal below it.
|
|
13
|
+
*/
|
|
9
14
|
export function toOne(related, read, options) {
|
|
10
15
|
return { cardinality: 'one', related, read, load: options?.load };
|
|
11
16
|
}
|
|
12
|
-
/** Declares a to-many relationship - its `data` is an array of identifiers. */
|
|
17
|
+
/** Declares a to-many relationship - its `data` is an array of identifiers. The context is inferred as for `toOne`. */
|
|
13
18
|
export function toMany(related, read, options) {
|
|
14
19
|
return { cardinality: 'many', related, read, load: options?.load };
|
|
15
20
|
}
|
|
16
21
|
/** The linkage schema for one relationship, pinned to the related `type` so a wrong type fails the parse. */
|
|
17
22
|
export function relationshipSchema(def) {
|
|
18
23
|
const identifier = resourceIdentifierSchema.extend({ type: z.literal(def.related().type) });
|
|
19
|
-
return z
|
|
24
|
+
return z
|
|
25
|
+
.object({
|
|
20
26
|
data: (def.cardinality === 'one' ? identifier.nullable() : z.array(identifier)).optional(),
|
|
21
|
-
links:
|
|
27
|
+
links: relationshipLinksSchema.optional(),
|
|
22
28
|
meta: metaSchema.optional(),
|
|
29
|
+
})
|
|
30
|
+
.refine((relationship) => Object.keys(relationship).length > 0, {
|
|
31
|
+
message: 'A relationship object carries links, data or meta.',
|
|
23
32
|
});
|
|
24
33
|
}
|
|
25
34
|
/** The `relationships` member for a whole resource - one key per declaration, absent when it declares none. */
|
package/dist/resource.d.ts
CHANGED
|
@@ -2,10 +2,12 @@ import type { output, ZodObject, ZodType } from 'zod';
|
|
|
2
2
|
import { type CollectionDocument, type ResourceDocument } from './document.js';
|
|
3
3
|
import { type LoadContextArguments, type RelatedResource, type RelationshipDef } from './relationship.js';
|
|
4
4
|
import { type CollectionExtras, type RequestedDocumentShape, type Row } from './serialize.js';
|
|
5
|
+
/** The context every loader in a relationship map runs under. */
|
|
6
|
+
type ContextOfRelationships<R> = R[keyof R] extends RelationshipDef<infer C, any> ? C : unknown;
|
|
5
7
|
/** Per-entity overrides for a resource declaration. */
|
|
6
|
-
export interface ResourceOptions<
|
|
8
|
+
export interface ResourceOptions<R> {
|
|
7
9
|
/** Relationships this resource declares, keyed by the member name they take in `relationships`. */
|
|
8
|
-
relationships?:
|
|
10
|
+
relationships?: R;
|
|
9
11
|
}
|
|
10
12
|
/**
|
|
11
13
|
* One resource type declared once: the schemas a route answers with, and the serializer that produces
|
|
@@ -18,8 +20,10 @@ export interface ResourceOptions<C> {
|
|
|
18
20
|
* `C` is the context its loaders are called with, inferred from the relationships it declares and from
|
|
19
21
|
* the resources they point at, so every resource in one document's graph loads under one context.
|
|
20
22
|
*/
|
|
21
|
-
export interface JsonApiResource<A extends ZodObject, C = unknown
|
|
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> {
|
|
24
|
+
readonly type: T;
|
|
22
25
|
readonly attributes: A;
|
|
26
|
+
readonly relationships: R;
|
|
23
27
|
/** The single-resource document schema - `{ data, included?, links?, meta?, jsonapi? }`. */
|
|
24
28
|
readonly document: ZodType<ResourceDocument<output<A>>>;
|
|
25
29
|
/** The collection document schema - the same members with `data` an array. */
|
|
@@ -35,6 +39,16 @@ export interface JsonApiResource<A extends ZodObject, C = unknown> extends Relat
|
|
|
35
39
|
/** Serializes rows into a collection document, merging in pagination `links` and `meta`. */
|
|
36
40
|
serializeMany(rows: Row[], extras?: CollectionExtras, requested?: RequestedDocumentShape, ...context: LoadContextArguments<C>): Promise<CollectionDocument<output<A>>>;
|
|
37
41
|
}
|
|
42
|
+
/** A relationship map's own names, and none where the map is the empty default. */
|
|
43
|
+
type RelationshipName<R> = string extends keyof R ? never : keyof R & string;
|
|
44
|
+
/**
|
|
45
|
+
* `never` where a name breaks the standard's one field namespace (an attribute or relationship named `type` or `id`,
|
|
46
|
+
* or a name that is both), which turns the declaring call into a compile error.
|
|
47
|
+
*/
|
|
48
|
+
type FieldNamespace<A extends ZodObject, R> = [
|
|
49
|
+
(keyof A['shape'] & string & ('type' | 'id' | RelationshipName<R>)) | (RelationshipName<R> & ('type' | 'id'))
|
|
50
|
+
] extends [never] ? unknown : never;
|
|
38
51
|
/** Declares a JSON:API resource type - its `type`, the schema of its `attributes`, and its relationships. */
|
|
39
|
-
export declare function jsonApiResource<A extends ZodObject, C =
|
|
52
|
+
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>;
|
|
53
|
+
export {};
|
|
40
54
|
//# sourceMappingURL=resource.d.ts.map
|
package/dist/resource.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../src/resource.ts"],"names":[],"mappings":"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"}
|
package/dist/resource.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Relator } from 'ts-japi';
|
|
2
|
+
import { z } from 'zod';
|
|
2
3
|
import { collectionDocumentSchema, resourceDocumentSchema, resourceObjectSchema, } from './document.js';
|
|
3
4
|
import { loadedRelated, loadIncludedRows } from './document-load.js';
|
|
5
|
+
import { isMemberName } from './member-name.js';
|
|
4
6
|
import { loadContext } from './relationship.js';
|
|
5
|
-
import { createSerializer, serializeCollection, serializeResource, } from './serialize.js';
|
|
7
|
+
import { assertRowId, createSerializer, serializeCollection, serializeResource, } from './serialize.js';
|
|
6
8
|
/**
|
|
7
9
|
* How many requested shapes one resource keeps a serializer for. The shape is spelled by the caller's
|
|
8
10
|
* query, so past this bound a serializer is built for the call and not kept.
|
|
@@ -15,9 +17,67 @@ const MAX_KEPT_SERIALIZERS = 64;
|
|
|
15
17
|
function shapeKey(requested) {
|
|
16
18
|
return JSON.stringify([requested?.fields ?? null, requested?.include ?? null]);
|
|
17
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Steps past the wrappers that change presence or transport, not shape, as a declaration's schemas nest:
|
|
22
|
+
* optional/nullable/default, an array's element, a union's members, and a pipe's `in` - which is what a
|
|
23
|
+
* `.transform()` or `.pipe()` compiles to, so a nested object behind either is still checked.
|
|
24
|
+
*
|
|
25
|
+
* A `z.record()` and a `z.lazy()` schema are left unwalked on purpose: a record's keys are the caller's
|
|
26
|
+
* own data, not members this declaration names, and a lazy schema resolves its inner type only on use,
|
|
27
|
+
* which is past the point this walk runs.
|
|
28
|
+
*/
|
|
29
|
+
function membersOf(schema) {
|
|
30
|
+
const def = schema.def;
|
|
31
|
+
if (def.innerType)
|
|
32
|
+
return membersOf(def.innerType);
|
|
33
|
+
if (def.type === 'array' && def.element)
|
|
34
|
+
return membersOf(def.element);
|
|
35
|
+
if (def.type === 'union' && def.options)
|
|
36
|
+
return def.options.flatMap(membersOf);
|
|
37
|
+
if (def.type === 'pipe' && def.in)
|
|
38
|
+
return membersOf(def.in);
|
|
39
|
+
return [schema];
|
|
40
|
+
}
|
|
41
|
+
/** Every member name an attribute schema declares, at every depth. */
|
|
42
|
+
function memberNames(schema) {
|
|
43
|
+
return membersOf(schema).flatMap((member) => member instanceof z.ZodObject
|
|
44
|
+
? Object.entries(member.shape).flatMap(([name, inner]) => [name, ...memberNames(inner)])
|
|
45
|
+
: []);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @throws Error on a type or member name the standard does not allow, a name outside the one field namespace, or an
|
|
49
|
+
* attribute that republishes a relationship's own reference as a foreign key
|
|
50
|
+
*/
|
|
51
|
+
function assertDeclaration(type, attributes,
|
|
52
|
+
// Only `cardinality` is read here; the full `RelationshipDef<C, R>` is contravariant in `C` through its
|
|
53
|
+
// optional `load`, which makes a map typed with concrete C/R fail against one typed `any`/`any`.
|
|
54
|
+
relationships) {
|
|
55
|
+
if (!isMemberName(type))
|
|
56
|
+
throw new Error(`"${type}" is not a legal JSON:API type.`);
|
|
57
|
+
const attributeNames = Object.keys(attributes.shape);
|
|
58
|
+
for (const name of [...memberNames(attributes), ...Object.keys(relationships)]) {
|
|
59
|
+
if (!isMemberName(name))
|
|
60
|
+
throw new Error(`"${name}" is not a legal JSON:API member name on "${type}".`);
|
|
61
|
+
}
|
|
62
|
+
for (const name of [...attributeNames, ...Object.keys(relationships)]) {
|
|
63
|
+
if (name === 'type' || name === 'id')
|
|
64
|
+
throw new Error(`"${type}" cannot declare a field named "${name}".`);
|
|
65
|
+
}
|
|
66
|
+
for (const [name, def] of Object.entries(relationships)) {
|
|
67
|
+
if (attributeNames.includes(name))
|
|
68
|
+
throw new Error(`"${type}" declares "${name}" as an attribute and a relationship.`);
|
|
69
|
+
const keys = def.cardinality === 'one' ? [`${name}Id`, `${name}_id`] : [`${name}Ids`, `${name}_ids`];
|
|
70
|
+
const foreignKey = keys.find((key) => attributeNames.includes(key));
|
|
71
|
+
if (foreignKey)
|
|
72
|
+
throw new Error(`"${type}" publishes "${foreignKey}"; the "${name}" relationship already carries it.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
18
75
|
/** Declares a JSON:API resource type - its `type`, the schema of its `attributes`, and its relationships. */
|
|
19
76
|
export function jsonApiResource(type, attributes, options = {}) {
|
|
20
|
-
|
|
77
|
+
// Safe: when `relationships` is omitted, R is inferred as its own empty-relationships default above,
|
|
78
|
+
// which `{}` already satisfies.
|
|
79
|
+
const relationships = (options.relationships ?? {});
|
|
80
|
+
assertDeclaration(type, attributes, relationships);
|
|
21
81
|
// The attribute keys ARE the projection, so a row member the schema does not declare never reaches the wire.
|
|
22
82
|
const projection = Object.fromEntries(Object.keys(attributes.shape).map((name) => [name, 1]));
|
|
23
83
|
const serializers = new Map();
|
|
@@ -44,7 +104,14 @@ export function jsonApiResource(type, attributes, options = {}) {
|
|
|
44
104
|
return built;
|
|
45
105
|
const relators = Object.fromEntries(Object.entries(relationships).map(([name, def]) => [
|
|
46
106
|
name,
|
|
47
|
-
new Relator(async (row) =>
|
|
107
|
+
new Relator(async (row) => {
|
|
108
|
+
const related = def.load === undefined ? def.read(row) : loadedRelated(def, row, loaded);
|
|
109
|
+
// A relationship absent on the row reads back `undefined`, not the `null` its own type promises.
|
|
110
|
+
for (const one of Array.isArray(related) ? related : related == null ? [] : [related]) {
|
|
111
|
+
assertRowId(def.related().type, one);
|
|
112
|
+
}
|
|
113
|
+
return related;
|
|
114
|
+
},
|
|
48
115
|
// The lazy overload, so a pair of resources naming each other resolves on use, not on construction.
|
|
49
116
|
() => def.related().serializerFor(requested, loaded), { relatedName: name }),
|
|
50
117
|
]));
|
|
@@ -55,11 +122,14 @@ export function jsonApiResource(type, attributes, options = {}) {
|
|
|
55
122
|
return serializer;
|
|
56
123
|
},
|
|
57
124
|
async serialize(row, requested, ...context) {
|
|
125
|
+
assertRowId(type, row);
|
|
58
126
|
const loaded = await loadIncludedRows(resource, [row], requested, loadContext(context));
|
|
59
127
|
// ts-japi hands back an untyped object; the declared attributes are this resource's own schema.
|
|
60
128
|
return serializeResource(resource.serializerFor(requested, loaded), row, loaded);
|
|
61
129
|
},
|
|
62
130
|
async serializeMany(rows, extras, requested, ...context) {
|
|
131
|
+
for (const row of rows)
|
|
132
|
+
assertRowId(type, row);
|
|
63
133
|
const loaded = await loadIncludedRows(resource, rows, requested, loadContext(context));
|
|
64
134
|
return serializeCollection(resource.serializerFor(requested, loaded), rows, extras, loaded);
|
|
65
135
|
},
|
package/dist/serialize.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { Serializer, type SerializerOptions } from 'ts-japi';
|
|
2
2
|
import type { PaginationLinks } from './primitives.js';
|
|
3
|
-
/** One row as a serializer hands it over
|
|
4
|
-
export
|
|
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;
|
|
6
|
+
[member: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Refuses a row whose id is not a string at runtime. The type is the defence that matters: on a create this fires
|
|
10
|
+
* after the write committed, so it only stops a wrong document from going out.
|
|
11
|
+
*
|
|
12
|
+
* @throws TypeError naming the resource type
|
|
13
|
+
*/
|
|
14
|
+
export declare function assertRowId(type: string, row: unknown): void;
|
|
5
15
|
/**
|
|
6
16
|
* The rows one document's relationship loaders answered, keyed by related type and then by id.
|
|
7
17
|
*
|
|
@@ -46,8 +56,8 @@ export interface CollectionExtras {
|
|
|
46
56
|
* @param data - the row to serialize; its `id` member becomes the resource id
|
|
47
57
|
* @param loaded - what this document's relationship loaders answered, which decides its `included`
|
|
48
58
|
*/
|
|
49
|
-
export declare function serializeResource(serializer: ResourceSerializer, data: Row, loaded?: LoadedRows): Promise<
|
|
59
|
+
export declare function serializeResource(serializer: ResourceSerializer, data: Row, loaded?: LoadedRows): Promise<Record<string, unknown>>;
|
|
50
60
|
/** Serializes a list of rows into a collection document, merging in the pagination `links` and `meta`. */
|
|
51
|
-
export declare function serializeCollection(serializer: ResourceSerializer, items: Row[], extras?: CollectionExtras, loaded?: LoadedRows): Promise<
|
|
61
|
+
export declare function serializeCollection(serializer: ResourceSerializer, items: Row[], extras?: CollectionExtras, loaded?: LoadedRows): Promise<Record<string, unknown>>;
|
|
52
62
|
export {};
|
|
53
63
|
//# sourceMappingURL=serialize.d.ts.map
|
package/dist/serialize.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/serialize.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { Relator, Serializer } from 'ts-japi';
|
|
2
2
|
import { JSON_API_VERSION } from './media-type.js';
|
|
3
|
+
/**
|
|
4
|
+
* Refuses a row whose id is not a string at runtime. The type is the defence that matters: on a create this fires
|
|
5
|
+
* after the write committed, so it only stops a wrong document from going out.
|
|
6
|
+
*
|
|
7
|
+
* @throws TypeError naming the resource type
|
|
8
|
+
*/
|
|
9
|
+
export function assertRowId(type, row) {
|
|
10
|
+
const id = row?.id;
|
|
11
|
+
if (typeof id !== 'string') {
|
|
12
|
+
throw new TypeError(`A "${type}" row carries a ${typeof id} id; a JSON:API id is a string.`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
3
15
|
/**
|
|
4
16
|
* Whether the static projection publishes `name`, read so that a `0` counts as hidden under either mode.
|
|
5
17
|
*
|
|
@@ -54,7 +66,11 @@ export function createSerializer(type, options, requested) {
|
|
|
54
66
|
}),
|
|
55
67
|
});
|
|
56
68
|
}
|
|
57
|
-
/**
|
|
69
|
+
/**
|
|
70
|
+
* Raises the `jsonapi` member to {@link JSON_API_VERSION}, keeping whatever else ts-japi put there.
|
|
71
|
+
*
|
|
72
|
+
* Typed over a document, not a {@link Row}: a document carries no `id` of its own, unlike the row serialized into it.
|
|
73
|
+
*/
|
|
58
74
|
function stamped(doc) {
|
|
59
75
|
const existing = (doc.jsonapi ?? {});
|
|
60
76
|
return { ...doc, jsonapi: { ...existing, version: JSON_API_VERSION } };
|
|
@@ -74,6 +90,19 @@ function includedAsLoaded(document, loaded) {
|
|
|
74
90
|
included: document.included.filter((resource) => loaded.get(resource.type)?.has(resource.id) ?? true),
|
|
75
91
|
};
|
|
76
92
|
}
|
|
93
|
+
/** The `type` and `id` pair a resource object is identified by. */
|
|
94
|
+
const identity = (resource) => JSON.stringify([resource.type, resource.id]);
|
|
95
|
+
/**
|
|
96
|
+
* Drops from `included` every resource already present as primary data. A compound document carries one resource
|
|
97
|
+
* object per type and id, and a client indexing both members by that pair reads the second as a conflict.
|
|
98
|
+
*/
|
|
99
|
+
function withoutPrimary(document) {
|
|
100
|
+
if (document.included === undefined || document.data == null)
|
|
101
|
+
return document;
|
|
102
|
+
const data = Array.isArray(document.data) ? document.data : [document.data];
|
|
103
|
+
const primary = new Set(data.map(identity));
|
|
104
|
+
return { ...document, included: document.included.filter((resource) => !primary.has(identity(resource))) };
|
|
105
|
+
}
|
|
77
106
|
/**
|
|
78
107
|
* Serializes one row into a single-resource document.
|
|
79
108
|
*
|
|
@@ -81,12 +110,12 @@ function includedAsLoaded(document, loaded) {
|
|
|
81
110
|
* @param loaded - what this document's relationship loaders answered, which decides its `included`
|
|
82
111
|
*/
|
|
83
112
|
export async function serializeResource(serializer, data, loaded) {
|
|
84
|
-
return stamped(includedAsLoaded(await serializer.serialize(data), loaded));
|
|
113
|
+
return stamped(withoutPrimary(includedAsLoaded(await serializer.serialize(data), loaded)));
|
|
85
114
|
}
|
|
86
115
|
/** Serializes a list of rows into a collection document, merging in the pagination `links` and `meta`. */
|
|
87
116
|
export async function serializeCollection(serializer, items, extras = {}, loaded) {
|
|
88
117
|
return {
|
|
89
|
-
...stamped(includedAsLoaded(await serializer.serialize(items), loaded)),
|
|
118
|
+
...stamped(withoutPrimary(includedAsLoaded(await serializer.serialize(items), loaded))),
|
|
90
119
|
...(extras.links ? { links: extras.links } : {}),
|
|
91
120
|
...(extras.meta ? { meta: extras.meta } : {}),
|
|
92
121
|
};
|