@webda/graphql 4.0.0-beta.6 → 4.0.0-beta.8

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.
@@ -0,0 +1,221 @@
1
+ import { AsyncQueue, HttpContext, Session, StreamingOperationContext, WebdaError, getOperationStreaming, toPublicChunk } from "@webda/core";
2
+ import { operationError } from "./mutations.js";
3
+ /** Operations the model schema already serves (X, Xs, createX, updateX, deleteX) */
4
+ export const CRUD_METHODS = new Set([
5
+ "modelCreate",
6
+ "modelUpdate",
7
+ "modelPatch",
8
+ "modelDelete",
9
+ "modelGet",
10
+ "modelQuery"
11
+ ]);
12
+ /** A valid GraphQL name */
13
+ export const GRAPHQL_NAME = /^[_A-Za-z][_0-9A-Za-z]*$/;
14
+ /** Streamed chunks waiting for the subscriber above which the operation waits */
15
+ const HIGH_WATER = 16;
16
+ /**
17
+ * @param id - operation id
18
+ * @returns its PascalCase name without dots (`TaskService.Summary` → `TaskServiceSummary`)
19
+ */
20
+ export function operationTypeName(id) {
21
+ return id
22
+ .split(".")
23
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
24
+ .join("");
25
+ }
26
+ /**
27
+ * @param id - operation id
28
+ * @returns its GraphQL field name (`TaskService.Summary` → `taskServiceSummary`)
29
+ */
30
+ export function operationFieldName(id) {
31
+ const name = operationTypeName(id);
32
+ return name.charAt(0).toLowerCase() + name.slice(1);
33
+ }
34
+ /**
35
+ * @param op - operation
36
+ * @returns true when it only reads (REST GET, or MCP readOnly)
37
+ */
38
+ export function isReadOnlyOperation(op) {
39
+ return ((typeof op.rest === "object" && op.rest?.method?.toLowerCase() === "get") ||
40
+ (typeof op.mcp === "object" && op.mcp?.readOnly === true));
41
+ }
42
+ /**
43
+ * Where an operation is exposed in GraphQL
44
+ * @param id - operation id
45
+ * @param op - operation
46
+ * @returns its placement, undefined when GraphQL does not expose it
47
+ * @throws Error when an explicit placement does not match the streaming mode
48
+ */
49
+ export function graphqlPlacement(id, op) {
50
+ if (op.hidden || op.graphql === false || CRUD_METHODS.has(op.method)) {
51
+ return undefined;
52
+ }
53
+ const streaming = getOperationStreaming(op);
54
+ if (streaming === "client" || streaming === "bidi") {
55
+ return undefined;
56
+ }
57
+ const explicit = typeof op.graphql === "object" ? op.graphql : undefined;
58
+ const forced = explicit?.subscription
59
+ ? { kind: "subscription", name: explicit.subscription }
60
+ : explicit?.query
61
+ ? { kind: "query", name: explicit.query }
62
+ : explicit?.mutation
63
+ ? { kind: "mutation", name: explicit.mutation }
64
+ : undefined;
65
+ if (forced && (forced.kind === "subscription") !== (streaming === "server")) {
66
+ throw new Error(`Operation ${id}: graphql.${forced.kind} does not match its streaming mode (${streaming}); a server-streaming operation is a subscription, the others a query or a mutation`);
67
+ }
68
+ if (forced) {
69
+ return forced;
70
+ }
71
+ if (streaming === "server") {
72
+ return { kind: "subscription", name: operationFieldName(id) };
73
+ }
74
+ return { kind: isReadOnlyOperation(op) ? "query" : "mutation", name: operationFieldName(id) };
75
+ }
76
+ /**
77
+ * A value as clients may see it: plain JSON without `__` keys
78
+ * @param value - an operation result or chunk
79
+ * @returns the copy (null for undefined)
80
+ */
81
+ export function publicCopy(value) {
82
+ return value === undefined ? null : toPublicChunk(value);
83
+ }
84
+ /**
85
+ * The context of an operation called from GraphQL: the GraphQL request's session and headers, the field arguments as
86
+ * input; a non-streamed result is kept as is (`result`), streamed chunks are queued for the subscription.
87
+ */
88
+ export class GraphQLOperationContext extends StreamingOperationContext {
89
+ /**
90
+ * @param parent - the GraphQL request context
91
+ * @param input - the operation input (from the field arguments)
92
+ * @param transform - turns a streamed chunk into what the subscriber receives
93
+ */
94
+ constructor(parent, input, transform = publicCopy) {
95
+ super(parent.getHttpContext?.() ?? new HttpContext("localhost", "POST", "/graphql"));
96
+ this.transform = transform;
97
+ this.queue = new AsyncQueue();
98
+ this.pending = 0;
99
+ this.wakers = [];
100
+ this.finished = false;
101
+ this.setSession(parent.getSession() ?? new Session());
102
+ this.message = Buffer.from(input === undefined ? "" : JSON.stringify(input));
103
+ }
104
+ /**
105
+ * The session comes from the GraphQL request, already loaded
106
+ * @override
107
+ */
108
+ async init(_force = false) {
109
+ return this;
110
+ }
111
+ /**
112
+ * @override
113
+ */
114
+ async getRawInput(limit = 10 * 1024 * 1024, _timeout = 60000) {
115
+ return this.message.subarray(0, limit);
116
+ }
117
+ /**
118
+ * @override
119
+ */
120
+ async getRawInputAsString(limit = 10 * 1024 * 1024, _timeout = 60000, encoding) {
121
+ return this.message.subarray(0, limit).toString(encoding || "utf8");
122
+ }
123
+ /**
124
+ * No connection: the subscriber leaving is signalled by cancel()
125
+ * @override
126
+ */
127
+ get connectionEnded() {
128
+ return false;
129
+ }
130
+ /**
131
+ * A non-streamed result is kept as is
132
+ * @override
133
+ */
134
+ writeResult(output) {
135
+ this.result = output;
136
+ return true;
137
+ }
138
+ /**
139
+ * Streamed chunks are queued for the subscriber
140
+ * @override
141
+ * @throws OperationCancelledError when the stream is over
142
+ */
143
+ sendChunk(chunk) {
144
+ if (this.finished)
145
+ throw new WebdaError.OperationCancelledError();
146
+ this.queue.push(this.transform(chunk));
147
+ this.pending++;
148
+ return this.pending < HIGH_WATER;
149
+ }
150
+ /**
151
+ * Wait for the subscriber to consume the queued chunks (or to leave)
152
+ * @override
153
+ */
154
+ async waitForDrain() {
155
+ while (!this.isCancelled && this.pending >= HIGH_WATER) {
156
+ await new Promise(resolve => this.wakers.push(resolve));
157
+ }
158
+ }
159
+ /** The subscriber left: the next write or drain throws, the iterator ends. */
160
+ cancel() {
161
+ super.cancel();
162
+ this.queue.end(true);
163
+ this.wake();
164
+ }
165
+ /** The operation completed. */
166
+ finish() {
167
+ this.finished = true;
168
+ this.queue.end();
169
+ }
170
+ /**
171
+ * The operation failed: the subscriber gets the error after the chunks already queued, unless it already left
172
+ * @param error - what the operation threw (mapped like a query error: unexpected ones are hidden)
173
+ */
174
+ fail(error) {
175
+ this.finished = true;
176
+ if (this.isCancelled && error instanceof WebdaError.OperationCancelledError) {
177
+ // The expected end of an operation whose subscriber left
178
+ this.queue.end();
179
+ return;
180
+ }
181
+ // Any other error is mapped (and logged when unexpected) even if nobody listens anymore
182
+ const mapped = operationError(error);
183
+ if (!this.isCancelled) {
184
+ this.failure = mapped;
185
+ }
186
+ this.queue.end();
187
+ }
188
+ /**
189
+ * @returns the chunks, for a subscription field (return() cancels the operation)
190
+ */
191
+ chunks() {
192
+ const iterator = {
193
+ next: async () => {
194
+ const item = await this.queue.next();
195
+ if (item.done) {
196
+ if (this.failure !== undefined) {
197
+ const failure = this.failure;
198
+ this.failure = undefined;
199
+ throw failure;
200
+ }
201
+ return item;
202
+ }
203
+ this.pending--;
204
+ this.wake();
205
+ return item;
206
+ },
207
+ return: async () => {
208
+ this.cancel();
209
+ return { value: undefined, done: true };
210
+ },
211
+ [Symbol.asyncIterator]: () => iterator
212
+ };
213
+ return iterator;
214
+ }
215
+ /** Lets a waiting drained() check again */
216
+ wake() {
217
+ for (const waker of this.wakers.splice(0))
218
+ waker();
219
+ }
220
+ }
221
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"any.d.ts","sourceRoot":"","sources":["../../src/types/any.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAQ,MAAM,SAAS,CAAC;AAWlD,eAAO,MAAM,aAAa,6BAexB,CAAC"}
1
+ {"version":3,"file":"any.d.ts","sourceRoot":"","sources":["../../src/types/any.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAA6B,MAAM,SAAS,CAAC;AA4BvE,eAAO,MAAM,aAAa,6BAOxB,CAAC"}
package/lib/types/any.js CHANGED
@@ -1,26 +1,34 @@
1
- import { GraphQLScalarType, Kind } from "graphql";
1
+ import { GraphQLScalarType, Kind, valueFromASTUntyped } from "graphql";
2
2
  /**
3
- * Coerce an arbitrary value into an object — parses JSON strings, passes objects through
4
- * @param value - value to coerce
5
- * @returns parsed object, the value itself if already an object, or null
3
+ * Read a string as JSON when it looks like a JSON object or array
4
+ * @param value - the string
5
+ * @returns the parsed value, or the string itself
6
6
  */
7
- function coerceAny(value) {
8
- return typeof value === "object" ? value : typeof value === "string" ? JSON.parse(value) : null;
7
+ function fromJSONString(value) {
8
+ const text = value.trim();
9
+ if (!text.startsWith("{") && !text.startsWith("[")) {
10
+ return value;
11
+ }
12
+ try {
13
+ return JSON.parse(text);
14
+ }
15
+ catch {
16
+ return value;
17
+ }
18
+ }
19
+ /**
20
+ * Values pass through unchanged (objects, arrays, numbers, booleans, strings)
21
+ * @param value - value to pass
22
+ * @returns the value, null for undefined
23
+ */
24
+ function passThrough(value) {
25
+ return value === undefined ? null : value;
9
26
  }
10
27
  export const AnyScalarType = new GraphQLScalarType({
11
28
  name: "Object",
12
- description: "Arbitrary object",
13
- parseValue: coerceAny,
14
- serialize: coerceAny,
15
- parseLiteral: ast => {
16
- switch (ast.kind) {
17
- case Kind.STRING:
18
- return JSON.parse(ast.value);
19
- case Kind.OBJECT:
20
- throw new Error(`Not sure what to do with OBJECT for ObjectScalarType`);
21
- default:
22
- return null;
23
- }
24
- }
29
+ description: "Arbitrary value: object, array, number, boolean or string",
30
+ parseValue: passThrough,
31
+ serialize: passThrough,
32
+ parseLiteral: (ast, variables) => ast.kind === Kind.STRING ? fromJSONString(ast.value) : valueFromASTUntyped(ast, variables)
25
33
  });
26
34
  //# sourceMappingURL=any.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"any.js","sourceRoot":"","sources":["../../src/types/any.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAElD;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAAU;IAC3B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClG,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,iBAAiB,CAAC;IACjD,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,kBAAkB;IAC/B,UAAU,EAAE,SAAS;IACrB,SAAS,EAAE,SAAS;IACpB,YAAY,EAAE,GAAG,CAAC,EAAE;QAClB,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,IAAI,CAAC,MAAM;gBACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,IAAI,CAAC,MAAM;gBACd,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAC1E;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"any.js","sourceRoot":"","sources":["../../src/types/any.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEvE;;;;GAIG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,KAAU;IAC7B,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AAC5C,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,iBAAiB,CAAC;IACjD,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,2DAA2D;IACxE,UAAU,EAAE,WAAW;IACvB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAC/B,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,GAAG,EAAE,SAAS,CAAC;CAC7F,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/types/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAQ,MAAM,SAAS,CAAC;AAElD,eAAO,MAAM,UAAU,iCAuBrB,CAAC"}
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/types/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAQ,MAAM,SAAS,CAAC;AAElD,eAAO,MAAM,UAAU,iCAyBrB,CAAC"}
package/lib/types/date.js CHANGED
@@ -3,8 +3,10 @@ export const DateScalar = new GraphQLScalarType({
3
3
  name: "Date",
4
4
  description: "Date custom scalar type",
5
5
  serialize(value) {
6
- if (value instanceof Date) {
7
- return value.toISOString(); // Convert outgoing Date to integer for JSON
6
+ // Stores serializing to JSON return dates as ISO strings or timestamps
7
+ const date = typeof value === "string" || typeof value === "number" ? new Date(value) : value;
8
+ if (date instanceof Date && !isNaN(date.getTime())) {
9
+ return date.toISOString();
8
10
  }
9
11
  throw Error("GraphQL Date Scalar serializer expected a `Date` object");
10
12
  },
@@ -1 +1 @@
1
- {"version":3,"file":"date.js","sourceRoot":"","sources":["../../src/types/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC;IAC9C,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,yBAAyB;IACtC,SAAS,CAAC,KAAK;QACb,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,4CAA4C;QAC1E,CAAC;QACD,MAAM,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IACD,UAAU,CAAC,KAAK;QACd,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,mCAAmC;QAC7D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,YAAY,CAAC,GAAG;QACd,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,4DAA4D;YAC5D,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"date.js","sourceRoot":"","sources":["../../src/types/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,iBAAiB,CAAC;IAC9C,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,yBAAyB;IACtC,SAAS,CAAC,KAAK;QACb,uEAAuE;QACvE,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAC9F,IAAI,IAAI,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YACnD,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC;QAC5B,CAAC;QACD,MAAM,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzE,CAAC;IACD,UAAU,CAAC,KAAK;QACd,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,mCAAmC;QAC7D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,YAAY,CAAC,GAAG;QACd,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,4DAA4D;YAC5D,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webda/graphql",
3
- "version": "4.0.0-beta.6",
3
+ "version": "4.0.0-beta.8",
4
4
  "description": "GraphQL endpoint for your Webda Application",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -18,12 +18,15 @@
18
18
  "graphql-ws": "^6.0.8",
19
19
  "json-schema": "^0.4.0",
20
20
  "ws": "^8.20.0",
21
- "@webda/runtime": "4.0.0-beta.6",
22
- "@webda/core": "4.0.0-beta.6",
23
- "@webda/ql": "4.0.0-beta.6"
21
+ "@webda/core": "4.0.0-beta.8",
22
+ "@webda/utils": "4.0.0-beta.8",
23
+ "@webda/workout": "4.0.0-beta.5",
24
+ "@webda/runtime": "4.0.0-beta.8",
25
+ "@webda/ql": "4.0.0-beta.7"
24
26
  },
25
27
  "devDependencies": {
26
28
  "@types/node": "25.5.0",
29
+ "@vitest/coverage-v8": "^4.1.2",
27
30
  "c8": "^11.0.0",
28
31
  "glob": "^13.0.6",
29
32
  "js-beautify": "^1.15.4",
@@ -32,7 +35,9 @@
32
35
  "skott": "^0.35.8",
33
36
  "source-map-support": "^0.5.21",
34
37
  "vite": "^6.0.0",
35
- "@webda/compiler": "^4.0.0-beta.6"
38
+ "vitest": "^4.0.0",
39
+ "@webda/compiler": "^4.0.0-beta.8",
40
+ "@webda/test": "^4.0.0-beta.7"
36
41
  },
37
42
  "webda": {
38
43
  "namespace": "Webda"
@@ -59,7 +64,7 @@
59
64
  "scripts": {
60
65
  "build": "webdac build",
61
66
  "pretest": "npm run build",
62
- "test": "echo 'Tests disabled — spec files need migration from @testdeck/mocha to @webda/test'",
67
+ "test": "vitest run",
63
68
  "new-model": "webda init webda:model",
64
69
  "new-service": "webda init webda:service",
65
70
  "lint": "eslint",
package/webda.module.json CHANGED
@@ -20,6 +20,16 @@
20
20
  "description": "Expose current user in the context with me",
21
21
  "type": "boolean"
22
22
  },
23
+ "exposeOperations": {
24
+ "default": [
25
+ "*"
26
+ ],
27
+ "description": "Operations exposed as GraphQL fields next to the model schema, with the operation transports' patterns:\n`\"*\"`, `\"Service.*\"`, an exact id, `\"!Id\"` to exclude; `[]` exposes no operation",
28
+ "items": {
29
+ "type": "string"
30
+ },
31
+ "type": "array"
32
+ },
23
33
  "globalSubscription": {
24
34
  "default": false,
25
35
  "description": "Expose a aggregation of all available subscriptions",