lumen-framework 3.0.2 → 3.1.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/dist/cli.cjs +71 -38
- package/dist/cli.cjs.map +4 -4
- package/dist/index.js +978 -272
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +969 -263
- package/dist/index.mjs.map +4 -4
- package/dist/types/errors/namespaced-serializer-missing-error.d.ts +15 -0
- package/dist/types/packages/application/utils/validate-namespaced-serializers.d.ts +15 -0
- package/dist/types/packages/controller/errors/index.d.ts +1 -0
- package/dist/types/packages/controller/errors/related-record-not-found-error.d.ts +14 -0
- package/dist/types/packages/controller/index.d.ts +65 -0
- package/dist/types/packages/controller/utils/find-many.d.ts +2 -1
- package/dist/types/packages/controller/utils/find-one.d.ts +2 -1
- package/dist/types/packages/controller/utils/params-to-query.d.ts +7 -2
- package/dist/types/packages/controller/utils/validate-relationships.d.ts +8 -0
- package/dist/types/packages/database/constants.d.ts +1 -0
- package/dist/types/packages/database/model/index.d.ts +11 -0
- package/dist/types/packages/database/model/utils/process-write-error.d.ts +9 -1
- package/dist/types/packages/database/validation/errors/validation-error.d.ts +11 -2
- package/dist/types/packages/jsonapi/errors/not-acceptable-error.d.ts +1 -1
- package/dist/types/packages/jsonapi/index.d.ts +3 -1
- package/dist/types/packages/jsonapi/interfaces.d.ts +1 -1
- package/dist/types/packages/jsonapi/utils/has-media-type-params.d.ts +6 -0
- package/dist/types/packages/jsonapi/utils/is-jsonapi.d.ts +2 -0
- package/dist/types/packages/jsonapi/utils/media-type.d.ts +19 -0
- package/dist/types/packages/router/route/params/errors/client-generated-id-error.d.ts +13 -0
- package/dist/types/packages/router/route/params/errors/forbidden-parameter-error.d.ts +14 -0
- package/dist/types/packages/router/route/params/errors/index.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/invalid-parameter-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/parameter-not-nullable-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/parameter-required-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/parameter-type-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/parameter-value-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/errors/resource-mismatch-error.d.ts +2 -0
- package/dist/types/packages/router/route/params/index.d.ts +1 -0
- package/dist/types/packages/router/route/params/parameter/forbidden-parameter.d.ts +12 -0
- package/dist/types/packages/router/route/params/parameter/index.d.ts +8 -0
- package/dist/types/packages/router/route/params/utils/validate-client-id.d.ts +8 -0
- package/dist/types/packages/serializer/index.d.ts +111 -36
- package/dist/types/packages/serializer/utils/include-tree.d.ts +29 -0
- package/dist/types/packages/serializer/utils/load-linkage.d.ts +22 -0
- package/dist/types/packages/server/index.d.ts +2 -1
- package/dist/types/packages/server/interfaces.d.ts +5 -0
- package/dist/types/packages/server/utils/source-for.d.ts +10 -0
- package/dist/types/packages/server/utils/validate-accept.d.ts +5 -1
- package/dist/types/packages/server/utils/validate-content-type.d.ts +4 -0
- package/package.json +1 -1
- package/dist/types/packages/jsonapi/utils/has-media-type.d.ts +0 -4
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { Bundle$Namespace } from '../loader';
|
|
1
2
|
import type { Model, ModelClass } from '../database';
|
|
2
3
|
import type { JSONAPI$Document, JSONAPI$DocumentLinks, JSONAPI$ResourceObject, JSONAPI$RelationshipObject } from '../jsonapi';
|
|
3
4
|
import type { Serializer$opts } from './interfaces';
|
|
5
|
+
import type { Linkage } from './utils/load-linkage';
|
|
6
|
+
import type { IncludeTree } from './utils/include-tree';
|
|
4
7
|
/**
|
|
5
8
|
* ## Overview
|
|
6
9
|
*
|
|
@@ -155,6 +158,17 @@ import type { Serializer$opts } from './interfaces';
|
|
|
155
158
|
* If we request that the `posts` association is included from the `/users`
|
|
156
159
|
* endpoint, we will only get the `attributes` that the `PostsSerializer` has
|
|
157
160
|
* defined even though the response is processed by the `UsersSerializer`.
|
|
161
|
+
* The same goes for relationships: each included resource carries the
|
|
162
|
+
* `relationships` its own Serializer declares in `hasOne` and `hasMany`.
|
|
163
|
+
*
|
|
164
|
+
* Included resources follow the request's namespace: from `/admin/posts`,
|
|
165
|
+
* included comments are serialized by `AdminCommentsSerializer` when it
|
|
166
|
+
* exists and by `CommentsSerializer` otherwise (the same fallback a
|
|
167
|
+
* namespaced Controller uses), and their links point into `/admin`.
|
|
168
|
+
*
|
|
169
|
+
* Relationship paths may be nested, e.g. `/posts?include=comments.user`, up
|
|
170
|
+
* to the controller's `maxIncludeDepth` (3 by default). The intermediate
|
|
171
|
+
* resources (the comments) are included along with the leaves (their users).
|
|
158
172
|
*
|
|
159
173
|
* #### Sparse Fieldsets
|
|
160
174
|
*
|
|
@@ -401,6 +415,17 @@ declare class Serializer<T extends Model> {
|
|
|
401
415
|
* @private
|
|
402
416
|
*/
|
|
403
417
|
namespace: string;
|
|
418
|
+
/**
|
|
419
|
+
* Every Serializer of the application, keyed by namespaced path (`posts`,
|
|
420
|
+
* `admin/posts`). Attached once all of them are built, and used by
|
|
421
|
+
* `serializerFor()` to serialize related resources in this Serializer's
|
|
422
|
+
* namespace.
|
|
423
|
+
*
|
|
424
|
+
* @property serializers
|
|
425
|
+
* @type {Map}
|
|
426
|
+
* @private
|
|
427
|
+
*/
|
|
428
|
+
serializers?: Bundle$Namespace<Serializer<Model>>;
|
|
404
429
|
constructor({ model, parent, namespace }: Serializer$opts<T>);
|
|
405
430
|
/**
|
|
406
431
|
* Transform an array of Model instances or a single Model instance into a
|
|
@@ -423,25 +448,40 @@ declare class Serializer<T extends Model> {
|
|
|
423
448
|
* the resource and relationship objects in the returned [JSON API](
|
|
424
449
|
* http://jsonapi.org) document object.
|
|
425
450
|
*
|
|
426
|
-
* @param {Array} options.include - An array of
|
|
427
|
-
*
|
|
428
|
-
* the returned [JSON API](http://jsonapi.org)
|
|
451
|
+
* @param {Array} options.include - An array of relationship paths (e.g.
|
|
452
|
+
* `'comments'` or `'comments.user'`) whose resources should be added to the
|
|
453
|
+
* top level included object of the returned [JSON API](http://jsonapi.org)
|
|
454
|
+
* document object. Intermediate resources of a nested path are included too.
|
|
455
|
+
*
|
|
456
|
+
* @param {String} options.namespace - The namespace of the request, i.e. of
|
|
457
|
+
* the Controller handling it. Every link in the document is built in it, and
|
|
458
|
+
* included resources are serialized by their Serializer in it (falling back
|
|
459
|
+
* to the root). Defaults to this Serializer's namespace — which is the root
|
|
460
|
+
* one when a namespaced Controller has no Serializer of its own, so the
|
|
461
|
+
* Controller passes its namespace explicitly.
|
|
429
462
|
*
|
|
430
463
|
* @return {Promise} Resolves with a [JSON API](http://jsonapi.org) document
|
|
431
464
|
* object.
|
|
432
465
|
*
|
|
433
466
|
* @private
|
|
434
467
|
*/
|
|
435
|
-
format({ data, links, domain, include }: {
|
|
468
|
+
format({ data, links, domain, include, namespace }: {
|
|
436
469
|
data: T | Array<T>;
|
|
437
470
|
links: JSONAPI$DocumentLinks;
|
|
438
471
|
domain: string;
|
|
439
472
|
include: Array<string>;
|
|
473
|
+
namespace?: string;
|
|
440
474
|
}): Promise<JSONAPI$Document>;
|
|
441
475
|
/**
|
|
442
476
|
* Transform a single Model instance into a [JSON API](http://jsonapi.org)
|
|
443
477
|
* resource object.
|
|
444
478
|
*
|
|
479
|
+
* Relationships are serialized in one of two ways. By default each one is
|
|
480
|
+
* read from the Model instance (for primary data the query has already
|
|
481
|
+
* loaded them). When `linkage` is given — as it is for included resources,
|
|
482
|
+
* whose relationships are batch-loaded by `addIncluded()` — the resource
|
|
483
|
+
* linkage is built from it instead, without touching the database.
|
|
484
|
+
*
|
|
445
485
|
* @method formatOne
|
|
446
486
|
*
|
|
447
487
|
* @param {Object} options - An options object used for building the returned
|
|
@@ -458,30 +498,33 @@ declare class Serializer<T extends Model> {
|
|
|
458
498
|
* the top level links object or relationship links objects in the returned
|
|
459
499
|
* [JSON API](http://jsonapi.org) resource object.
|
|
460
500
|
*
|
|
461
|
-
* @param {Array} options.include - An array of
|
|
462
|
-
*
|
|
463
|
-
* a [JSON API](http://jsonapi.org) document object.
|
|
501
|
+
* @param {Array} options.include - An array of the relationship keys whose
|
|
502
|
+
* related records should be collected into `options.related`.
|
|
464
503
|
*
|
|
465
|
-
* @param {
|
|
466
|
-
*
|
|
467
|
-
* included
|
|
504
|
+
* @param {Map} options.related - Collects, per relationship key in
|
|
505
|
+
* `options.include`, the related Model instances that belong in the top
|
|
506
|
+
* level included object of a [JSON API](http://jsonapi.org) document object.
|
|
468
507
|
*
|
|
469
|
-
* @param {
|
|
470
|
-
*
|
|
471
|
-
*
|
|
508
|
+
* @param {Object} options.linkage - Pre-loaded resource linkage (related
|
|
509
|
+
* primary keys per relationship key) to serialize relationships from.
|
|
510
|
+
*
|
|
511
|
+
* @param {String} options.namespace - The namespace to build links in.
|
|
512
|
+
* Defaults to this Serializer's; included resources pass the namespace of
|
|
513
|
+
* the request, so every link in a document points into the same namespace.
|
|
472
514
|
*
|
|
473
515
|
* @return {Promise} Resolves with a [JSON API](http://jsonapi.org) resource
|
|
474
516
|
* object.
|
|
475
517
|
*
|
|
476
518
|
* @private
|
|
477
519
|
*/
|
|
478
|
-
formatOne({ item, links, domain, include,
|
|
520
|
+
formatOne({ item, links, domain, include, related, linkage, namespace }: {
|
|
479
521
|
item: T;
|
|
480
522
|
links?: boolean;
|
|
481
523
|
domain: string;
|
|
482
|
-
include
|
|
483
|
-
|
|
484
|
-
|
|
524
|
+
include?: Array<string>;
|
|
525
|
+
related?: Map<string, Array<Model>>;
|
|
526
|
+
linkage?: Linkage;
|
|
527
|
+
namespace?: string;
|
|
485
528
|
}): Promise<JSONAPI$ResourceObject>;
|
|
486
529
|
/**
|
|
487
530
|
* Transform a single Model instance into a [JSON API](http://jsonapi.org)
|
|
@@ -489,33 +532,65 @@ declare class Serializer<T extends Model> {
|
|
|
489
532
|
*
|
|
490
533
|
* @method formatRelationship
|
|
491
534
|
*
|
|
492
|
-
* @param {
|
|
535
|
+
* @param {Model} item - The Model instance to transform into the returned
|
|
493
536
|
* [JSON API](http://jsonapi.org) relationship object.
|
|
494
537
|
*
|
|
495
|
-
* @param {
|
|
538
|
+
* @param {String} domain - A string used to build links included in the
|
|
496
539
|
* returned [JSON API](http://jsonapi.org) relationship object.
|
|
497
540
|
*
|
|
498
|
-
* @
|
|
499
|
-
* the returned [JSON API](http://jsonapi.org) relationship object.
|
|
500
|
-
*
|
|
501
|
-
* @param {Array} options.include - An array of strings containing the
|
|
502
|
-
* relationship keys that should be added to the top level included object of
|
|
503
|
-
* a [JSON API](http://jsonapi.org) document object.
|
|
541
|
+
* @return {Object} A [JSON API](http://jsonapi.org) relationship object.
|
|
504
542
|
*
|
|
505
|
-
* @
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
*
|
|
510
|
-
*
|
|
543
|
+
* @private
|
|
544
|
+
*/
|
|
545
|
+
formatRelationship(item: Model, domain: string, namespace?: string): JSONAPI$RelationshipObject;
|
|
546
|
+
/**
|
|
547
|
+
* Build a [JSON API](http://jsonapi.org) relationship object from resource
|
|
548
|
+
* linkage, in the same shape `formatRelationship()` produces from Model
|
|
549
|
+
* instances: to-one relationships carry a `links` object, to-many ones only
|
|
550
|
+
* `data`, and a missing to-one relationship is `{ data: null }`.
|
|
511
551
|
*
|
|
552
|
+
* @method formatLinkage
|
|
553
|
+
* @private
|
|
554
|
+
*/
|
|
555
|
+
formatLinkage(domain: string, type: string | undefined, linkage: Array<string> | string | null | undefined, namespace?: string): JSONAPI$RelationshipObject;
|
|
556
|
+
/**
|
|
557
|
+
* Add `records` (instances of `model`) to `included` as resource objects,
|
|
558
|
+
* then recurse into the relationships named in `tree`. Each is serialized by
|
|
559
|
+
* `model`'s Serializer in this Serializer's namespace (`serializerFor()`), so
|
|
560
|
+
* `/admin/posts?include=comments` uses `AdminCommentsSerializer` when there
|
|
561
|
+
* is one and `CommentsSerializer` otherwise. The relationships of every level
|
|
562
|
+
* are batch-loaded with one query per relationship, not one per record.
|
|
563
|
+
*
|
|
564
|
+
* @method addIncluded
|
|
512
565
|
* @private
|
|
513
566
|
*/
|
|
514
|
-
|
|
515
|
-
|
|
567
|
+
addIncluded({ model, records, tree, domain, included, namespace }: {
|
|
568
|
+
model: ModelClass;
|
|
569
|
+
records: Array<Model>;
|
|
570
|
+
tree: IncludeTree;
|
|
516
571
|
domain: string;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}): Promise<
|
|
572
|
+
included: Map<string, JSONAPI$ResourceObject>;
|
|
573
|
+
namespace: string;
|
|
574
|
+
}): Promise<void>;
|
|
575
|
+
/**
|
|
576
|
+
* Resolve the Serializer for `model` in `namespace` (this Serializer's by
|
|
577
|
+
* default), the way a namespaced Controller resolves its own:
|
|
578
|
+
* `admin/comments` if it exists, otherwise the closest ancestor namespace's,
|
|
579
|
+
* down to the root `comments` Serializer. Falls back to `model.serializer`
|
|
580
|
+
* when this Serializer was not created by an application (e.g. in
|
|
581
|
+
* isolation).
|
|
582
|
+
*
|
|
583
|
+
* Pass the request's namespace when there is one: a Serializer's own
|
|
584
|
+
* namespace is the root one whenever it is a namespaced Controller's
|
|
585
|
+
* fallback.
|
|
586
|
+
*
|
|
587
|
+
* @method serializerFor
|
|
588
|
+
* @private
|
|
589
|
+
*/
|
|
590
|
+
serializerFor(model: ModelClass, namespace?: string): Serializer<Model>;
|
|
591
|
+
/**
|
|
592
|
+
* @private
|
|
593
|
+
*/
|
|
594
|
+
linkFor(domain: string, type: string, id: string, namespace?: string): string;
|
|
520
595
|
}
|
|
521
596
|
export default Serializer;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Model, ModelClass } from '../../database';
|
|
2
|
+
import type Serializer from '../index';
|
|
3
|
+
/**
|
|
4
|
+
* A parsed `include` parameter: each relationship name maps to the tree of
|
|
5
|
+
* relationships to include from the records it points to.
|
|
6
|
+
*
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
export type IncludeTree = Map<string, IncludeTree>;
|
|
10
|
+
/**
|
|
11
|
+
* Parse relationship paths (`['comments', 'comments.user', 'user']`) into an
|
|
12
|
+
* include tree. Every prefix of a path is part of the tree, because JSON:API
|
|
13
|
+
* requires the intermediate resources of a multi-part path to be included
|
|
14
|
+
* along with its leaves (`comments.user` includes the comments too).
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
export declare function createIncludeTree(paths?: Array<string>): IncludeTree;
|
|
19
|
+
/**
|
|
20
|
+
* Enumerate every include path available from `names` (relationships of
|
|
21
|
+
* `model`), down to `depth` levels. Each level continues with the relationships
|
|
22
|
+
* declared by the related model's serializer as `serializerFor` resolves it —
|
|
23
|
+
* the same one its included resources are serialized with (namespaced, with a
|
|
24
|
+
* fallback to the root). Used to build the allowed values of the `include`
|
|
25
|
+
* parameter.
|
|
26
|
+
*
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
export declare function enumerateIncludePaths(model: ModelClass, names: Array<string>, depth: number, serializerFor?: (model: ModelClass) => Serializer<Model> | undefined): Array<string>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Model, ModelClass } from '../../database';
|
|
2
|
+
/**
|
|
3
|
+
* The resource linkage of one record: the primary key(s) of the records each
|
|
4
|
+
* named relationship points to — an array for has-many, otherwise a single id
|
|
5
|
+
* or `null`.
|
|
6
|
+
*
|
|
7
|
+
* @private
|
|
8
|
+
*/
|
|
9
|
+
export type Linkage = Record<string, Array<string> | string | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Batch-load the resource linkage of the relationships `names` for every one of
|
|
12
|
+
* `records` (all instances of `model`), keyed by each record's primary key.
|
|
13
|
+
*
|
|
14
|
+
* This is what lets included resources carry `relationships` without an N+1:
|
|
15
|
+
* it issues at most one query per relationship — and a single query for all
|
|
16
|
+
* belongs-to relationships, whose foreign keys live on `model` itself — however
|
|
17
|
+
* many records there are. The queries mirror the lazy relationship getters in
|
|
18
|
+
* `database/relationship/utils/getters.ts`, which remain the source of truth.
|
|
19
|
+
*
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
export default function loadLinkage(model: ModelClass, records: Array<Model>, names: Array<string>): Promise<Map<string, Linkage>>;
|
|
@@ -22,6 +22,7 @@ declare class Server {
|
|
|
22
22
|
export default Server;
|
|
23
23
|
export { REQUEST_METHODS, getDomain } from './request';
|
|
24
24
|
export { default as createServerError } from './utils/create-server-error';
|
|
25
|
-
export
|
|
25
|
+
export { default as sourceFor } from './utils/source-for';
|
|
26
|
+
export type { Server$config, Server$ErrorSource } from './interfaces';
|
|
26
27
|
export type { Request, Request$params, Request$method } from './request/interfaces';
|
|
27
28
|
export type { Response } from './response/interfaces';
|
|
@@ -13,6 +13,11 @@ export type Server$opts = Server$config & {
|
|
|
13
13
|
logger: Logger;
|
|
14
14
|
router: Router;
|
|
15
15
|
};
|
|
16
|
+
export type Server$ErrorSource = {
|
|
17
|
+
pointer?: string;
|
|
18
|
+
parameter?: string;
|
|
19
|
+
};
|
|
16
20
|
export interface Server$Error extends Error {
|
|
17
21
|
statusCode: number;
|
|
22
|
+
source?: Server$ErrorSource;
|
|
18
23
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Server$ErrorSource } from '../interfaces';
|
|
2
|
+
/**
|
|
3
|
+
* Map an internal parameter path to a JSON:API error `source`. Paths under
|
|
4
|
+
* `data` are request document members and become a JSON Pointer
|
|
5
|
+
* (`data.attributes.isPublic` -> `/data/attributes/is-public`); anything else
|
|
6
|
+
* is a query parameter (`page.size` -> `page[size]`).
|
|
7
|
+
*
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
export default function sourceFor(path: string): Server$ErrorSource;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* JSON:API 1.0: respond 406 if the Accept header contains the JSON:API media
|
|
3
|
+
* type and *all* instances of it are modified with media type parameters.
|
|
4
|
+
* An Accept header without the JSON:API media type is left alone.
|
|
5
|
+
*
|
|
2
6
|
* @private
|
|
3
7
|
*/
|
|
4
|
-
export default function validateAccept(
|
|
8
|
+
export default function validateAccept(accept?: string): true;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* JSON:API 1.0: respond 415 if the Content-Type is the JSON:API media type
|
|
3
|
+
* with any media type parameters. A missing or different Content-Type is
|
|
4
|
+
* also answered with 415, since that is the only type the server accepts.
|
|
5
|
+
*
|
|
2
6
|
* @private
|
|
3
7
|
*/
|
|
4
8
|
export default function validateContentType(contentType?: string): true;
|
package/package.json
CHANGED