@kavo/graphql 0.4.0 → 0.6.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/discovery.d.ts +7 -7
- package/dist/discovery.js +8 -8
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/registry.d.ts +11 -11
- package/dist/registry.js +7 -7
- package/dist/schema.d.ts +15 -15
- package/dist/schema.js +11 -11
- package/package.json +6 -6
package/dist/discovery.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ClassRef, EntityId } from "@kavo/core";
|
|
2
2
|
import type { GraphQLSchema } from "graphql";
|
|
3
|
-
import type {
|
|
4
|
-
/** The minimum a host framework needs to hand this package about one `@
|
|
5
|
-
export interface
|
|
3
|
+
import type { BoundKavoService } from "./schema.js";
|
|
4
|
+
/** The minimum a host framework needs to hand this package about one `@Kavo` entity. */
|
|
5
|
+
export interface KavoEntityRef {
|
|
6
6
|
readonly entity: ClassRef;
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
@@ -10,18 +10,18 @@ export interface CrudEntityRef {
|
|
|
10
10
|
* GraphQL types and put them all on one schema." Two things stay
|
|
11
11
|
* deliberately outside this package, supplied by the caller instead:
|
|
12
12
|
*
|
|
13
|
-
* - **How to enumerate `@
|
|
13
|
+
* - **How to enumerate `@Kavo` entities** — `@kavo/nest`'s `getKavoEntities()`,
|
|
14
14
|
* a plain array an Express/Fastify/Next.js app builds by hand, or any
|
|
15
15
|
* other host's own registry.
|
|
16
16
|
* - **How to resolve a bound service for one entity** — `@kavo/nest`'s
|
|
17
|
-
* `ModuleRef` + `
|
|
17
|
+
* `ModuleRef` + `getKavoServiceToken`, a plain `Map`, or whatever DI
|
|
18
18
|
* container that host uses.
|
|
19
19
|
*
|
|
20
20
|
* This function only ever touches `@kavo/core` shapes and this package's
|
|
21
21
|
* own type registry — never a host framework — so the same call works
|
|
22
|
-
* from `@kavo/nest`'s `
|
|
22
|
+
* from `@kavo/nest`'s `BaseKavoGraphQLController` today and from a future
|
|
23
23
|
* `@kavo/express`/`@kavo/fastify`/`@kavo/nextjs` binding without either
|
|
24
24
|
* package importing the other (ADR-0016).
|
|
25
25
|
*/
|
|
26
|
-
export declare function
|
|
26
|
+
export declare function resolveKavoGraphQLSchema(entities: readonly KavoEntityRef[], resolveService: (entity: ClassRef) => BoundKavoService<object, EntityId, unknown, unknown, unknown, unknown, unknown>): GraphQLSchema;
|
|
27
27
|
//# sourceMappingURL=discovery.d.ts.map
|
package/dist/discovery.js
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { mergeKavoGraphQLSchemas } from "./schema.js";
|
|
2
|
+
import { getKavoGraphQLTypes } from "./registry.js";
|
|
3
3
|
/**
|
|
4
4
|
* The host-agnostic half of "discover every entity that registered
|
|
5
5
|
* GraphQL types and put them all on one schema." Two things stay
|
|
6
6
|
* deliberately outside this package, supplied by the caller instead:
|
|
7
7
|
*
|
|
8
|
-
* - **How to enumerate `@
|
|
8
|
+
* - **How to enumerate `@Kavo` entities** — `@kavo/nest`'s `getKavoEntities()`,
|
|
9
9
|
* a plain array an Express/Fastify/Next.js app builds by hand, or any
|
|
10
10
|
* other host's own registry.
|
|
11
11
|
* - **How to resolve a bound service for one entity** — `@kavo/nest`'s
|
|
12
|
-
* `ModuleRef` + `
|
|
12
|
+
* `ModuleRef` + `getKavoServiceToken`, a plain `Map`, or whatever DI
|
|
13
13
|
* container that host uses.
|
|
14
14
|
*
|
|
15
15
|
* This function only ever touches `@kavo/core` shapes and this package's
|
|
16
16
|
* own type registry — never a host framework — so the same call works
|
|
17
|
-
* from `@kavo/nest`'s `
|
|
17
|
+
* from `@kavo/nest`'s `BaseKavoGraphQLController` today and from a future
|
|
18
18
|
* `@kavo/express`/`@kavo/fastify`/`@kavo/nextjs` binding without either
|
|
19
19
|
* package importing the other (ADR-0016).
|
|
20
20
|
*/
|
|
21
|
-
export function
|
|
21
|
+
export function resolveKavoGraphQLSchema(entities, resolveService) {
|
|
22
22
|
const bindings = [];
|
|
23
23
|
for (const { entity } of entities) {
|
|
24
|
-
const types =
|
|
24
|
+
const types = getKavoGraphQLTypes(entity);
|
|
25
25
|
if (types === undefined) {
|
|
26
26
|
continue;
|
|
27
27
|
}
|
|
28
28
|
bindings.push({ name: entity.name, service: resolveService(entity), ...types });
|
|
29
29
|
}
|
|
30
|
-
return
|
|
30
|
+
return mergeKavoGraphQLSchemas(bindings);
|
|
31
31
|
}
|
|
32
32
|
//# sourceMappingURL=discovery.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { createKavoGraphQLSchema, mergeKavoGraphQLSchemas, type KavoGraphQLOptions, type BoundKavoService, } from "./schema.js";
|
|
2
|
+
export { registerKavoGraphQLTypes, getKavoGraphQLTypes, type KavoGraphQLTypes } from "./registry.js";
|
|
3
|
+
export { resolveKavoGraphQLSchema, type KavoEntityRef } from "./discovery.js";
|
|
4
4
|
export { GraphQLJSON } from "./json-scalar.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
1
|
+
export { createKavoGraphQLSchema, mergeKavoGraphQLSchemas, } from "./schema.js";
|
|
2
|
+
export { registerKavoGraphQLTypes, getKavoGraphQLTypes } from "./registry.js";
|
|
3
|
+
export { resolveKavoGraphQLSchema } from "./discovery.js";
|
|
4
4
|
export { GraphQLJSON } from "./json-scalar.js";
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
package/dist/registry.d.ts
CHANGED
|
@@ -2,13 +2,13 @@ import type { ClassRef } from "@kavo/core";
|
|
|
2
2
|
import type { GraphQLInputObjectType, GraphQLObjectType } from "graphql";
|
|
3
3
|
/**
|
|
4
4
|
* GraphQL object/input types (and which mutations to expose) for one
|
|
5
|
-
* entity — the hand-written part `
|
|
6
|
-
* class. Each mutation flag/input mirrors `
|
|
5
|
+
* entity — the hand-written part `registerKavoGraphQLTypes` attaches to a
|
|
6
|
+
* class. Each mutation flag/input mirrors `KavoGraphQLOptions` in
|
|
7
7
|
* `schema.ts` one for one — omit any of them to leave that mutation off
|
|
8
|
-
* the schema for this entity, same opt-in shape `@
|
|
8
|
+
* the schema for this entity, same opt-in shape `@Kavo`'s own `operations`
|
|
9
9
|
* config uses on the REST side.
|
|
10
10
|
*/
|
|
11
|
-
export interface
|
|
11
|
+
export interface KavoGraphQLTypes {
|
|
12
12
|
readonly itemType: GraphQLObjectType;
|
|
13
13
|
/** Omit to leave the `create<Name>` mutation off the schema for this entity. */
|
|
14
14
|
readonly createInputType?: GraphQLInputObjectType;
|
|
@@ -25,14 +25,14 @@ export interface CrudGraphQLTypes {
|
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Attaches GraphQL types to an entity once, next to its DTOs — the
|
|
28
|
-
* counterpart of `@kavo/nest`'s `
|
|
29
|
-
* every `@
|
|
30
|
-
* schema with no per-entity list of its own (see `
|
|
28
|
+
* counterpart of `@kavo/nest`'s `getKavoEntities()`: a consumer can walk
|
|
29
|
+
* every `@Kavo` entity and look up its GraphQL types here, wiring a merged
|
|
30
|
+
* schema with no per-entity list of its own (see `resolveKavoGraphQLSchema`
|
|
31
31
|
* in `discovery.ts`, which does exactly that). An entity with no
|
|
32
32
|
* registration here simply has no GraphQL surface — opt-in, not implied by
|
|
33
|
-
* `@
|
|
33
|
+
* `@Kavo` alone. Process-wide, same scope as `@kavo/nest`'s own registry.
|
|
34
34
|
*/
|
|
35
|
-
export declare function
|
|
36
|
-
/** The types `
|
|
37
|
-
export declare function
|
|
35
|
+
export declare function registerKavoGraphQLTypes(entity: ClassRef, types: KavoGraphQLTypes): void;
|
|
36
|
+
/** The types `registerKavoGraphQLTypes` attached to `entity`, or `undefined` if it never registered any. */
|
|
37
|
+
export declare function getKavoGraphQLTypes(entity: ClassRef): KavoGraphQLTypes | undefined;
|
|
38
38
|
//# sourceMappingURL=registry.d.ts.map
|
package/dist/registry.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
const typeRegistry = new Map();
|
|
2
2
|
/**
|
|
3
3
|
* Attaches GraphQL types to an entity once, next to its DTOs — the
|
|
4
|
-
* counterpart of `@kavo/nest`'s `
|
|
5
|
-
* every `@
|
|
6
|
-
* schema with no per-entity list of its own (see `
|
|
4
|
+
* counterpart of `@kavo/nest`'s `getKavoEntities()`: a consumer can walk
|
|
5
|
+
* every `@Kavo` entity and look up its GraphQL types here, wiring a merged
|
|
6
|
+
* schema with no per-entity list of its own (see `resolveKavoGraphQLSchema`
|
|
7
7
|
* in `discovery.ts`, which does exactly that). An entity with no
|
|
8
8
|
* registration here simply has no GraphQL surface — opt-in, not implied by
|
|
9
|
-
* `@
|
|
9
|
+
* `@Kavo` alone. Process-wide, same scope as `@kavo/nest`'s own registry.
|
|
10
10
|
*/
|
|
11
|
-
export function
|
|
11
|
+
export function registerKavoGraphQLTypes(entity, types) {
|
|
12
12
|
typeRegistry.set(entity, types);
|
|
13
13
|
}
|
|
14
|
-
/** The types `
|
|
15
|
-
export function
|
|
14
|
+
/** The types `registerKavoGraphQLTypes` attached to `entity`, or `undefined` if it never registered any. */
|
|
15
|
+
export function getKavoGraphQLTypes(entity) {
|
|
16
16
|
return typeRegistry.get(entity);
|
|
17
17
|
}
|
|
18
18
|
//# sourceMappingURL=registry.js.map
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { GraphQLObjectType, GraphQLSchema, type GraphQLFieldConfig, type GraphQLInputObjectType } from "graphql";
|
|
2
|
-
import type {
|
|
2
|
+
import type { DefaultKavoService, EntityId } from "@kavo/core";
|
|
3
3
|
/**
|
|
4
4
|
* What a query/mutation resolver in this binding actually calls — the
|
|
5
5
|
* transport-agnostic programmatic surface `createCrud` returns. Kept as a
|
|
6
|
-
* structural type (not `
|
|
6
|
+
* structural type (not `DefaultKavoService` itself) so a caller only has to
|
|
7
7
|
* satisfy the handful of methods a schema actually wires up, the same way
|
|
8
8
|
* `@kavo/nest`'s standard-operation routes bind to it. Exported (not just
|
|
9
9
|
* internal) so `discovery.ts`'s host-agnostic resolver callback can name it.
|
|
@@ -11,12 +11,12 @@ import type { DefaultCrudService, EntityId } from "@kavo/core";
|
|
|
11
11
|
* Every standard operation is picked unconditionally — whether a given
|
|
12
12
|
* field actually reaches the schema is decided per entity by which
|
|
13
13
|
* `*InputType`/`include*` options `crudFields` receives, mirroring how
|
|
14
|
-
* `@
|
|
14
|
+
* `@Kavo`'s own `operations` config opts entities in or out on the REST
|
|
15
15
|
* side. Calling `restoreOne`/`purgeOne` against an entity that never
|
|
16
16
|
* declared soft delete still raises `OperationDisabledException` from the
|
|
17
17
|
* engine itself — this binding does not re-check that, same as REST.
|
|
18
18
|
*/
|
|
19
|
-
export type
|
|
19
|
+
export type BoundKavoService<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto> = Pick<DefaultKavoService<Entity, Id, CreateDto, UpdateDto, PatchDto, unknown, ItemDto, ListDto>, "findOne" | "findMany" | "createOne" | "updateOne" | "patchOne" | "deleteOne" | "restoreOne" | "purgeOne">;
|
|
20
20
|
/**
|
|
21
21
|
* One entity's GraphQL binding: a query root (`<name>`/`<name>s`) plus
|
|
22
22
|
* whichever mutations its options ask for — every resolver a direct call
|
|
@@ -25,10 +25,10 @@ export type BoundCrudService<Entity extends object, Id extends EntityId, CreateD
|
|
|
25
25
|
* that field never reaches the schema, the same "declare what you want"
|
|
26
26
|
* shape `createInputType` already had.
|
|
27
27
|
*/
|
|
28
|
-
export interface
|
|
28
|
+
export interface KavoGraphQLOptions<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto> {
|
|
29
29
|
/** Singular, capitalized entity name — becomes `Query.<lowerName>` / `<Name>List` / `createName` / etc. */
|
|
30
30
|
readonly name: string;
|
|
31
|
-
readonly service:
|
|
31
|
+
readonly service: BoundKavoService<Entity, Id, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>;
|
|
32
32
|
readonly itemType: GraphQLObjectType;
|
|
33
33
|
/** Omit to leave the `create<Name>` mutation off the schema. */
|
|
34
34
|
readonly createInputType?: GraphQLInputObjectType;
|
|
@@ -44,12 +44,12 @@ export interface CrudGraphQLOptions<Entity extends object, Id extends EntityId,
|
|
|
44
44
|
readonly purgeOne?: boolean;
|
|
45
45
|
}
|
|
46
46
|
/**
|
|
47
|
-
* Field maps for one entity's binding — the unit `
|
|
48
|
-
* wraps and `
|
|
47
|
+
* Field maps for one entity's binding — the unit `createKavoGraphQLSchema`
|
|
48
|
+
* wraps and `mergeKavoGraphQLSchemas`/`resolveKavoGraphQLSchema` combine.
|
|
49
49
|
* Not exported from the barrel: an internal building block, same status as
|
|
50
50
|
* `lowerFirst`.
|
|
51
51
|
*/
|
|
52
|
-
export declare function crudFields<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>(options:
|
|
52
|
+
export declare function crudFields<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>(options: KavoGraphQLOptions<Entity, Id, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>): {
|
|
53
53
|
query: Record<string, GraphQLFieldConfig<unknown, unknown>>;
|
|
54
54
|
mutation: Record<string, GraphQLFieldConfig<unknown, unknown>>;
|
|
55
55
|
};
|
|
@@ -61,18 +61,18 @@ export declare function crudFields<Entity extends object, Id extends EntityId, C
|
|
|
61
61
|
* resolver delegates straight to the bound service, which itself is sugar
|
|
62
62
|
* over `engine.execute` — the identical pipeline REST runs.
|
|
63
63
|
*
|
|
64
|
-
* For an app with more than one entity, prefer `
|
|
65
|
-
* `
|
|
64
|
+
* For an app with more than one entity, prefer `mergeKavoGraphQLSchemas` (or
|
|
65
|
+
* `resolveKavoGraphQLSchema` for a framework-driven registry) — they put
|
|
66
66
|
* every entity's fields on one `Query`/`Mutation` root instead of one
|
|
67
67
|
* schema (and one mounted endpoint) per entity.
|
|
68
68
|
*/
|
|
69
|
-
export declare function
|
|
69
|
+
export declare function createKavoGraphQLSchema<Entity extends object, Id extends EntityId, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>(options: KavoGraphQLOptions<Entity, Id, CreateDto, UpdateDto, PatchDto, ItemDto, ListDto>): GraphQLSchema;
|
|
70
70
|
/**
|
|
71
71
|
* Combines several entities' bindings onto one `Query`/`Mutation` root —
|
|
72
72
|
* the shape an app actually wants: one `/graphql` endpoint for every
|
|
73
|
-
* `@
|
|
74
|
-
* `
|
|
73
|
+
* `@Kavo` entity, not one per entity. Each entry is the same options shape
|
|
74
|
+
* `createKavoGraphQLSchema` takes; field names are namespaced by each
|
|
75
75
|
* entity's own `name`, so entries never collide with each other.
|
|
76
76
|
*/
|
|
77
|
-
export declare function
|
|
77
|
+
export declare function mergeKavoGraphQLSchemas(bindings: readonly KavoGraphQLOptions<object, EntityId, unknown, unknown, unknown, unknown, unknown>[]): GraphQLSchema;
|
|
78
78
|
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.js
CHANGED
|
@@ -18,8 +18,8 @@ function lowerFirst(value) {
|
|
|
18
18
|
return value.charAt(0).toLowerCase() + value.slice(1);
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
|
-
* Field maps for one entity's binding — the unit `
|
|
22
|
-
* wraps and `
|
|
21
|
+
* Field maps for one entity's binding — the unit `createKavoGraphQLSchema`
|
|
22
|
+
* wraps and `mergeKavoGraphQLSchemas`/`resolveKavoGraphQLSchema` combine.
|
|
23
23
|
* Not exported from the barrel: an internal building block, same status as
|
|
24
24
|
* `lowerFirst`.
|
|
25
25
|
*/
|
|
@@ -117,12 +117,12 @@ export function crudFields(options) {
|
|
|
117
117
|
* resolver delegates straight to the bound service, which itself is sugar
|
|
118
118
|
* over `engine.execute` — the identical pipeline REST runs.
|
|
119
119
|
*
|
|
120
|
-
* For an app with more than one entity, prefer `
|
|
121
|
-
* `
|
|
120
|
+
* For an app with more than one entity, prefer `mergeKavoGraphQLSchemas` (or
|
|
121
|
+
* `resolveKavoGraphQLSchema` for a framework-driven registry) — they put
|
|
122
122
|
* every entity's fields on one `Query`/`Mutation` root instead of one
|
|
123
123
|
* schema (and one mounted endpoint) per entity.
|
|
124
124
|
*/
|
|
125
|
-
export function
|
|
125
|
+
export function createKavoGraphQLSchema(options) {
|
|
126
126
|
const { query, mutation } = crudFields(options);
|
|
127
127
|
return new GraphQLSchema({
|
|
128
128
|
query: new GraphQLObjectType({ name: "Query", fields: query }),
|
|
@@ -132,11 +132,11 @@ export function createCrudGraphQLSchema(options) {
|
|
|
132
132
|
/**
|
|
133
133
|
* Combines several entities' bindings onto one `Query`/`Mutation` root —
|
|
134
134
|
* the shape an app actually wants: one `/graphql` endpoint for every
|
|
135
|
-
* `@
|
|
136
|
-
* `
|
|
135
|
+
* `@Kavo` entity, not one per entity. Each entry is the same options shape
|
|
136
|
+
* `createKavoGraphQLSchema` takes; field names are namespaced by each
|
|
137
137
|
* entity's own `name`, so entries never collide with each other.
|
|
138
138
|
*/
|
|
139
|
-
export function
|
|
139
|
+
export function mergeKavoGraphQLSchemas(bindings) {
|
|
140
140
|
const query = {};
|
|
141
141
|
const mutation = {};
|
|
142
142
|
for (const binding of bindings) {
|
|
@@ -149,10 +149,10 @@ export function mergeCrudGraphQLSchemas(bindings) {
|
|
|
149
149
|
// or more fields.`) — graphql-js would only report that cryptically, on
|
|
150
150
|
// the first request, deep inside `graphql()`'s own schema validation.
|
|
151
151
|
// Failing fast here, at schema-build time, with a message that names the
|
|
152
|
-
// actual fix, is what `
|
|
152
|
+
// actual fix, is what `resolveKavoGraphQLSchema` (zero entities
|
|
153
153
|
// discovered) relies on to fail at boot instead of at request time.
|
|
154
|
-
throw new ConfigurationException("GraphQLSchema", "bindings", "no entity registered any GraphQL types — call
|
|
155
|
-
"for at least one @
|
|
154
|
+
throw new ConfigurationException("GraphQLSchema", "bindings", "no entity registered any GraphQL types — call registerKavoGraphQLTypes(Entity, {...}) " +
|
|
155
|
+
"for at least one @Kavo entity before enabling a GraphQL endpoint");
|
|
156
156
|
}
|
|
157
157
|
return new GraphQLSchema({
|
|
158
158
|
query: new GraphQLObjectType({ name: "Query", fields: query }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kavo/graphql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Kavo GraphQL binding — builds a GraphQL schema over a createCrud service, delegating every resolver to the same engine REST uses.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
|
-
"scripts": {
|
|
27
|
-
"build": "tsc -b"
|
|
28
|
-
},
|
|
29
26
|
"dependencies": {
|
|
30
|
-
"@kavo/core": "
|
|
27
|
+
"@kavo/core": "^0.6.0"
|
|
31
28
|
},
|
|
32
29
|
"peerDependencies": {
|
|
33
30
|
"graphql": "^17.0.0"
|
|
34
31
|
},
|
|
35
32
|
"devDependencies": {
|
|
36
33
|
"graphql": "^17.0.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -b"
|
|
37
37
|
}
|
|
38
|
-
}
|
|
38
|
+
}
|