@nifrajs/graphql 4.0.0 → 5.0.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/pubsub.js CHANGED
@@ -9,8 +9,23 @@
9
9
  * `{ publish, subscribe }` shape over your bus and pass it in. Keeping only the in-memory impl here is
10
10
  * the guardrail - a durable payload-carrying sink does not belong in a public package.
11
11
  */
12
- /** Create an in-memory {@link GraphqlPubSub}. */
13
- export function createPubSub() {
12
+ export class GraphqlPubSubOverflowError extends Error {
13
+ code = "graphql_pubsub_overflow";
14
+ constructor() {
15
+ super("GraphQL subscription event queue is full");
16
+ this.name = "GraphqlPubSubOverflowError";
17
+ }
18
+ }
19
+ /** Create an in-memory {@link GraphqlPubSub} with finite subscriber queues. */
20
+ export function createPubSub(options = {}) {
21
+ const maxQueuedEvents = options.maxQueuedEvents ?? 1024;
22
+ const overflow = options.overflow ?? "error";
23
+ if (!Number.isSafeInteger(maxQueuedEvents) || maxQueuedEvents < 1) {
24
+ throw new RangeError("createPubSub maxQueuedEvents must be a positive safe integer");
25
+ }
26
+ if (overflow !== "error" && overflow !== "drop-oldest" && overflow !== "drop-newest") {
27
+ throw new TypeError("createPubSub overflow must be error, drop-oldest or drop-newest");
28
+ }
14
29
  const topics = new Map();
15
30
  const publish = (topic, payload) => {
16
31
  const sinks = topics.get(topic);
@@ -26,7 +41,7 @@ export function createPubSub() {
26
41
  topics.set(topic, sinks);
27
42
  }
28
43
  const set = sinks;
29
- const sink = createSink(() => {
44
+ const sink = createSink(maxQueuedEvents, overflow, () => {
30
45
  set.delete(sink);
31
46
  if (set.size === 0)
32
47
  topics.delete(topic);
@@ -36,10 +51,11 @@ export function createPubSub() {
36
51
  };
37
52
  return { publish, subscribe };
38
53
  }
39
- function createSink(onClose) {
54
+ function createSink(maxQueuedEvents, overflow, onClose) {
40
55
  const queue = [];
41
56
  const pulls = [];
42
57
  let done = false;
58
+ let failure;
43
59
  const push = (payload) => {
44
60
  if (done)
45
61
  return;
@@ -48,11 +64,22 @@ function createSink(onClose) {
48
64
  pull({ value: payload, done: false });
49
65
  return;
50
66
  }
67
+ if (queue.length >= maxQueuedEvents) {
68
+ if (overflow === "drop-newest")
69
+ return;
70
+ if (overflow === "error") {
71
+ failure = new GraphqlPubSubOverflowError();
72
+ finish();
73
+ return;
74
+ }
75
+ queue.shift();
76
+ }
51
77
  queue.push(payload);
52
78
  };
53
79
  const finish = () => {
54
80
  if (!done) {
55
81
  done = true;
82
+ queue.length = 0;
56
83
  onClose();
57
84
  for (const pull of pulls.splice(0))
58
85
  pull({ value: undefined, done: true });
@@ -61,16 +88,24 @@ function createSink(onClose) {
61
88
  };
62
89
  const iterator = {
63
90
  next() {
64
- if (queue.length > 0)
65
- return Promise.resolve({ value: queue.shift(), done: false });
91
+ if (failure !== undefined) {
92
+ const error = failure;
93
+ failure = undefined;
94
+ return Promise.reject(error);
95
+ }
66
96
  if (done)
67
97
  return Promise.resolve({ value: undefined, done: true });
98
+ // biome-ignore lint/plugin/requireSafetyCommentForTypeAssertion: a nonempty queue owns one Event; undefined is itself a valid Event payload.
99
+ if (queue.length > 0)
100
+ return Promise.resolve({ value: queue.shift(), done: false });
68
101
  return new Promise((resolve) => pulls.push(resolve));
69
102
  },
70
103
  return() {
104
+ failure = undefined;
71
105
  return Promise.resolve(finish());
72
106
  },
73
107
  throw(err) {
108
+ failure = undefined;
74
109
  finish();
75
110
  return Promise.reject(err);
76
111
  },
@@ -1 +1 @@
1
- {"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../src/pubsub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,iDAAiD;AACjD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAA;IAElD,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,OAAc,EAAQ,EAAE;QACtD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,KAAK,KAAK,SAAS;YAAE,OAAM;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC9C,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,CAAC,KAAa,EAAgC,EAAE;QAChE,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG,IAAI,GAAG,EAAE,CAAA;YACjB,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC1B,CAAC;QACD,MAAM,GAAG,GAAG,KAAK,CAAA;QACjB,MAAM,IAAI,GAAG,UAAU,CAAQ,GAAG,EAAE;YAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YAChB,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;gBAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACb,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC,CAAA;IAED,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;AAC/B,CAAC;AAQD,SAAS,UAAU,CAAQ,OAAmB;IAC5C,MAAM,KAAK,GAAY,EAAE,CAAA;IACzB,MAAM,KAAK,GAAmD,EAAE,CAAA;IAChE,IAAI,IAAI,GAAG,KAAK,CAAA;IAEhB,MAAM,IAAI,GAAG,CAAC,OAAc,EAAQ,EAAE;QACpC,IAAI,IAAI;YAAE,OAAM;QAChB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;QAC1B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YACrC,OAAM;QACR,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACrB,CAAC,CAAA;IAED,MAAM,MAAM,GAAG,GAA0B,EAAE;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,CAAA;YACX,OAAO,EAAE,CAAA;YACT,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5E,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;IACzC,CAAC,CAAA;IAED,MAAM,QAAQ,GAAiC;QAC7C,IAAI;YACF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAW,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAC5F,IAAI,IAAI;gBAAE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;YAClE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA;QACtD,CAAC;QACD,MAAM;YACJ,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;QAClC,CAAC;QACD,KAAK,CAAC,GAAa;YACjB,MAAM,EAAE,CAAA;YACR,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC5B,CAAC;QACD,CAAC,MAAM,CAAC,aAAa,CAAC;YACpB,OAAO,IAAI,CAAA;QACb,CAAC;KACF,CAAA;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;AAC3B,CAAC"}
1
+ {"version":3,"file":"pubsub.js","sourceRoot":"","sources":["../src/pubsub.ts"],"names":[],"mappings":"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"}
package/dist/ws.d.ts CHANGED
@@ -24,12 +24,21 @@ interface GraphqlWsConnection {
24
24
  /** Tear the graphql-ws connection down (graphql-ws's `opened()` return value). */
25
25
  closed?: (code: number, reason: string) => void | Promise<void>;
26
26
  readonly subscriptions: Set<string>;
27
+ /** One abort controller per running operation id, aborted by the client's complete or a close. */
28
+ operations?: Map<string, AbortController>;
29
+ /** Set once graphql-ws sends `connection_ack`, i.e. `connection_init` was admitted. */
30
+ acknowledged?: boolean;
27
31
  }
28
32
  export interface GraphqlWsOptions<Context extends Record<string, unknown> = Record<string, unknown>> {
29
33
  /** The executable schema. */
30
34
  readonly schema: GraphQLSchema;
31
35
  /** Build the resolver `contextValue` from the upgrade request. Shared with the HTTP transport. */
32
36
  readonly context?: GraphqlContextBuilder<Context>;
37
+ /**
38
+ * Admit a socket from its upgrade request, before {@link onConnect}; return `false` (or throw) to
39
+ * reject the connection. `mountGraphql({ subscriptions: true })` passes its HTTP `authorize` here.
40
+ */
41
+ readonly authorize?: (request: Request) => boolean | Promise<boolean>;
33
42
  /**
34
43
  * Called once per connection with the client's `connection_init` payload; return `false` (or throw)
35
44
  * to reject the connection. The seam for authenticating a socket from an init token.
@@ -44,9 +53,14 @@ export interface GraphqlWsOptions<Context extends Record<string, unknown> = Reco
44
53
  readonly maxAliases?: number;
45
54
  readonly maxComplexity?: number;
46
55
  readonly maxOperations?: number;
56
+ readonly maxFieldOverlaps?: number;
47
57
  /** Maximum concurrent subscription operation ids per connection. Default 20. */
48
58
  readonly maxSubscriptions?: number;
49
- /** Maximum time for initial execute/subscribe setup. Default 10 seconds. */
59
+ /**
60
+ * Maximum time for initial execute/subscribe setup. Default 10 seconds. Each operation's abort
61
+ * signal, which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline, when
62
+ * the client completes the operation, and when the socket closes.
63
+ */
50
64
  readonly executionTimeoutMs?: number;
51
65
  }
52
66
  /**
package/dist/ws.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAoC,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EAKL,KAAK,aAAa,EAKnB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,KAAK,qBAAqB,EAI1B,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAgB,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAA;AASvE,2EAA2E;AAC3E,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,kFAAkF;IAClF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,gBAAgB,CAC/B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEjE,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,kGAAkG;IAClG,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IACjD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CACnB,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,EACzC,OAAO,EAAE,OAAO,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/C,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AA4HD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChG,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,GACjC,gBAAgB,CAAC,mBAAmB,CAAC,CAsHvC"}
1
+ {"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAoC,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAC1F,OAAO,EAML,KAAK,aAAa,EAKnB,MAAM,SAAS,CAAA;AAChB,OAAO,EACL,KAAK,qBAAqB,EAI1B,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AACnB,OAAO,EAAgB,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAUvE,2EAA2E;AAC3E,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,kFAAkF;IAClF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACnC,kGAAkG;IAClG,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACzC,uFAAuF;IACvF,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAQD,MAAM,WAAW,gBAAgB,CAC/B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAEjE,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,kGAAkG;IAClG,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAA;IACjD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACrE;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CACnB,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC,EACzC,OAAO,EAAE,OAAO,KACb,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;IAC/C,0DAA0D;IAC1D,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,gFAAgF;IAChF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAA;CACrC;AA0KD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChG,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,GACjC,gBAAgB,CAAC,mBAAmB,CAAC,CAmKvC"}
package/dist/ws.js CHANGED
@@ -15,7 +15,7 @@
15
15
  import { execute, GraphQLError, parse, specifiedRules, subscribe, validate, } from "graphql";
16
16
  import { GRAPHQL_TRANSPORT_WS_PROTOCOL, makeServer, } from "graphql-ws";
17
17
  import { buildContext } from "./context.js";
18
- import { documentLimitError, documentMetrics, graphqlLimits, requestLimitError, } from "./limits.js";
18
+ import { documentLimitError, documentMetrics, graphqlLimits, overlapLimitError, requestLimitError, } from "./limits.js";
19
19
  /** A frame is a string for JSON control messages; graphql-ws only speaks text frames. */
20
20
  function asText(data) {
21
21
  return typeof data === "string" ? data : new TextDecoder().decode(data);
@@ -64,11 +64,13 @@ function subscriptionFrameError(message, schema, limits) {
64
64
  catch (error) {
65
65
  return { id, message: error instanceof GraphQLError ? error.message : "Invalid GraphQL query." };
66
66
  }
67
+ const limitError = documentLimitError(documentMetrics(document), limits) ?? overlapLimitError(document, limits);
68
+ if (limitError !== undefined)
69
+ return { id, message: limitError };
67
70
  const validationErrors = validate(schema, document, specifiedRules);
68
- if (validationErrors.length > 0)
69
- return { id, message: validationErrors[0]?.message ?? "Invalid GraphQL query." };
70
- const limitError = documentLimitError(documentMetrics(document), limits);
71
- return limitError === undefined ? undefined : { id, message: limitError };
71
+ return validationErrors.length > 0
72
+ ? { id, message: validationErrors[0]?.message ?? "Invalid GraphQL query." }
73
+ : undefined;
72
74
  }
73
75
  function maskWsError(error) {
74
76
  const record = recordOf(error);
@@ -85,13 +87,16 @@ function maskWsError(error) {
85
87
  * so the id stops counting against `maxSubscriptions`: a client is not expected to complete an
86
88
  * operation the server already ended.
87
89
  */
88
- function outboundFrame(message, subscriptions) {
90
+ function outboundFrame(message, connection) {
89
91
  try {
90
92
  const parsed = recordOf(JSON.parse(message));
91
93
  if (parsed === undefined)
92
94
  return message;
95
+ if (parsed.type === "connection_ack")
96
+ connection.acknowledged = true;
93
97
  if ((parsed.type === "complete" || parsed.type === "error") && typeof parsed.id === "string") {
94
- subscriptions.delete(parsed.id);
98
+ connection.subscriptions.delete(parsed.id);
99
+ connection.operations?.delete(parsed.id);
95
100
  }
96
101
  if (parsed.type === "next") {
97
102
  const payload = recordOf(parsed.payload);
@@ -111,16 +116,61 @@ function outboundFrame(message, subscriptions) {
111
116
  }
112
117
  return message;
113
118
  }
119
+ /** Close a result that arrived after its operation timed out, if it is a stream nobody will read. */
120
+ function disposeLate(result) {
121
+ if (typeof result !== "object" || result === null || !(Symbol.asyncIterator in result))
122
+ return;
123
+ const iterator = recordOf(result);
124
+ if (iterator === undefined || typeof iterator.return !== "function")
125
+ return;
126
+ Promise.resolve(iterator.return.call(result)).catch(() => { });
127
+ }
128
+ const wrappedSubscribeFields = new WeakSet();
129
+ /**
130
+ * graphql drops a subscribe resolver's result that settles after the operation's signal aborted, so
131
+ * a source the resolver opened anyway would stay open. Each root subscription field's resolver is
132
+ * wrapped once to return such a late source; with no signal, or before an abort, it is unchanged.
133
+ */
134
+ function returnLateSources(schema) {
135
+ const fields = schema.getSubscriptionType()?.getFields() ?? {};
136
+ for (const field of Object.values(fields)) {
137
+ const resolver = field.subscribe;
138
+ if (resolver === undefined || wrappedSubscribeFields.has(field))
139
+ continue;
140
+ wrappedSubscribeFields.add(field);
141
+ field.subscribe = (source, args, context, info) => {
142
+ const result = resolver(source, args, context, info);
143
+ if (!(result instanceof Promise))
144
+ return result;
145
+ return result.then((value) => {
146
+ if (info.getAbortSignal()?.aborted === true)
147
+ disposeLate(value);
148
+ return value;
149
+ });
150
+ };
151
+ }
152
+ }
114
153
  /**
115
154
  * A timeout is that operation's error result. graphql-ws does not catch a rejected execute or
116
- * subscribe, so a rejection would end the whole socket instead of the one operation.
155
+ * subscribe, so a rejection would end the whole socket instead of the one operation. A timeout aborts
156
+ * the operation's `abortSignal`, which resolvers read through `info.getAbortSignal()`, and work that
157
+ * settles after it is not abandoned open: a late subscription stream is returned.
117
158
  */
118
- async function withWsTimeout(work, timeoutMs) {
119
- if (!(work instanceof Promise) || timeoutMs === 0)
159
+ async function withWsTimeout(start, outer, timeoutMs) {
160
+ const controller = new AbortController();
161
+ const work = start(outer ? AbortSignal.any([outer, controller.signal]) : controller.signal);
162
+ if (!(work instanceof Promise))
120
163
  return work;
121
164
  let timer;
165
+ let timedOut = false;
122
166
  const timeout = new Promise((resolve) => {
123
- timer = setTimeout(() => resolve({ errors: [new GraphQLError("Execution timed out.")] }), timeoutMs);
167
+ timer = setTimeout(() => {
168
+ timedOut = true;
169
+ const error = new GraphQLError("Execution timed out.");
170
+ // Resolved first: the abort can reject the work, and the race must settle on this result.
171
+ resolve({ errors: [error] });
172
+ controller.abort(error);
173
+ }, timeoutMs);
124
174
  });
125
175
  try {
126
176
  return await Promise.race([work, timeout]);
@@ -128,6 +178,8 @@ async function withWsTimeout(work, timeoutMs) {
128
178
  finally {
129
179
  if (timer !== undefined)
130
180
  clearTimeout(timer);
181
+ if (timedOut)
182
+ work.then(disposeLate, () => { });
131
183
  }
132
184
  }
133
185
  /**
@@ -150,8 +202,13 @@ export function graphqlWebSocket(options) {
150
202
  assertWsNumber(maxSubscriptions, "maxSubscriptions", 1);
151
203
  const executionTimeoutMs = options.executionTimeoutMs ?? 10_000;
152
204
  assertWsNumber(executionTimeoutMs, "executionTimeoutMs", 0);
153
- const executeWithTimeout = (args) => withWsTimeout(execute(args), executionTimeoutMs);
154
- const subscribeWithTimeout = (args) => withWsTimeout(subscribe(args), executionTimeoutMs);
205
+ const executeWithTimeout = (args) => executionTimeoutMs === 0
206
+ ? execute(args)
207
+ : withWsTimeout((abortSignal) => execute({ ...args, abortSignal }), args.abortSignal, executionTimeoutMs);
208
+ const subscribeWithTimeout = (args) => executionTimeoutMs === 0
209
+ ? subscribe(args)
210
+ : withWsTimeout((abortSignal) => subscribe({ ...args, abortSignal }), args.abortSignal, executionTimeoutMs);
211
+ returnLateSources(options.schema);
155
212
  const gqlServer = makeServer({
156
213
  // Keep the raw escape hatch for auxiliary graphql-ws hooks, but make the package's safety
157
214
  // controls authoritative: callers cannot accidentally replace the bounded execute/subscribe
@@ -160,19 +217,31 @@ export function graphqlWebSocket(options) {
160
217
  schema: options.schema,
161
218
  execute: executeWithTimeout,
162
219
  subscribe: subscribeWithTimeout,
163
- onConnect: options.onConnect
220
+ onConnect: options.onConnect || options.authorize
164
221
  ? async (ctx) => {
165
222
  try {
166
- return await options.onConnect?.(ctx.connectionParams, ctx.extra.request);
223
+ if (options.authorize !== undefined && !(await options.authorize(ctx.extra.request)))
224
+ return false;
225
+ return ((await options.onConnect?.(ctx.connectionParams, ctx.extra.request)) ?? true);
167
226
  }
168
227
  catch {
169
228
  return false;
170
229
  }
171
230
  }
172
231
  : undefined,
173
- context: options.context
174
- ? async (ctx) => await buildContext(options.context, { request: ctx.extra.request })
175
- : undefined,
232
+ // graphql-ws builds the context once per operation, just before executing it, so the operation's
233
+ // abort signal is attached to its execution arguments here.
234
+ context: async (ctx, id, _payload, args) => {
235
+ const controller = new AbortController();
236
+ ctx.extra.operations.set(id, controller);
237
+ args.abortSignal =
238
+ args.abortSignal === undefined || args.abortSignal === null
239
+ ? controller.signal
240
+ : AbortSignal.any([args.abortSignal, controller.signal]);
241
+ return options.context === undefined
242
+ ? undefined
243
+ : await buildContext(options.context, { request: ctx.extra.request });
244
+ },
176
245
  });
177
246
  return {
178
247
  upgrade(c) {
@@ -181,10 +250,12 @@ export function graphqlWebSocket(options) {
181
250
  open(ws) {
182
251
  const protocol = ws.raw?.protocol ?? GRAPHQL_TRANSPORT_WS_PROTOCOL;
183
252
  let onFrame;
253
+ const operations = new Map();
254
+ ws.data.operations = operations;
184
255
  const closed = gqlServer.opened({
185
256
  protocol,
186
257
  send: async (data) => {
187
- ws.send(outboundFrame(data, ws.data.subscriptions));
258
+ ws.send(outboundFrame(data, ws.data));
188
259
  },
189
260
  close: (code, reason) => {
190
261
  ws.close(code, reason);
@@ -192,7 +263,7 @@ export function graphqlWebSocket(options) {
192
263
  onMessage: (cb) => {
193
264
  onFrame = cb;
194
265
  },
195
- }, { request: ws.data.request });
266
+ }, { request: ws.data.request, operations });
196
267
  ws.data.closed = closed;
197
268
  ws.data.dispatch = async (message) => {
198
269
  try {
@@ -211,7 +282,12 @@ export function graphqlWebSocket(options) {
211
282
  // this socket - including the client's `Complete` that stops the subscription. graphql-ws drives
212
283
  // its own sends and error frames from inside that loop; we only feed it inbound frames.
213
284
  const message = asText(data);
214
- const rejected = subscriptionFrameError(message, options.schema, limits);
285
+ // Until connection_init is admitted, graphql-ws answers a subscribe frame by closing with 4401
286
+ // without reading the query. Parsing or validating it here would hand an unauthenticated socket
287
+ // schema suggestions and synchronous validation work.
288
+ const rejected = ws.data.acknowledged === true
289
+ ? subscriptionFrameError(message, options.schema, limits)
290
+ : undefined;
215
291
  if (rejected !== undefined) {
216
292
  ws.send(JSON.stringify({
217
293
  id: rejected.id,
@@ -235,6 +311,8 @@ export function graphqlWebSocket(options) {
235
311
  }
236
312
  else if (frame?.type === "complete" && typeof frame.id === "string") {
237
313
  ws.data.subscriptions.delete(frame.id);
314
+ ws.data.operations?.get(frame.id)?.abort(new GraphQLError("Operation completed."));
315
+ ws.data.operations?.delete(frame.id);
238
316
  }
239
317
  }
240
318
  catch {
@@ -244,6 +322,9 @@ export function graphqlWebSocket(options) {
244
322
  },
245
323
  close(ws, code, reason) {
246
324
  ws.data.subscriptions.clear();
325
+ for (const controller of ws.data.operations?.values() ?? [])
326
+ controller.abort(new GraphQLError("Socket closed."));
327
+ ws.data.operations?.clear();
247
328
  // The socket is gone: a failing iterator return() or onClose hook has no one left to answer.
248
329
  void Promise.resolve(ws.data.closed?.(code, reason)).catch(() => { });
249
330
  },
package/dist/ws.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nifrajs/graphql",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "Mount a GraphQL endpoint on a nifra app - a spec-compliant GraphQL-over-HTTP handler you mount at POST /graphql, graphql-ws subscriptions over nifra's native WebSocket lane, and typed nifra context piped straight into your resolvers. Uses graphql's own execute/subscribe; no server framework re-bundled.",
5
5
  "keywords": [
6
6
  "bun",
@@ -46,7 +46,7 @@
46
46
  "build": "tsc -p tsconfig.build.json && bun run ../../scripts/fix-dts.ts dist"
47
47
  },
48
48
  "peerDependencies": {
49
- "@nifrajs/core": "^4.0.0",
49
+ "@nifrajs/core": "^5.0.0",
50
50
  "graphql": "^17.0.0",
51
51
  "graphql-ws": "^6.0.0"
52
52
  },
package/src/http.ts CHANGED
@@ -6,7 +6,8 @@
6
6
  * (`@nifrajs/core/edge-kit`'s {@link readBodyFramed}).
7
7
  *
8
8
  * Spec: https://graphql.github.io/graphql-over-http/draft/. POST carries `{query, operationName?,
9
- * variables?, extensions?}` as `application/json`; GET carries them as query-string params and may run
9
+ * variables?, extensions?}` as `application/json` (any other media type answers 415, so a cross-site
10
+ * form cannot post a mutation); GET carries them as query-string params and may run
10
11
  * **queries only** (never a mutation) so it stays a safe, cacheable idempotent method. Responses use the
11
12
  * `application/graphql-response+json` media type with spec status codes by default; set
12
13
  * `legacyJsonResponse` for the old always-200 `application/json` shape older clients expect.
@@ -49,6 +50,7 @@ import {
49
50
  documentMetrics,
50
51
  type GraphqlLimits,
51
52
  graphqlLimits,
53
+ overlapLimitError,
52
54
  requestLimitError,
53
55
  safeFormattedError,
54
56
  } from "./limits.ts"
@@ -84,7 +86,16 @@ export interface GraphqlHttpOptions<Context = unknown, Env = unknown> {
84
86
  readonly maxComplexity?: number
85
87
  /** Maximum operation definitions in one document. Default 10. */
86
88
  readonly maxOperations?: number
87
- /** Maximum asynchronous resolver execution time. Default 10 seconds. */
89
+ /**
90
+ * Maximum pairs of fields sharing a response name in one selection set, counted through fragments.
91
+ * Validation compares every such pair, so this bounds its cost. Default 2,000.
92
+ */
93
+ readonly maxFieldOverlaps?: number
94
+ /**
95
+ * Maximum asynchronous resolver execution time. Default 10 seconds. The execution's abort signal,
96
+ * which a resolver reads through `info.getAbortSignal()`, is aborted at this deadline and when the
97
+ * request itself is aborted.
98
+ */
88
99
  readonly executionTimeoutMs?: number
89
100
  /** Prototype-pollution policy for the parsed JSON body. Default `"reject"`. */
90
101
  readonly protoPoisoning?: ProtoPoisoning
@@ -96,8 +107,8 @@ export interface GraphqlHttpOptions<Context = unknown, Env = unknown> {
96
107
  */
97
108
  readonly allowedOrigins?: readonly string[]
98
109
  /**
99
- * Per-request authorization, run after the body parses and before execution. Return `false` to answer
100
- * `401` with a GraphQL error envelope and skip execution entirely.
110
+ * Per-request authorization, run after the origin check and before the body is read or parsed; a
111
+ * CORS preflight (`OPTIONS`) skips it. Return `false` to answer `401` with a GraphQL error envelope.
101
112
  */
102
113
  readonly authorize?: (request: Request) => boolean | Promise<boolean>
103
114
  /** Emit the legacy always-200 `application/json` response shape instead of `application/graphql-response+json`. */
@@ -195,6 +206,12 @@ function parseVariables(raw: unknown): Record<string, unknown> | null {
195
206
  return parsed as Record<string, unknown>
196
207
  }
197
208
 
209
+ /** `application/json` or a structured `+json` type, parameters ignored. */
210
+ function isJsonMediaType(header: string | null): boolean {
211
+ const essence = header?.split(";", 1)[0]?.trim().toLowerCase() ?? ""
212
+ return essence === "application/json" || /^application\/[a-z0-9.+-]+\+json$/.test(essence)
213
+ }
214
+
198
215
  /** Read `{query, operationName, variables}` from a parsed POST body. Throws GraphQLError when malformed. */
199
216
  function paramsFromBody(body: unknown): GraphqlParams {
200
217
  if (body === null || typeof body !== "object" || Array.isArray(body)) {
@@ -247,12 +264,10 @@ async function run<Context, Env>(
247
264
  return requestError("", 400, legacy, cors, [gqlErr], opts.formatError)
248
265
  }
249
266
 
250
- const validationErrors = validate(opts.schema, document, specifiedRules)
251
- if (validationErrors.length > 0) {
252
- return requestError("", 400, legacy, cors, validationErrors, opts.formatError)
253
- }
254
-
255
- const documentLimit = documentLimitError(documentMetrics(document), limits)
267
+ // Every limit runs before validate(): its overlap rule is quadratic, so a small document within the
268
+ // byte limit can hold the event loop for seconds.
269
+ const documentLimit =
270
+ documentLimitError(documentMetrics(document), limits) ?? overlapLimitError(document, limits)
256
271
  if (documentLimit !== undefined) {
257
272
  return requestError(
258
273
  documentLimit,
@@ -264,6 +279,11 @@ async function run<Context, Env>(
264
279
  )
265
280
  }
266
281
 
282
+ const validationErrors = validate(opts.schema, document, specifiedRules)
283
+ if (validationErrors.length > 0) {
284
+ return requestError("", 400, legacy, cors, validationErrors, opts.formatError)
285
+ }
286
+
267
287
  // GET is idempotent and cacheable, so per the GraphQL-over-HTTP spec it may run queries only.
268
288
  const operationAst = getOperationAST(document, params.operationName ?? undefined)
269
289
  if (isGet && operationAst != null && operationAst.operation !== "query") {
@@ -295,15 +315,20 @@ async function run<Context, Env>(
295
315
 
296
316
  let result: ExecutionResult
297
317
  try {
298
- const execution = execute({
299
- schema: opts.schema,
300
- document,
301
- rootValue: opts.rootValue,
302
- contextValue,
303
- variableValues: params.variables ?? undefined,
304
- operationName: params.operationName ?? undefined,
305
- })
306
- result = (await withExecutionTimeout(execution, executionTimeoutMs)) as ExecutionResult
318
+ result = await withExecutionTimeout(
319
+ (abortSignal) =>
320
+ execute({
321
+ schema: opts.schema,
322
+ document,
323
+ rootValue: opts.rootValue,
324
+ contextValue,
325
+ variableValues: params.variables ?? undefined,
326
+ operationName: params.operationName ?? undefined,
327
+ abortSignal,
328
+ }),
329
+ request.signal,
330
+ executionTimeoutMs,
331
+ )
307
332
  } catch (err) {
308
333
  const gqlErr =
309
334
  err instanceof GraphQLError
@@ -342,11 +367,23 @@ class ExecutionTimeoutError extends Error {
342
367
  }
343
368
  }
344
369
 
345
- async function withExecutionTimeout<T>(work: T | Promise<T>, timeoutMs: number): Promise<T> {
370
+ /** Run `start` under a deadline. A timeout rejects and aborts the signal resolvers were given. */
371
+ async function withExecutionTimeout<T>(
372
+ start: (abortSignal: AbortSignal) => T | Promise<T>,
373
+ outer: AbortSignal,
374
+ timeoutMs: number,
375
+ ): Promise<T> {
376
+ const controller = new AbortController()
377
+ const work = start(AbortSignal.any([outer, controller.signal]))
346
378
  if (!(work instanceof Promise) || timeoutMs === 0) return work
347
379
  let timer: ReturnType<typeof setTimeout> | undefined
348
380
  const timeout = new Promise<T>((_, reject) => {
349
- timer = setTimeout(() => reject(new ExecutionTimeoutError()), timeoutMs)
381
+ timer = setTimeout(() => {
382
+ const error = new ExecutionTimeoutError()
383
+ // Rejected first: the abort can reject the work, and the race must settle on the timeout.
384
+ reject(error)
385
+ controller.abort(error)
386
+ }, timeoutMs)
350
387
  })
351
388
  try {
352
389
  return await Promise.race([work, timeout])
@@ -412,6 +449,19 @@ export async function respondGraphql<Context = unknown, Env = unknown>(
412
449
  )
413
450
  }
414
451
 
452
+ // Checked before the body is read: urlencoded, multipart and text/plain are what a browser sends
453
+ // cross-site without a preflight, so accepting one would let a form run a mutation with cookies.
454
+ if (!isJsonMediaType(request.headers.get("content-type"))) {
455
+ return requestError(
456
+ "Unsupported media type.",
457
+ 415,
458
+ legacy,
459
+ cors,
460
+ [new GraphQLError("A POST body must be sent as application/json.")],
461
+ options.formatError,
462
+ )
463
+ }
464
+
415
465
  // Read the JSON body through core's single bounded + proto-guarded framing lane.
416
466
  return readBodyFramed<Response>(
417
467
  request,