@common-stack/server-stack 9.0.2-alpha.2 → 9.0.2-alpha.7

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.
@@ -1,6 +1,7 @@
1
- import*as url from'url';import {WebSocketServer}from'ws';import {useServer}from'graphql-ws/lib/use/ws';import {createWebSocketContext}from'./websocket-context.mjs';import {config}from'../config/env-config.mjs';class WebsocketMultiPathServer {
1
+ import {WebSocketServer}from'../express-adapter.mjs';import {useServer}from'graphql-ws/lib/use/ws';import {createWebSocketContext}from'./websocket-context.mjs';import {config}from'../config/env-config.mjs';class WebsocketMultiPathServer {
2
2
  moduleService;
3
3
  cache;
4
+ serverHost;
4
5
  webSockets = {};
5
6
  // private graphqlSubscriptionServer: GraphqlSubscriptionServer;
6
7
  _graphqlWs;
@@ -8,27 +9,58 @@ import*as url from'url';import {WebSocketServer}from'ws';import {useServer}from'
8
9
  maxConnections;
9
10
  /** Whether connection limiting is enabled */
10
11
  limitEnabled;
11
- constructor(moduleService, cache, multiplePathConfig, limitConfig) {
12
+ constructor(moduleService, cache, serverHost, // ultimate-express app or http.Server for WebSocket binding
13
+ multiplePathConfig, limitConfig) {
12
14
  this.moduleService = moduleService;
13
15
  this.cache = cache;
16
+ this.serverHost = serverHost;
14
17
  // Read from validated config (Kubernetes configmap) or use defaults
15
18
  this.maxConnections = limitConfig?.maxConnections ?? config.WEBSOCKET_MAX_CONNECTIONS;
16
19
  this.limitEnabled = limitConfig?.limitEnabled ?? config.WEBSOCKET_LIMIT_ENABLED;
17
- this._graphqlWs = new WebSocketServer({ noServer: true, path: __GRAPHQL_ENDPOINT__ });
20
+ // With the adapter, WebSocketServer works with both ultimate-ws and ws.
21
+ // - ultimate-ws: binds to the ultimate-express app via { server: app, path }
22
+ // - ws: binds to the http.Server via { server: httpServer, path }
23
+ this._graphqlWs = new WebSocketServer({
24
+ server: this.serverHost,
25
+ path: __GRAPHQL_ENDPOINT__,
26
+ verifyClient: (info, cb) => {
27
+ if (this.limitEnabled && this.isConnectionLimitReached()) {
28
+ this.moduleService.logger?.warn?.(`WebSocket connection limit reached (${this.maxConnections}). Rejecting new connection.`);
29
+ cb(false, 503, 'Service Unavailable');
30
+ return;
31
+ }
32
+ cb(true);
33
+ },
34
+ });
18
35
  this.webSockets[__GRAPHQL_ENDPOINT__] = this._graphqlWs;
19
36
  // Initialize useServer ONCE for the GraphQL WebSocket server
20
- // This prevents memory leaks from creating new listeners on each connection
37
+ // This prevents memory leaks from creating new listeners on each connection.
38
+ // The 3rd positional `keepAlive` arg drives transport-level ping/pong so
39
+ // dead clients (mobile sleep, NAT timeout) are evicted. Default 30s,
40
+ // tunable via `GRAPHQL_WS_KEEPALIVE_MS`.
41
+ const keepAliveMs = Number(process.env.GRAPHQL_WS_KEEPALIVE_MS) || 30_000;
21
42
  useServer({
22
43
  schema: moduleService.schema,
23
44
  // Using shared context creation function to maintain consistency with GraphqlWs
24
45
  context: async (ctx) => createWebSocketContext(ctx, moduleService, cache),
25
- }, this._graphqlWs);
46
+ }, this._graphqlWs, keepAliveMs);
26
47
  for (let key in multiplePathConfig) {
27
48
  if (!multiplePathConfig.hasOwnProperty(key)) {
28
49
  continue;
29
50
  }
30
51
  if (!this.webSockets[key]) {
31
- this.webSockets[key] = new WebSocketServer({ noServer: true });
52
+ this.webSockets[key] = new WebSocketServer({
53
+ server: this.serverHost,
54
+ path: key,
55
+ verifyClient: (info, cb) => {
56
+ if (this.limitEnabled && this.isConnectionLimitReached()) {
57
+ this.moduleService.logger?.warn?.(`WebSocket connection limit reached (${this.maxConnections}). Rejecting new connection.`);
58
+ cb(false, 503, 'Service Unavailable');
59
+ return;
60
+ }
61
+ cb(true);
62
+ },
63
+ });
32
64
  this.webSockets[key].on('connection', (ws, request) => {
33
65
  Promise.all([
34
66
  moduleService.createContext(request, null),
@@ -38,37 +70,6 @@ import*as url from'url';import {WebSocketServer}from'ws';import {useServer}from'
38
70
  }
39
71
  }
40
72
  }
41
- httpServerUpgrade(httpServer) {
42
- httpServer.on('upgrade', (request, socket, head) => {
43
- const pathname = url.parse(request.url).pathname;
44
- // Check connection limit before accepting new connections
45
- if (this.limitEnabled && this.isConnectionLimitReached()) {
46
- this.moduleService.logger?.warn?.(`WebSocket connection limit reached (${this.maxConnections}). Rejecting new connection.`);
47
- socket.write('HTTP/1.1 503 Service Unavailable\r\n');
48
- socket.write('Retry-After: 60\r\n');
49
- socket.write('\r\n');
50
- socket.destroy();
51
- return;
52
- }
53
- if (!this.webSockets[pathname]) {
54
- // in development
55
- if (pathname !== '/sockjs-node') {
56
- // need to destroy
57
- socket.destroy();
58
- }
59
- return;
60
- }
61
- // code to run when a new connection is made
62
- this.webSockets[pathname].handleUpgrade(request, socket, head, (ws) => {
63
- this.webSockets[pathname].emit('connection', ws, request);
64
- });
65
- });
66
- // (new GraphqlWs(this.graphqlWs, this.moduleService, this.cache)).create();
67
- // useServer({
68
- // schema: this.moduleService.schema,
69
- // }, this.graphqlWs);
70
- return httpServer;
71
- }
72
73
  /**
73
74
  * Get total number of active WebSocket connections across all paths
74
75
  */
@@ -1 +1 @@
1
- {"version":3,"file":"WebsocketMultipathUpdate.mjs","sources":["../../src/servers/WebsocketMultipathUpdate.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WebsocketMultipathUpdate.mjs","sources":["../../src/servers/WebsocketMultipathUpdate.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common-stack/server-stack",
3
- "version": "9.0.2-alpha.2",
3
+ "version": "9.0.2-alpha.7",
4
4
  "description": "common core for higher packages to depend on",
5
5
  "license": "UNLICENSED",
6
6
  "author": "CDMBase LLC",
@@ -32,9 +32,9 @@
32
32
  "@cdm-logger/client": "^9.0.17",
33
33
  "@cdm-logger/server": "^9.0.17",
34
34
  "@cdmbase/graphql-type-uri": "^4.0.0",
35
- "@common-stack/codegen-zod": "9.0.2-alpha.1",
36
- "@common-stack/graphql-api": "9.0.2-alpha.2",
37
- "@common-stack/store-redis": "9.0.2-alpha.1",
35
+ "@common-stack/codegen-zod": "9.0.2-alpha.7",
36
+ "@common-stack/graphql-api": "9.0.2-alpha.7",
37
+ "@common-stack/store-redis": "9.0.2-alpha.7",
38
38
  "@graphql-tools/links": "^9.0.1",
39
39
  "@graphql-tools/schema": "^10.0.6",
40
40
  "@graphql-tools/stitch": "^9.2.10",
@@ -84,8 +84,8 @@
84
84
  "zod": "^4.0.0"
85
85
  },
86
86
  "devDependencies": {
87
- "@common-stack/server-core": "9.0.2-alpha.2",
88
- "common": "9.0.2-alpha.1"
87
+ "@common-stack/server-core": "9.0.2-alpha.7",
88
+ "common": "9.0.2-alpha.7"
89
89
  },
90
90
  "peerDependencies": {
91
91
  "@cdm-logger/core": ">=7.0.12",
@@ -98,7 +98,7 @@
98
98
  "publishConfig": {
99
99
  "access": "public"
100
100
  },
101
- "gitHead": "a9302f283cd6804ea171774a4f476dc911855b42",
101
+ "gitHead": "61ed3dee2b995cf4adaf8c5df9a0c3aaef62b24e",
102
102
  "typescript": {
103
103
  "definition": "lib/index.d.ts"
104
104
  }