@rpcbase/server 0.594.0 → 0.595.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.
Files changed (61) hide show
  1. package/dist/convertHeifToWebp-BT1n72DQ.js +148 -0
  2. package/dist/convertHeifToWebp-BT1n72DQ.js.map +1 -0
  3. package/dist/email-Co1GNjlT.js +7204 -0
  4. package/dist/email-Co1GNjlT.js.map +1 -0
  5. package/dist/handler-BqlcQ9sE.js +245 -0
  6. package/dist/handler-BqlcQ9sE.js.map +1 -0
  7. package/dist/handler-C92_gJkX.js +743 -0
  8. package/dist/handler-C92_gJkX.js.map +1 -0
  9. package/dist/handler-CapJTGzc.js +795 -0
  10. package/dist/handler-CapJTGzc.js.map +1 -0
  11. package/dist/handler-Fk-5fOSm.js +119 -0
  12. package/dist/handler-Fk-5fOSm.js.map +1 -0
  13. package/dist/htmlTemplate.d.ts +16 -0
  14. package/dist/htmlTemplate.d.ts.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +5140 -5286
  18. package/dist/index.js.map +1 -1
  19. package/dist/notifications.js +273 -382
  20. package/dist/notifications.js.map +1 -1
  21. package/dist/postProcessors-iffHvje4.js +89 -0
  22. package/dist/postProcessors-iffHvje4.js.map +1 -0
  23. package/dist/queryWindow-DP8zD0lb.js +555 -0
  24. package/dist/queryWindow-DP8zD0lb.js.map +1 -0
  25. package/dist/render_resend-B1SSQ4f7.js +7 -0
  26. package/dist/render_resend-B1SSQ4f7.js.map +1 -0
  27. package/dist/rts/index.js +990 -1207
  28. package/dist/rts/index.js.map +1 -1
  29. package/dist/schemas-B2fUvgYo.js +4151 -0
  30. package/dist/schemas-B2fUvgYo.js.map +1 -0
  31. package/dist/shared-DfrVDSp0.js +79 -0
  32. package/dist/shared-DfrVDSp0.js.map +1 -0
  33. package/dist/ssrMiddleware.d.ts +7 -3
  34. package/dist/ssrMiddleware.d.ts.map +1 -1
  35. package/dist/uploads/worker.js +139 -168
  36. package/dist/uploads/worker.js.map +1 -1
  37. package/dist/uploads.js +12 -22
  38. package/dist/uploads.js.map +1 -1
  39. package/package.json +1 -1
  40. package/dist/convertHeifToWebp-C-DGXZ2k.js +0 -169
  41. package/dist/convertHeifToWebp-C-DGXZ2k.js.map +0 -1
  42. package/dist/email-BCf24GmK.js +0 -8071
  43. package/dist/email-BCf24GmK.js.map +0 -1
  44. package/dist/handler-BqoKvylN.js +0 -147
  45. package/dist/handler-BqoKvylN.js.map +0 -1
  46. package/dist/handler-CUOJ51-w.js +0 -903
  47. package/dist/handler-CUOJ51-w.js.map +0 -1
  48. package/dist/handler-D-XdgeG_.js +0 -986
  49. package/dist/handler-D-XdgeG_.js.map +0 -1
  50. package/dist/handler-F0gFTzvh.js +0 -275
  51. package/dist/handler-F0gFTzvh.js.map +0 -1
  52. package/dist/postProcessors-D27fGZP0.js +0 -107
  53. package/dist/postProcessors-D27fGZP0.js.map +0 -1
  54. package/dist/queryWindow-Cdr7K-S1.js +0 -714
  55. package/dist/queryWindow-Cdr7K-S1.js.map +0 -1
  56. package/dist/render_resend_false-MiC__Smr.js +0 -6
  57. package/dist/render_resend_false-MiC__Smr.js.map +0 -1
  58. package/dist/schemas-Drf83ni9.js +0 -4517
  59. package/dist/schemas-Drf83ni9.js.map +0 -1
  60. package/dist/shared-CJrm9Wjp.js +0 -104
  61. package/dist/shared-CJrm9Wjp.js.map +0 -1
package/dist/rts/index.js CHANGED
@@ -1,1245 +1,1028 @@
1
- import { randomUUID } from "node:crypto";
1
+ import { a as resolveRtsQueryDependencyModelNames, c as runRtsQuery, i as normalizeRtsQueryOptions, l as syncAuthenticatedSessionFromRequest, s as runRtsCount, t as RTS_QUERY_WINDOW_MAX_COUNT } from "../queryWindow-DP8zD0lb.js";
2
2
  import { models } from "@rpcbase/db";
3
+ import { randomUUID } from "node:crypto";
3
4
  import { buildAbilityFromSession } from "@rpcbase/db/acl";
4
5
  import { WebSocketServer } from "ws";
5
- import { d as syncAuthenticatedSessionFromRequest, n as normalizeRtsQueryOptions, e as resolveRtsQueryDependencyModelNames, R as RTS_QUERY_WINDOW_MAX_COUNT, a as runRtsQuery, c as runRtsCount } from "../queryWindow-Cdr7K-S1.js";
6
- const routes = Object.entries({
7
- .../* @__PURE__ */ Object.assign({ "./api/changes/handler.ts": () => import("../handler-BqoKvylN.js") })
8
- }).reduce((acc, [path, mod]) => {
9
- acc[path.replace("./api/", "@rpcbase/server/rts/api/")] = mod;
10
- return acc;
6
+ //#region src/rts/routes.ts
7
+ var routes = Object.entries({ .../* #__PURE__ */ Object.assign({ "./api/changes/handler.ts": () => import("../handler-Fk-5fOSm.js") }) }).reduce((acc, [path, mod]) => {
8
+ acc[path.replace("./api/", "@rpcbase/server/rts/api/")] = mod;
9
+ return acc;
11
10
  }, {});
12
- const QUERY_KEY_MAX_LEN = 4096;
13
- const INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set(["RBRtsChange", "RBRtsCounter"]);
14
- const DEFAULT_MAX_PAYLOAD_BYTES = 1024 * 1024;
15
- const DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 256;
16
- const DEFAULT_DISPATCH_DEBOUNCE_MS = 25;
17
- const initializedServers = /* @__PURE__ */ new WeakSet();
18
- const customHandlers = [];
19
- const sockets = /* @__PURE__ */ new Map();
20
- const socketMeta = /* @__PURE__ */ new Map();
21
- const socketWrappers = /* @__PURE__ */ new Map();
22
- const socketCleanup = /* @__PURE__ */ new Map();
23
- const socketSubscriptions = /* @__PURE__ */ new Map();
24
- const socketCountSubscriptions = /* @__PURE__ */ new Map();
25
- const subscriptions = /* @__PURE__ */ new Map();
26
- const countSubscriptions = /* @__PURE__ */ new Map();
27
- const changeStreams = /* @__PURE__ */ new Map();
28
- const dispatchTimers = /* @__PURE__ */ new Map();
29
- const upgradeMeta = /* @__PURE__ */ new WeakMap();
30
- let maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES;
31
- let maxSubscriptionsPerSocket = DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET;
32
- let dispatchDebounceMs = DEFAULT_DISPATCH_DEBOUNCE_MS;
33
- let allowInternalModels = false;
34
- const isValidQueryWindowCount = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= RTS_QUERY_WINDOW_MAX_COUNT;
35
- class RtsSocket {
36
- id;
37
- tenantId;
38
- userId;
39
- ws;
40
- handlers = /* @__PURE__ */ new Map();
41
- messageHandlers = /* @__PURE__ */ new Map();
42
- constructor({
43
- id,
44
- ws,
45
- meta
46
- }) {
47
- this.id = id;
48
- this.ws = ws;
49
- this.tenantId = meta.tenantId;
50
- this.userId = meta.userId;
51
- }
52
- on(event, handler) {
53
- const set = this.handlers.get(event) ?? /* @__PURE__ */ new Set();
54
- set.add(handler);
55
- this.handlers.set(event, set);
56
- return () => this.off(event, handler);
57
- }
58
- off(event, handler) {
59
- const set = this.handlers.get(event);
60
- if (!set) return;
61
- set.delete(handler);
62
- if (!set.size) this.handlers.delete(event);
63
- }
64
- emit(event, payload) {
65
- sendWs(this.ws, {
66
- type: "event",
67
- event,
68
- payload
69
- });
70
- }
71
- onRtsMessage(channel, handler) {
72
- const set = this.messageHandlers.get(channel) ?? /* @__PURE__ */ new Set();
73
- set.add(handler);
74
- this.messageHandlers.set(channel, set);
75
- return () => this.offRtsMessage(channel, handler);
76
- }
77
- offRtsMessage(channel, handler) {
78
- const set = this.messageHandlers.get(channel);
79
- if (!set) return;
80
- set.delete(handler);
81
- if (!set.size) this.messageHandlers.delete(channel);
82
- }
83
- emitRtsMessage(channel, payload) {
84
- sendWs(this.ws, {
85
- type: "rts-message",
86
- channel,
87
- payload
88
- });
89
- }
90
- close() {
91
- try {
92
- this.ws.close();
93
- } catch {
94
- }
95
- }
96
- dispatch(event, payload) {
97
- const set = this.handlers.get(event);
98
- if (!set) return;
99
- for (const handler of set) {
100
- handler(payload);
101
- }
102
- }
103
- dispatchRtsMessage(channel, payload) {
104
- const set = this.messageHandlers.get(channel);
105
- if (!set) return;
106
- for (const handler of set) {
107
- handler(payload);
108
- }
109
- }
110
- }
111
- const rawToText = (raw) => {
112
- if (typeof raw === "string") return raw;
113
- if (raw instanceof ArrayBuffer) return Buffer.from(raw).toString();
114
- if (Array.isArray(raw)) return Buffer.concat(raw).toString();
115
- return raw.toString();
11
+ //#endregion
12
+ //#region src/rts/index.ts
13
+ var QUERY_KEY_MAX_LEN = 4096;
14
+ var INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set(["RBRtsChange", "RBRtsCounter"]);
15
+ var DEFAULT_MAX_PAYLOAD_BYTES = 1024 * 1024;
16
+ var DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 256;
17
+ var DEFAULT_DISPATCH_DEBOUNCE_MS = 25;
18
+ var initializedServers = /* @__PURE__ */ new WeakSet();
19
+ var customHandlers = [];
20
+ var sockets = /* @__PURE__ */ new Map();
21
+ var socketMeta = /* @__PURE__ */ new Map();
22
+ var socketWrappers = /* @__PURE__ */ new Map();
23
+ var socketCleanup = /* @__PURE__ */ new Map();
24
+ var socketSubscriptions = /* @__PURE__ */ new Map();
25
+ var socketCountSubscriptions = /* @__PURE__ */ new Map();
26
+ var subscriptions = /* @__PURE__ */ new Map();
27
+ var countSubscriptions = /* @__PURE__ */ new Map();
28
+ var changeStreams = /* @__PURE__ */ new Map();
29
+ var dispatchTimers = /* @__PURE__ */ new Map();
30
+ var upgradeMeta = /* @__PURE__ */ new WeakMap();
31
+ var maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES;
32
+ var maxSubscriptionsPerSocket = DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET;
33
+ var dispatchDebounceMs = DEFAULT_DISPATCH_DEBOUNCE_MS;
34
+ var allowInternalModels = false;
35
+ var isValidQueryWindowCount = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= 4096;
36
+ var RtsSocket = class {
37
+ id;
38
+ tenantId;
39
+ userId;
40
+ ws;
41
+ handlers = /* @__PURE__ */ new Map();
42
+ messageHandlers = /* @__PURE__ */ new Map();
43
+ constructor({ id, ws, meta }) {
44
+ this.id = id;
45
+ this.ws = ws;
46
+ this.tenantId = meta.tenantId;
47
+ this.userId = meta.userId;
48
+ }
49
+ on(event, handler) {
50
+ const set = this.handlers.get(event) ?? /* @__PURE__ */ new Set();
51
+ set.add(handler);
52
+ this.handlers.set(event, set);
53
+ return () => this.off(event, handler);
54
+ }
55
+ off(event, handler) {
56
+ const set = this.handlers.get(event);
57
+ if (!set) return;
58
+ set.delete(handler);
59
+ if (!set.size) this.handlers.delete(event);
60
+ }
61
+ emit(event, payload) {
62
+ sendWs(this.ws, {
63
+ type: "event",
64
+ event,
65
+ payload
66
+ });
67
+ }
68
+ onRtsMessage(channel, handler) {
69
+ const set = this.messageHandlers.get(channel) ?? /* @__PURE__ */ new Set();
70
+ set.add(handler);
71
+ this.messageHandlers.set(channel, set);
72
+ return () => this.offRtsMessage(channel, handler);
73
+ }
74
+ offRtsMessage(channel, handler) {
75
+ const set = this.messageHandlers.get(channel);
76
+ if (!set) return;
77
+ set.delete(handler);
78
+ if (!set.size) this.messageHandlers.delete(channel);
79
+ }
80
+ emitRtsMessage(channel, payload) {
81
+ sendWs(this.ws, {
82
+ type: "rts-message",
83
+ channel,
84
+ payload
85
+ });
86
+ }
87
+ close() {
88
+ try {
89
+ this.ws.close();
90
+ } catch {}
91
+ }
92
+ dispatch(event, payload) {
93
+ const set = this.handlers.get(event);
94
+ if (!set) return;
95
+ for (const handler of set) handler(payload);
96
+ }
97
+ dispatchRtsMessage(channel, payload) {
98
+ const set = this.messageHandlers.get(channel);
99
+ if (!set) return;
100
+ for (const handler of set) handler(payload);
101
+ }
116
102
  };
117
- const safeJsonParse = (raw) => JSON.parse(rawToText(raw));
118
- const sendWs = (ws, message) => {
119
- if (ws.readyState !== 1) return;
120
- ws.send(JSON.stringify(message));
103
+ var rawToText = (raw) => {
104
+ if (typeof raw === "string") return raw;
105
+ if (raw instanceof ArrayBuffer) return Buffer.from(raw).toString();
106
+ if (Array.isArray(raw)) return Buffer.concat(raw).toString();
107
+ return raw.toString();
121
108
  };
122
- const ensureSocketErrorHandler = (socket, context) => {
123
- if (socket.listenerCount("error") > 0) return;
124
- socket.on("error", (err) => {
125
- const message = err instanceof Error ? err.message : String(err);
126
- const name = err instanceof Error ? err.name : typeof err;
127
- const stack = err instanceof Error ? err.stack : void 0;
128
- const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
129
- if (code === "ECONNRESET" || code == null && message.includes("ECONNRESET")) return;
130
- console.warn("[rb/rts] socket error", {
131
- name,
132
- code,
133
- message,
134
- stack,
135
- remoteAddress: socket.remoteAddress,
136
- remotePort: socket.remotePort,
137
- localAddress: socket.localAddress,
138
- localPort: socket.localPort,
139
- ...context?.()
140
- });
141
- });
109
+ var safeJsonParse = (raw) => JSON.parse(rawToText(raw));
110
+ var sendWs = (ws, message) => {
111
+ if (ws.readyState !== 1) return;
112
+ ws.send(JSON.stringify(message));
142
113
  };
143
- const redactErrorMessage = (err) => {
144
- const raw = err instanceof Error ? err.message : "Unknown error";
145
- const trimmedModelList = raw.replace(/\.\s+Available models:[\s\S]*$/, "");
146
- const maxLen = 256;
147
- if (trimmedModelList.length <= maxLen) return trimmedModelList;
148
- return trimmedModelList.slice(0, maxLen);
114
+ var ensureSocketErrorHandler = (socket, context) => {
115
+ if (socket.listenerCount("error") > 0) return;
116
+ socket.on("error", (err) => {
117
+ const message = err instanceof Error ? err.message : String(err);
118
+ const name = err instanceof Error ? err.name : typeof err;
119
+ const stack = err instanceof Error ? err.stack : void 0;
120
+ const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
121
+ if (code === "ECONNRESET" || code == null && message.includes("ECONNRESET")) return;
122
+ console.warn("[rb/rts] socket error", {
123
+ name,
124
+ code,
125
+ message,
126
+ stack,
127
+ remoteAddress: socket.remoteAddress,
128
+ remotePort: socket.remotePort,
129
+ localAddress: socket.localAddress,
130
+ localPort: socket.localPort,
131
+ ...context?.()
132
+ });
133
+ });
149
134
  };
150
- const unauthorized = (socket, message = "Unauthorized") => {
151
- ensureSocketErrorHandler(socket);
152
- try {
153
- socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
154
- socket.write(`Error: ${message}\r
155
- `);
156
- socket.end();
157
- } catch {
158
- socket.destroy();
159
- }
135
+ var redactErrorMessage = (err) => {
136
+ const trimmedModelList = (err instanceof Error ? err.message : "Unknown error").replace(/\.\s+Available models:[\s\S]*$/, "");
137
+ const maxLen = 256;
138
+ if (trimmedModelList.length <= maxLen) return trimmedModelList;
139
+ return trimmedModelList.slice(0, maxLen);
160
140
  };
161
- const badRequest = (socket, message = "Bad Request") => {
162
- ensureSocketErrorHandler(socket);
163
- try {
164
- socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
165
- socket.write(`Error: ${message}\r
166
- `);
167
- socket.end();
168
- } catch {
169
- socket.destroy();
170
- }
141
+ var unauthorized = (socket, message = "Unauthorized") => {
142
+ ensureSocketErrorHandler(socket);
143
+ try {
144
+ socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
145
+ socket.write(`Error: ${message}\r\n`);
146
+ socket.end();
147
+ } catch {
148
+ socket.destroy();
149
+ }
171
150
  };
172
- const runSessionMiddleware = async (sessionMiddleware, req) => {
173
- await new Promise((resolve, reject) => {
174
- const next = (err) => {
175
- if (err) reject(err);
176
- else resolve();
177
- };
178
- sessionMiddleware(req, {}, next);
179
- });
151
+ var badRequest = (socket, message = "Bad Request") => {
152
+ ensureSocketErrorHandler(socket);
153
+ try {
154
+ socket.write("HTTP/1.1 400 Bad Request\r\n\r\n");
155
+ socket.write(`Error: ${message}\r\n`);
156
+ socket.end();
157
+ } catch {
158
+ socket.destroy();
159
+ }
180
160
  };
181
- const parseUpgradeMeta = async ({
182
- req,
183
- url,
184
- sessionMiddleware,
185
- postSyncSessionMiddleware
186
- }) => {
187
- const upgradeReq = req;
188
- try {
189
- await runSessionMiddleware(sessionMiddleware, upgradeReq);
190
- } catch {
191
- throw new Error("Failed to load session for RTS");
192
- }
193
- await syncAuthenticatedSessionFromRequest(upgradeReq);
194
- if (postSyncSessionMiddleware) {
195
- try {
196
- await runSessionMiddleware(postSyncSessionMiddleware, upgradeReq);
197
- } catch {
198
- throw new Error("RTS session authorization failed");
199
- }
200
- }
201
- const sessionUser = upgradeReq.session?.user;
202
- const sessionUserId = sessionUser?.id?.trim();
203
- if (!sessionUserId) {
204
- throw new Error("Not signed in (missing session.user.id)");
205
- }
206
- const tenantId = sessionUser?.currentTenantId?.trim();
207
- if (!tenantId) {
208
- throw new Error("Missing current tenant in session");
209
- }
210
- const ability = buildAbilityFromSession({
211
- tenantId,
212
- session: upgradeReq.session
213
- });
214
- return {
215
- tenantId,
216
- userId: sessionUserId,
217
- ability
218
- };
161
+ var runSessionMiddleware = async (sessionMiddleware, req) => {
162
+ await new Promise((resolve, reject) => {
163
+ const next = (err) => {
164
+ if (err) reject(err);
165
+ else resolve();
166
+ };
167
+ sessionMiddleware(req, {}, next);
168
+ });
219
169
  };
220
- const getTenantModel = async (tenantId, modelName) => {
221
- const ctx = {
222
- req: {
223
- session: {
224
- user: {
225
- currentTenantId: tenantId
226
- }
227
- }
228
- }
229
- };
230
- return models.getUnsafe(modelName, ctx);
170
+ var parseUpgradeMeta = async ({ req, url, sessionMiddleware, postSyncSessionMiddleware }) => {
171
+ const upgradeReq = req;
172
+ try {
173
+ await runSessionMiddleware(sessionMiddleware, upgradeReq);
174
+ } catch {
175
+ throw new Error("Failed to load session for RTS");
176
+ }
177
+ await syncAuthenticatedSessionFromRequest(upgradeReq);
178
+ if (postSyncSessionMiddleware) try {
179
+ await runSessionMiddleware(postSyncSessionMiddleware, upgradeReq);
180
+ } catch {
181
+ throw new Error("RTS session authorization failed");
182
+ }
183
+ const sessionUser = upgradeReq.session?.user;
184
+ const sessionUserId = sessionUser?.id?.trim();
185
+ if (!sessionUserId) throw new Error("Not signed in (missing session.user.id)");
186
+ const tenantId = sessionUser?.currentTenantId?.trim();
187
+ if (!tenantId) throw new Error("Missing current tenant in session");
188
+ return {
189
+ tenantId,
190
+ userId: sessionUserId,
191
+ ability: buildAbilityFromSession({
192
+ tenantId,
193
+ session: upgradeReq.session
194
+ })
195
+ };
231
196
  };
232
- const makeDispatchKey = (tenantId, modelName) => `${tenantId}:${modelName}`;
233
- const clearDispatchTimer = (tenantId, modelName) => {
234
- const key = makeDispatchKey(tenantId, modelName);
235
- const timer = dispatchTimers.get(key);
236
- if (!timer) return;
237
- clearTimeout(timer);
238
- dispatchTimers.delete(key);
197
+ var getTenantModel = async (tenantId, modelName) => {
198
+ const ctx = { req: { session: { user: { currentTenantId: tenantId } } } };
199
+ return models.getUnsafe(modelName, ctx);
239
200
  };
240
- const scheduleDispatchSubscriptionsForModel = (tenantId, modelName) => {
241
- const key = makeDispatchKey(tenantId, modelName);
242
- if (dispatchTimers.has(key)) return;
243
- const delay = Math.max(0, Math.min(1e3, Math.floor(dispatchDebounceMs)));
244
- dispatchTimers.set(key, setTimeout(() => {
245
- dispatchTimers.delete(key);
246
- void Promise.all([dispatchSubscriptionsForModel(tenantId, modelName), dispatchCountSubscriptionsForModel(tenantId, modelName)]).catch(() => {
247
- });
248
- }, delay));
201
+ var makeDispatchKey = (tenantId, modelName) => `${tenantId}:${modelName}`;
202
+ var clearDispatchTimer = (tenantId, modelName) => {
203
+ const key = makeDispatchKey(tenantId, modelName);
204
+ const timer = dispatchTimers.get(key);
205
+ if (!timer) return;
206
+ clearTimeout(timer);
207
+ dispatchTimers.delete(key);
249
208
  };
250
- const runAndSendQuery = async ({
251
- tenantId,
252
- targetSocketIds,
253
- ability,
254
- modelName,
255
- queryKey,
256
- query,
257
- options
258
- }) => {
259
- const result = await runRtsQuery({
260
- tenantId,
261
- ability,
262
- modelName,
263
- query,
264
- options,
265
- allowInternalModels
266
- });
267
- const payload = {
268
- type: "query-payload",
269
- modelName,
270
- queryKey,
271
- data: result.data,
272
- ...result.pageInfo ? {
273
- pageInfo: result.pageInfo
274
- } : {},
275
- ...typeof result.totalCount === "number" ? {
276
- totalCount: result.totalCount
277
- } : {}
278
- };
279
- for (const socketId of targetSocketIds) {
280
- const ws = sockets.get(socketId);
281
- if (!ws) continue;
282
- sendWs(ws, payload);
283
- }
209
+ var scheduleDispatchSubscriptionsForModel = (tenantId, modelName) => {
210
+ const key = makeDispatchKey(tenantId, modelName);
211
+ if (dispatchTimers.has(key)) return;
212
+ const delay = Math.max(0, Math.min(1e3, Math.floor(dispatchDebounceMs)));
213
+ dispatchTimers.set(key, setTimeout(() => {
214
+ dispatchTimers.delete(key);
215
+ Promise.all([dispatchSubscriptionsForModel(tenantId, modelName), dispatchCountSubscriptionsForModel(tenantId, modelName)]).catch(() => {});
216
+ }, delay));
284
217
  };
285
- const getHeadWindowOptions = (options, requestedCount) => {
286
- if (!options.pagination) return options;
287
- const pagination = {
288
- ...options.pagination,
289
- limit: requestedCount
290
- };
291
- delete pagination.cursor;
292
- delete pagination.direction;
293
- return {
294
- ...options,
295
- pagination
296
- };
218
+ var runAndSendQuery = async ({ tenantId, targetSocketIds, ability, modelName, queryKey, query, options }) => {
219
+ const result = await runRtsQuery({
220
+ tenantId,
221
+ ability,
222
+ modelName,
223
+ query,
224
+ options,
225
+ allowInternalModels
226
+ });
227
+ const payload = {
228
+ type: "query-payload",
229
+ modelName,
230
+ queryKey,
231
+ data: result.data,
232
+ ...result.pageInfo ? { pageInfo: result.pageInfo } : {},
233
+ ...typeof result.totalCount === "number" ? { totalCount: result.totalCount } : {}
234
+ };
235
+ for (const socketId of targetSocketIds) {
236
+ const ws = sockets.get(socketId);
237
+ if (!ws) continue;
238
+ sendWs(ws, payload);
239
+ }
297
240
  };
298
- const runAndSendSubscriptionQuery = async ({
299
- tenantId,
300
- targetSocketIds,
301
- ability,
302
- modelName,
303
- queryKey,
304
- subscription
305
- }) => {
306
- if (!subscription.options.pagination) {
307
- await runAndSendQuery({
308
- tenantId,
309
- targetSocketIds,
310
- ability,
311
- modelName,
312
- queryKey,
313
- query: subscription.query,
314
- options: subscription.options
315
- });
316
- return;
317
- }
318
- const groups = /* @__PURE__ */ new Map();
319
- for (const socketId of targetSocketIds) {
320
- const state = subscription.windows.get(socketId);
321
- if (!state) continue;
322
- state.version += 1;
323
- const targets = groups.get(state.requestedCount) ?? [];
324
- targets.push({
325
- socketId,
326
- window: {
327
- requestedCount: state.requestedCount,
328
- version: state.version
329
- }
330
- });
331
- groups.set(state.requestedCount, targets);
332
- }
333
- await Promise.all(Array.from(groups.entries()).map(async ([requestedCount, targets]) => {
334
- try {
335
- const result = await runRtsQuery({
336
- tenantId,
337
- ability,
338
- modelName,
339
- query: subscription.query,
340
- options: getHeadWindowOptions(subscription.options, requestedCount),
341
- allowInternalModels,
342
- paginationMaxLimit: RTS_QUERY_WINDOW_MAX_COUNT,
343
- includePaginationCursors: false
344
- });
345
- for (const target of targets) {
346
- const current = subscription.windows.get(target.socketId);
347
- if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) {
348
- continue;
349
- }
350
- const ws = sockets.get(target.socketId);
351
- if (!ws) continue;
352
- sendWs(ws, {
353
- type: "query-payload",
354
- modelName,
355
- queryKey,
356
- data: result.data,
357
- ...result.pageInfo ? {
358
- pageInfo: result.pageInfo
359
- } : {},
360
- ...typeof result.totalCount === "number" ? {
361
- totalCount: result.totalCount
362
- } : {},
363
- window: target.window
364
- });
365
- }
366
- } catch (err) {
367
- const error = redactErrorMessage(err);
368
- for (const target of targets) {
369
- const current = subscription.windows.get(target.socketId);
370
- if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) {
371
- continue;
372
- }
373
- const ws = sockets.get(target.socketId);
374
- if (!ws) continue;
375
- sendWs(ws, {
376
- type: "query-payload",
377
- modelName,
378
- queryKey,
379
- error,
380
- window: target.window
381
- });
382
- }
383
- }
384
- }));
241
+ var getHeadWindowOptions = (options, requestedCount) => {
242
+ if (!options.pagination) return options;
243
+ const pagination = {
244
+ ...options.pagination,
245
+ limit: requestedCount
246
+ };
247
+ delete pagination.cursor;
248
+ delete pagination.direction;
249
+ return {
250
+ ...options,
251
+ pagination
252
+ };
385
253
  };
386
- const runAndSendCount = async ({
387
- tenantId,
388
- targetSocketIds,
389
- ability,
390
- modelName,
391
- queryKey,
392
- query
393
- }) => {
394
- const count = await runRtsCount({
395
- tenantId,
396
- ability,
397
- modelName,
398
- query,
399
- allowInternalModels
400
- });
401
- const payload = {
402
- type: "count-payload",
403
- modelName,
404
- queryKey,
405
- count
406
- };
407
- for (const socketId of targetSocketIds) {
408
- const ws = sockets.get(socketId);
409
- if (!ws) continue;
410
- sendWs(ws, payload);
411
- }
254
+ var runAndSendSubscriptionQuery = async ({ tenantId, targetSocketIds, ability, modelName, queryKey, subscription }) => {
255
+ if (!subscription.options.pagination) {
256
+ await runAndSendQuery({
257
+ tenantId,
258
+ targetSocketIds,
259
+ ability,
260
+ modelName,
261
+ queryKey,
262
+ query: subscription.query,
263
+ options: subscription.options
264
+ });
265
+ return;
266
+ }
267
+ const groups = /* @__PURE__ */ new Map();
268
+ for (const socketId of targetSocketIds) {
269
+ const state = subscription.windows.get(socketId);
270
+ if (!state) continue;
271
+ state.version += 1;
272
+ const targets = groups.get(state.requestedCount) ?? [];
273
+ targets.push({
274
+ socketId,
275
+ window: {
276
+ requestedCount: state.requestedCount,
277
+ version: state.version
278
+ }
279
+ });
280
+ groups.set(state.requestedCount, targets);
281
+ }
282
+ await Promise.all(Array.from(groups.entries()).map(async ([requestedCount, targets]) => {
283
+ try {
284
+ const result = await runRtsQuery({
285
+ tenantId,
286
+ ability,
287
+ modelName,
288
+ query: subscription.query,
289
+ options: getHeadWindowOptions(subscription.options, requestedCount),
290
+ allowInternalModels,
291
+ paginationMaxLimit: RTS_QUERY_WINDOW_MAX_COUNT,
292
+ includePaginationCursors: false
293
+ });
294
+ for (const target of targets) {
295
+ const current = subscription.windows.get(target.socketId);
296
+ if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) continue;
297
+ const ws = sockets.get(target.socketId);
298
+ if (!ws) continue;
299
+ sendWs(ws, {
300
+ type: "query-payload",
301
+ modelName,
302
+ queryKey,
303
+ data: result.data,
304
+ ...result.pageInfo ? { pageInfo: result.pageInfo } : {},
305
+ ...typeof result.totalCount === "number" ? { totalCount: result.totalCount } : {},
306
+ window: target.window
307
+ });
308
+ }
309
+ } catch (err) {
310
+ const error = redactErrorMessage(err);
311
+ for (const target of targets) {
312
+ const current = subscription.windows.get(target.socketId);
313
+ if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) continue;
314
+ const ws = sockets.get(target.socketId);
315
+ if (!ws) continue;
316
+ sendWs(ws, {
317
+ type: "query-payload",
318
+ modelName,
319
+ queryKey,
320
+ error,
321
+ window: target.window
322
+ });
323
+ }
324
+ }
325
+ }));
412
326
  };
413
- const subscriptionDependsOnModel = (changedModelName, ownerModelName, subscription) => {
414
- if (ownerModelName === changedModelName) return true;
415
- return subscription.dependencyModelNames.includes(changedModelName);
327
+ var runAndSendCount = async ({ tenantId, targetSocketIds, ability, modelName, queryKey, query }) => {
328
+ const payload = {
329
+ type: "count-payload",
330
+ modelName,
331
+ queryKey,
332
+ count: await runRtsCount({
333
+ tenantId,
334
+ ability,
335
+ modelName,
336
+ query,
337
+ allowInternalModels
338
+ })
339
+ };
340
+ for (const socketId of targetSocketIds) {
341
+ const ws = sockets.get(socketId);
342
+ if (!ws) continue;
343
+ sendWs(ws, payload);
344
+ }
416
345
  };
417
- const hasAnySubscriptionsDependingOnModel = (tenantId, modelName) => {
418
- const tenantSubs = subscriptions.get(tenantId);
419
- if (!tenantSubs) return false;
420
- for (const userSubs of tenantSubs.values()) {
421
- for (const [ownerModelName, modelSubs] of userSubs.entries()) {
422
- for (const subscription of modelSubs.values()) {
423
- if (subscriptionDependsOnModel(modelName, ownerModelName, subscription)) {
424
- return true;
425
- }
426
- }
427
- }
428
- }
429
- return false;
346
+ var subscriptionDependsOnModel = (changedModelName, ownerModelName, subscription) => {
347
+ if (ownerModelName === changedModelName) return true;
348
+ return subscription.dependencyModelNames.includes(changedModelName);
430
349
  };
431
- const hasAnyCountSubscriptionsForModel = (tenantId, modelName) => {
432
- const tenantSubs = countSubscriptions.get(tenantId);
433
- if (!tenantSubs) return false;
434
- for (const userSubs of tenantSubs.values()) {
435
- const modelSubs = userSubs.get(modelName);
436
- if (modelSubs?.size) {
437
- return true;
438
- }
439
- }
440
- return false;
350
+ var hasAnySubscriptionsDependingOnModel = (tenantId, modelName) => {
351
+ const tenantSubs = subscriptions.get(tenantId);
352
+ if (!tenantSubs) return false;
353
+ for (const userSubs of tenantSubs.values()) for (const [ownerModelName, modelSubs] of userSubs.entries()) for (const subscription of modelSubs.values()) if (subscriptionDependsOnModel(modelName, ownerModelName, subscription)) return true;
354
+ return false;
441
355
  };
442
- const dispatchSubscriptionsForModel = async (tenantId, modelName) => {
443
- const tenantSubs = subscriptions.get(tenantId);
444
- if (!tenantSubs || !tenantSubs.size) return;
445
- for (const userSubs of tenantSubs.values()) {
446
- for (const [ownerModelName, modelSubs] of userSubs.entries()) {
447
- for (const [queryKey, sub] of modelSubs.entries()) {
448
- if (!subscriptionDependsOnModel(modelName, ownerModelName, sub)) continue;
449
- const targetSocketIds = Array.from(sub.socketIds);
450
- if (!targetSocketIds.length) continue;
451
- const socketId = targetSocketIds[0];
452
- const meta = socketMeta.get(socketId);
453
- const ability = meta?.ability;
454
- if (!ability) continue;
455
- try {
456
- await runAndSendSubscriptionQuery({
457
- tenantId,
458
- targetSocketIds,
459
- ability,
460
- modelName: ownerModelName,
461
- queryKey,
462
- subscription: sub
463
- });
464
- } catch (err) {
465
- const error = redactErrorMessage(err);
466
- const payload = {
467
- type: "query-payload",
468
- modelName: ownerModelName,
469
- queryKey,
470
- error
471
- };
472
- for (const socketId2 of targetSocketIds) {
473
- const ws = sockets.get(socketId2);
474
- if (!ws) continue;
475
- sendWs(ws, payload);
476
- }
477
- }
478
- }
479
- }
480
- }
356
+ var hasAnyCountSubscriptionsForModel = (tenantId, modelName) => {
357
+ const tenantSubs = countSubscriptions.get(tenantId);
358
+ if (!tenantSubs) return false;
359
+ for (const userSubs of tenantSubs.values()) if (userSubs.get(modelName)?.size) return true;
360
+ return false;
481
361
  };
482
- const dispatchCountSubscriptionsForModel = async (tenantId, modelName) => {
483
- const tenantSubs = countSubscriptions.get(tenantId);
484
- if (!tenantSubs || !tenantSubs.size) return;
485
- for (const userSubs of tenantSubs.values()) {
486
- const modelSubs = userSubs.get(modelName);
487
- if (!modelSubs) continue;
488
- for (const [queryKey, sub] of modelSubs.entries()) {
489
- const targetSocketIds = Array.from(sub.socketIds);
490
- if (!targetSocketIds.length) continue;
491
- const socketId = targetSocketIds[0];
492
- const meta = socketMeta.get(socketId);
493
- const ability = meta?.ability;
494
- if (!ability) continue;
495
- try {
496
- await runAndSendCount({
497
- tenantId,
498
- targetSocketIds,
499
- ability,
500
- modelName,
501
- queryKey,
502
- query: sub.query
503
- });
504
- } catch (err) {
505
- const error = redactErrorMessage(err);
506
- const payload = {
507
- type: "count-payload",
508
- modelName,
509
- queryKey,
510
- error
511
- };
512
- for (const targetSocketId of targetSocketIds) {
513
- const ws = sockets.get(targetSocketId);
514
- if (!ws) continue;
515
- sendWs(ws, payload);
516
- }
517
- }
518
- }
519
- }
362
+ var dispatchSubscriptionsForModel = async (tenantId, modelName) => {
363
+ const tenantSubs = subscriptions.get(tenantId);
364
+ if (!tenantSubs || !tenantSubs.size) return;
365
+ for (const userSubs of tenantSubs.values()) for (const [ownerModelName, modelSubs] of userSubs.entries()) for (const [queryKey, sub] of modelSubs.entries()) {
366
+ if (!subscriptionDependsOnModel(modelName, ownerModelName, sub)) continue;
367
+ const targetSocketIds = Array.from(sub.socketIds);
368
+ if (!targetSocketIds.length) continue;
369
+ const socketId = targetSocketIds[0];
370
+ const ability = socketMeta.get(socketId)?.ability;
371
+ if (!ability) continue;
372
+ try {
373
+ await runAndSendSubscriptionQuery({
374
+ tenantId,
375
+ targetSocketIds,
376
+ ability,
377
+ modelName: ownerModelName,
378
+ queryKey,
379
+ subscription: sub
380
+ });
381
+ } catch (err) {
382
+ const payload = {
383
+ type: "query-payload",
384
+ modelName: ownerModelName,
385
+ queryKey,
386
+ error: redactErrorMessage(err)
387
+ };
388
+ for (const socketId of targetSocketIds) {
389
+ const ws = sockets.get(socketId);
390
+ if (!ws) continue;
391
+ sendWs(ws, payload);
392
+ }
393
+ }
394
+ }
520
395
  };
521
- const ensureChangeStream = async (tenantId, modelName) => {
522
- const tenantStreams = changeStreams.get(tenantId) ?? /* @__PURE__ */ new Map();
523
- changeStreams.set(tenantId, tenantStreams);
524
- if (tenantStreams.has(modelName)) return;
525
- const model = await getTenantModel(tenantId, modelName);
526
- const stream = model.watch([], {
527
- fullDocument: "updateLookup"
528
- });
529
- stream.on("change", () => {
530
- scheduleDispatchSubscriptionsForModel(tenantId, modelName);
531
- });
532
- stream.on("close", () => {
533
- clearDispatchTimer(tenantId, modelName);
534
- const map = changeStreams.get(tenantId);
535
- map?.delete(modelName);
536
- if (map && map.size === 0) changeStreams.delete(tenantId);
537
- });
538
- stream.on("error", () => {
539
- try {
540
- clearDispatchTimer(tenantId, modelName);
541
- stream.close();
542
- } catch {
543
- }
544
- });
545
- tenantStreams.set(modelName, stream);
396
+ var dispatchCountSubscriptionsForModel = async (tenantId, modelName) => {
397
+ const tenantSubs = countSubscriptions.get(tenantId);
398
+ if (!tenantSubs || !tenantSubs.size) return;
399
+ for (const userSubs of tenantSubs.values()) {
400
+ const modelSubs = userSubs.get(modelName);
401
+ if (!modelSubs) continue;
402
+ for (const [queryKey, sub] of modelSubs.entries()) {
403
+ const targetSocketIds = Array.from(sub.socketIds);
404
+ if (!targetSocketIds.length) continue;
405
+ const socketId = targetSocketIds[0];
406
+ const ability = socketMeta.get(socketId)?.ability;
407
+ if (!ability) continue;
408
+ try {
409
+ await runAndSendCount({
410
+ tenantId,
411
+ targetSocketIds,
412
+ ability,
413
+ modelName,
414
+ queryKey,
415
+ query: sub.query
416
+ });
417
+ } catch (err) {
418
+ const payload = {
419
+ type: "count-payload",
420
+ modelName,
421
+ queryKey,
422
+ error: redactErrorMessage(err)
423
+ };
424
+ for (const targetSocketId of targetSocketIds) {
425
+ const ws = sockets.get(targetSocketId);
426
+ if (!ws) continue;
427
+ sendWs(ws, payload);
428
+ }
429
+ }
430
+ }
431
+ }
546
432
  };
547
- const closeUnusedChangeStream = (tenantId, modelName) => {
548
- if (hasAnySubscriptionsDependingOnModel(tenantId, modelName) || hasAnyCountSubscriptionsForModel(tenantId, modelName)) {
549
- return;
550
- }
551
- const tenantStreams = changeStreams.get(tenantId);
552
- const stream = tenantStreams?.get(modelName);
553
- if (!stream) return;
554
- try {
555
- stream.close();
556
- } catch {
557
- }
558
- clearDispatchTimer(tenantId, modelName);
559
- tenantStreams?.delete(modelName);
560
- if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
433
+ var ensureChangeStream = async (tenantId, modelName) => {
434
+ const tenantStreams = changeStreams.get(tenantId) ?? /* @__PURE__ */ new Map();
435
+ changeStreams.set(tenantId, tenantStreams);
436
+ if (tenantStreams.has(modelName)) return;
437
+ const stream = (await getTenantModel(tenantId, modelName)).watch([], { fullDocument: "updateLookup" });
438
+ stream.on("change", () => {
439
+ scheduleDispatchSubscriptionsForModel(tenantId, modelName);
440
+ });
441
+ stream.on("close", () => {
442
+ clearDispatchTimer(tenantId, modelName);
443
+ const map = changeStreams.get(tenantId);
444
+ map?.delete(modelName);
445
+ if (map && map.size === 0) changeStreams.delete(tenantId);
446
+ });
447
+ stream.on("error", () => {
448
+ try {
449
+ clearDispatchTimer(tenantId, modelName);
450
+ stream.close();
451
+ } catch {}
452
+ });
453
+ tenantStreams.set(modelName, stream);
561
454
  };
562
- const addSocketSubscription = ({
563
- socketId,
564
- tenantId,
565
- userId,
566
- modelName,
567
- queryKey,
568
- query,
569
- options,
570
- dependencyModelNames
571
- }) => {
572
- const tenantSubs = subscriptions.get(tenantId) ?? /* @__PURE__ */ new Map();
573
- subscriptions.set(tenantId, tenantSubs);
574
- const userSubs = tenantSubs.get(userId) ?? /* @__PURE__ */ new Map();
575
- tenantSubs.set(userId, userSubs);
576
- const modelSubs = userSubs.get(modelName) ?? /* @__PURE__ */ new Map();
577
- userSubs.set(modelName, modelSubs);
578
- const existing = modelSubs.get(queryKey);
579
- if (existing) {
580
- existing.socketIds.add(socketId);
581
- existing.dependencyModelNames = Array.from(/* @__PURE__ */ new Set([...existing.dependencyModelNames, ...dependencyModelNames]));
582
- if (options.pagination) {
583
- existing.windows.set(socketId, {
584
- requestedCount: options.pagination.limit,
585
- version: 0
586
- });
587
- } else {
588
- existing.windows.delete(socketId);
589
- }
590
- } else {
591
- modelSubs.set(queryKey, {
592
- query,
593
- options,
594
- dependencyModelNames: Array.from(new Set(dependencyModelNames)),
595
- socketIds: /* @__PURE__ */ new Set([socketId]),
596
- windows: options.pagination ? /* @__PURE__ */ new Map([[socketId, {
597
- requestedCount: options.pagination.limit,
598
- version: 0
599
- }]]) : /* @__PURE__ */ new Map()
600
- });
601
- }
602
- const byModel = socketSubscriptions.get(socketId) ?? /* @__PURE__ */ new Map();
603
- socketSubscriptions.set(socketId, byModel);
604
- const querySet = byModel.get(modelName) ?? /* @__PURE__ */ new Set();
605
- byModel.set(modelName, querySet);
606
- querySet.add(queryKey);
455
+ var closeUnusedChangeStream = (tenantId, modelName) => {
456
+ if (hasAnySubscriptionsDependingOnModel(tenantId, modelName) || hasAnyCountSubscriptionsForModel(tenantId, modelName)) return;
457
+ const tenantStreams = changeStreams.get(tenantId);
458
+ const stream = tenantStreams?.get(modelName);
459
+ if (!stream) return;
460
+ try {
461
+ stream.close();
462
+ } catch {}
463
+ clearDispatchTimer(tenantId, modelName);
464
+ tenantStreams?.delete(modelName);
465
+ if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
607
466
  };
608
- const addSocketCountSubscription = ({
609
- socketId,
610
- tenantId,
611
- userId,
612
- modelName,
613
- queryKey,
614
- query
615
- }) => {
616
- const tenantSubs = countSubscriptions.get(tenantId) ?? /* @__PURE__ */ new Map();
617
- countSubscriptions.set(tenantId, tenantSubs);
618
- const userSubs = tenantSubs.get(userId) ?? /* @__PURE__ */ new Map();
619
- tenantSubs.set(userId, userSubs);
620
- const modelSubs = userSubs.get(modelName) ?? /* @__PURE__ */ new Map();
621
- userSubs.set(modelName, modelSubs);
622
- const existing = modelSubs.get(queryKey);
623
- if (existing) {
624
- existing.socketIds.add(socketId);
625
- } else {
626
- modelSubs.set(queryKey, {
627
- query,
628
- socketIds: /* @__PURE__ */ new Set([socketId])
629
- });
630
- }
631
- const byModel = socketCountSubscriptions.get(socketId) ?? /* @__PURE__ */ new Map();
632
- socketCountSubscriptions.set(socketId, byModel);
633
- const querySet = byModel.get(modelName) ?? /* @__PURE__ */ new Set();
634
- byModel.set(modelName, querySet);
635
- querySet.add(queryKey);
467
+ var addSocketSubscription = ({ socketId, tenantId, userId, modelName, queryKey, query, options, dependencyModelNames }) => {
468
+ const tenantSubs = subscriptions.get(tenantId) ?? /* @__PURE__ */ new Map();
469
+ subscriptions.set(tenantId, tenantSubs);
470
+ const userSubs = tenantSubs.get(userId) ?? /* @__PURE__ */ new Map();
471
+ tenantSubs.set(userId, userSubs);
472
+ const modelSubs = userSubs.get(modelName) ?? /* @__PURE__ */ new Map();
473
+ userSubs.set(modelName, modelSubs);
474
+ const existing = modelSubs.get(queryKey);
475
+ if (existing) {
476
+ existing.socketIds.add(socketId);
477
+ existing.dependencyModelNames = Array.from(/* @__PURE__ */ new Set([...existing.dependencyModelNames, ...dependencyModelNames]));
478
+ if (options.pagination) existing.windows.set(socketId, {
479
+ requestedCount: options.pagination.limit,
480
+ version: 0
481
+ });
482
+ else existing.windows.delete(socketId);
483
+ } else modelSubs.set(queryKey, {
484
+ query,
485
+ options,
486
+ dependencyModelNames: Array.from(new Set(dependencyModelNames)),
487
+ socketIds: /* @__PURE__ */ new Set([socketId]),
488
+ windows: options.pagination ? /* @__PURE__ */ new Map([[socketId, {
489
+ requestedCount: options.pagination.limit,
490
+ version: 0
491
+ }]]) : /* @__PURE__ */ new Map()
492
+ });
493
+ const byModel = socketSubscriptions.get(socketId) ?? /* @__PURE__ */ new Map();
494
+ socketSubscriptions.set(socketId, byModel);
495
+ const querySet = byModel.get(modelName) ?? /* @__PURE__ */ new Set();
496
+ byModel.set(modelName, querySet);
497
+ querySet.add(queryKey);
636
498
  };
637
- const removeSocketSubscription = ({
638
- socketId,
639
- tenantId,
640
- userId,
641
- modelName,
642
- queryKey
643
- }) => {
644
- const tenantSubs = subscriptions.get(tenantId);
645
- const userSubs = tenantSubs?.get(userId);
646
- const modelSubs = userSubs?.get(modelName);
647
- const sub = modelSubs?.get(queryKey);
648
- const affectedModelNames = /* @__PURE__ */ new Set([modelName, ...sub?.dependencyModelNames ?? []]);
649
- if (sub) {
650
- sub.socketIds.delete(socketId);
651
- sub.windows.delete(socketId);
652
- if (!sub.socketIds.size) {
653
- modelSubs?.delete(queryKey);
654
- }
655
- }
656
- const byModel = socketSubscriptions.get(socketId);
657
- const set = byModel?.get(modelName);
658
- if (set) {
659
- set.delete(queryKey);
660
- if (!set.size) {
661
- byModel?.delete(modelName);
662
- }
663
- }
664
- if (modelSubs && modelSubs.size === 0) {
665
- userSubs?.delete(modelName);
666
- }
667
- if (userSubs && userSubs.size === 0) {
668
- tenantSubs?.delete(userId);
669
- }
670
- for (const affectedModelName of affectedModelNames) {
671
- if (hasAnySubscriptionsDependingOnModel(tenantId, affectedModelName) || hasAnyCountSubscriptionsForModel(tenantId, affectedModelName)) {
672
- continue;
673
- }
674
- const tenantStreams = changeStreams.get(tenantId);
675
- const stream = tenantStreams?.get(affectedModelName);
676
- if (stream) {
677
- try {
678
- stream.close();
679
- } catch {
680
- }
681
- clearDispatchTimer(tenantId, affectedModelName);
682
- tenantStreams?.delete(affectedModelName);
683
- if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
684
- }
685
- }
686
- if (tenantSubs && tenantSubs.size === 0) subscriptions.delete(tenantId);
687
- if (byModel && byModel.size === 0) socketSubscriptions.delete(socketId);
499
+ var addSocketCountSubscription = ({ socketId, tenantId, userId, modelName, queryKey, query }) => {
500
+ const tenantSubs = countSubscriptions.get(tenantId) ?? /* @__PURE__ */ new Map();
501
+ countSubscriptions.set(tenantId, tenantSubs);
502
+ const userSubs = tenantSubs.get(userId) ?? /* @__PURE__ */ new Map();
503
+ tenantSubs.set(userId, userSubs);
504
+ const modelSubs = userSubs.get(modelName) ?? /* @__PURE__ */ new Map();
505
+ userSubs.set(modelName, modelSubs);
506
+ const existing = modelSubs.get(queryKey);
507
+ if (existing) existing.socketIds.add(socketId);
508
+ else modelSubs.set(queryKey, {
509
+ query,
510
+ socketIds: /* @__PURE__ */ new Set([socketId])
511
+ });
512
+ const byModel = socketCountSubscriptions.get(socketId) ?? /* @__PURE__ */ new Map();
513
+ socketCountSubscriptions.set(socketId, byModel);
514
+ const querySet = byModel.get(modelName) ?? /* @__PURE__ */ new Set();
515
+ byModel.set(modelName, querySet);
516
+ querySet.add(queryKey);
688
517
  };
689
- const removeSocketCountSubscription = ({
690
- socketId,
691
- tenantId,
692
- userId,
693
- modelName,
694
- queryKey
695
- }) => {
696
- const tenantSubs = countSubscriptions.get(tenantId);
697
- const userSubs = tenantSubs?.get(userId);
698
- const modelSubs = userSubs?.get(modelName);
699
- const sub = modelSubs?.get(queryKey);
700
- if (sub) {
701
- sub.socketIds.delete(socketId);
702
- if (!sub.socketIds.size) {
703
- modelSubs?.delete(queryKey);
704
- }
705
- }
706
- const byModel = socketCountSubscriptions.get(socketId);
707
- const set = byModel?.get(modelName);
708
- if (set) {
709
- set.delete(queryKey);
710
- if (!set.size) {
711
- byModel?.delete(modelName);
712
- }
713
- }
714
- if (modelSubs && modelSubs.size === 0) {
715
- userSubs?.delete(modelName);
716
- }
717
- if (userSubs && userSubs.size === 0) {
718
- tenantSubs?.delete(userId);
719
- }
720
- if (!hasAnySubscriptionsDependingOnModel(tenantId, modelName) && !hasAnyCountSubscriptionsForModel(tenantId, modelName)) {
721
- const tenantStreams = changeStreams.get(tenantId);
722
- const stream = tenantStreams?.get(modelName);
723
- if (stream) {
724
- try {
725
- stream.close();
726
- } catch {
727
- }
728
- clearDispatchTimer(tenantId, modelName);
729
- tenantStreams?.delete(modelName);
730
- if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
731
- }
732
- }
733
- if (tenantSubs && tenantSubs.size === 0) countSubscriptions.delete(tenantId);
734
- if (byModel && byModel.size === 0) socketCountSubscriptions.delete(socketId);
518
+ var removeSocketSubscription = ({ socketId, tenantId, userId, modelName, queryKey }) => {
519
+ const tenantSubs = subscriptions.get(tenantId);
520
+ const userSubs = tenantSubs?.get(userId);
521
+ const modelSubs = userSubs?.get(modelName);
522
+ const sub = modelSubs?.get(queryKey);
523
+ const affectedModelNames = /* @__PURE__ */ new Set([modelName, ...sub?.dependencyModelNames ?? []]);
524
+ if (sub) {
525
+ sub.socketIds.delete(socketId);
526
+ sub.windows.delete(socketId);
527
+ if (!sub.socketIds.size) modelSubs?.delete(queryKey);
528
+ }
529
+ const byModel = socketSubscriptions.get(socketId);
530
+ const set = byModel?.get(modelName);
531
+ if (set) {
532
+ set.delete(queryKey);
533
+ if (!set.size) byModel?.delete(modelName);
534
+ }
535
+ if (modelSubs && modelSubs.size === 0) userSubs?.delete(modelName);
536
+ if (userSubs && userSubs.size === 0) tenantSubs?.delete(userId);
537
+ for (const affectedModelName of affectedModelNames) {
538
+ if (hasAnySubscriptionsDependingOnModel(tenantId, affectedModelName) || hasAnyCountSubscriptionsForModel(tenantId, affectedModelName)) continue;
539
+ const tenantStreams = changeStreams.get(tenantId);
540
+ const stream = tenantStreams?.get(affectedModelName);
541
+ if (stream) {
542
+ try {
543
+ stream.close();
544
+ } catch {}
545
+ clearDispatchTimer(tenantId, affectedModelName);
546
+ tenantStreams?.delete(affectedModelName);
547
+ if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
548
+ }
549
+ }
550
+ if (tenantSubs && tenantSubs.size === 0) subscriptions.delete(tenantId);
551
+ if (byModel && byModel.size === 0) socketSubscriptions.delete(socketId);
735
552
  };
736
- const getSocketSubscriptionCount = (socketId) => {
737
- let count = 0;
738
- const querySubscriptionsByModel = socketSubscriptions.get(socketId);
739
- if (querySubscriptionsByModel) {
740
- for (const set of querySubscriptionsByModel.values()) count += set.size;
741
- }
742
- const countSubscriptionsByModel = socketCountSubscriptions.get(socketId);
743
- if (countSubscriptionsByModel) {
744
- for (const set of countSubscriptionsByModel.values()) count += set.size;
745
- }
746
- return count;
553
+ var removeSocketCountSubscription = ({ socketId, tenantId, userId, modelName, queryKey }) => {
554
+ const tenantSubs = countSubscriptions.get(tenantId);
555
+ const userSubs = tenantSubs?.get(userId);
556
+ const modelSubs = userSubs?.get(modelName);
557
+ const sub = modelSubs?.get(queryKey);
558
+ if (sub) {
559
+ sub.socketIds.delete(socketId);
560
+ if (!sub.socketIds.size) modelSubs?.delete(queryKey);
561
+ }
562
+ const byModel = socketCountSubscriptions.get(socketId);
563
+ const set = byModel?.get(modelName);
564
+ if (set) {
565
+ set.delete(queryKey);
566
+ if (!set.size) byModel?.delete(modelName);
567
+ }
568
+ if (modelSubs && modelSubs.size === 0) userSubs?.delete(modelName);
569
+ if (userSubs && userSubs.size === 0) tenantSubs?.delete(userId);
570
+ if (!hasAnySubscriptionsDependingOnModel(tenantId, modelName) && !hasAnyCountSubscriptionsForModel(tenantId, modelName)) {
571
+ const tenantStreams = changeStreams.get(tenantId);
572
+ const stream = tenantStreams?.get(modelName);
573
+ if (stream) {
574
+ try {
575
+ stream.close();
576
+ } catch {}
577
+ clearDispatchTimer(tenantId, modelName);
578
+ tenantStreams?.delete(modelName);
579
+ if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
580
+ }
581
+ }
582
+ if (tenantSubs && tenantSubs.size === 0) countSubscriptions.delete(tenantId);
583
+ if (byModel && byModel.size === 0) socketCountSubscriptions.delete(socketId);
747
584
  };
748
- const cleanupSocket = (socketId) => {
749
- const meta = socketMeta.get(socketId);
750
- if (meta) {
751
- const byModel = socketSubscriptions.get(socketId);
752
- if (byModel) {
753
- for (const [modelName, keys] of byModel.entries()) {
754
- for (const queryKey of keys.values()) {
755
- removeSocketSubscription({
756
- socketId,
757
- tenantId: meta.tenantId,
758
- userId: meta.userId,
759
- modelName,
760
- queryKey
761
- });
762
- }
763
- }
764
- }
765
- const countByModel = socketCountSubscriptions.get(socketId);
766
- if (countByModel) {
767
- for (const [modelName, keys] of countByModel.entries()) {
768
- for (const queryKey of keys.values()) {
769
- removeSocketCountSubscription({
770
- socketId,
771
- tenantId: meta.tenantId,
772
- userId: meta.userId,
773
- modelName,
774
- queryKey
775
- });
776
- }
777
- }
778
- }
779
- }
780
- socketSubscriptions.delete(socketId);
781
- socketCountSubscriptions.delete(socketId);
782
- const cleanupFns = socketCleanup.get(socketId) ?? [];
783
- socketCleanup.delete(socketId);
784
- for (const fn of cleanupFns) {
785
- try {
786
- fn();
787
- } catch {
788
- }
789
- }
790
- sockets.delete(socketId);
791
- socketMeta.delete(socketId);
792
- socketWrappers.delete(socketId);
585
+ var getSocketSubscriptionCount = (socketId) => {
586
+ let count = 0;
587
+ const querySubscriptionsByModel = socketSubscriptions.get(socketId);
588
+ if (querySubscriptionsByModel) for (const set of querySubscriptionsByModel.values()) count += set.size;
589
+ const countSubscriptionsByModel = socketCountSubscriptions.get(socketId);
590
+ if (countSubscriptionsByModel) for (const set of countSubscriptionsByModel.values()) count += set.size;
591
+ return count;
793
592
  };
794
- const handleClientMessage = async ({
795
- socketId,
796
- meta,
797
- message
798
- }) => {
799
- const ws = sockets.get(socketId);
800
- if (!ws) return;
801
- if (message.type === "event") {
802
- const wrapper = socketWrappers.get(socketId);
803
- wrapper?.dispatch(message.event, message.payload);
804
- return;
805
- }
806
- if (message.type === "rts-message") {
807
- const wrapper = socketWrappers.get(socketId);
808
- wrapper?.dispatchRtsMessage(message.channel, message.payload);
809
- return;
810
- }
811
- const isCountMessage = message.type === "run-count" || message.type === "register-count" || message.type === "remove-count";
812
- const sendAccessError = (error) => {
813
- if (isCountMessage) {
814
- sendWs(ws, {
815
- type: "count-payload",
816
- modelName: message.modelName ?? "",
817
- queryKey: message.queryKey ?? "",
818
- error
819
- });
820
- return;
821
- }
822
- sendWs(ws, {
823
- type: "query-payload",
824
- modelName: message.modelName ?? "",
825
- queryKey: message.queryKey ?? "",
826
- error
827
- });
828
- };
829
- if (!message.modelName || typeof message.modelName !== "string") return;
830
- if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(message.modelName)) {
831
- sendAccessError("Model not allowed");
832
- return;
833
- }
834
- if (!message.queryKey || typeof message.queryKey !== "string") return;
835
- if (message.queryKey.length > QUERY_KEY_MAX_LEN) return;
836
- if (message.type === "remove-query") {
837
- removeSocketSubscription({
838
- socketId,
839
- tenantId: meta.tenantId,
840
- userId: meta.userId,
841
- modelName: message.modelName,
842
- queryKey: message.queryKey
843
- });
844
- return;
845
- }
846
- if (message.type === "remove-count") {
847
- removeSocketCountSubscription({
848
- socketId,
849
- tenantId: meta.tenantId,
850
- userId: meta.userId,
851
- modelName: message.modelName,
852
- queryKey: message.queryKey
853
- });
854
- return;
855
- }
856
- const ability = meta.ability;
857
- if (!ability.can("read", message.modelName)) {
858
- sendAccessError("forbidden");
859
- return;
860
- }
861
- if (message.type === "set-query-window") {
862
- if (!isValidQueryWindowCount(message.requestedCount)) {
863
- sendWs(ws, {
864
- type: "query-payload",
865
- modelName: message.modelName,
866
- queryKey: message.queryKey,
867
- error: "Invalid requestedCount"
868
- });
869
- return;
870
- }
871
- const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
872
- const window = subscription?.windows.get(socketId);
873
- if (!subscription || !subscription.options.pagination || !window) {
874
- sendWs(ws, {
875
- type: "query-payload",
876
- modelName: message.modelName,
877
- queryKey: message.queryKey,
878
- error: "Paginated query subscription not found"
879
- });
880
- return;
881
- }
882
- window.requestedCount = message.requestedCount;
883
- await runAndSendSubscriptionQuery({
884
- tenantId: meta.tenantId,
885
- targetSocketIds: [socketId],
886
- ability,
887
- modelName: message.modelName,
888
- queryKey: message.queryKey,
889
- subscription
890
- });
891
- return;
892
- }
893
- if (!message.query || typeof message.query !== "object") return;
894
- if (message.type === "register-query" || message.type === "run-query") {
895
- const options = normalizeRtsQueryOptions(message.options);
896
- if (message.type === "register-query") {
897
- if (options.pagination && !isValidQueryWindowCount(options.pagination.limit)) {
898
- sendWs(ws, {
899
- type: "query-payload",
900
- modelName: message.modelName,
901
- queryKey: message.queryKey,
902
- error: "Invalid requestedCount"
903
- });
904
- return;
905
- }
906
- const existing = socketSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false;
907
- if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {
908
- sendWs(ws, {
909
- type: "query-payload",
910
- modelName: message.modelName,
911
- queryKey: message.queryKey,
912
- error: "Too many subscriptions"
913
- });
914
- return;
915
- }
916
- let dependencyModelNames = [];
917
- if (options.populate !== void 0) {
918
- try {
919
- dependencyModelNames = await resolveRtsQueryDependencyModelNames({
920
- tenantId: meta.tenantId,
921
- ability,
922
- modelName: message.modelName,
923
- options,
924
- allowInternalModels
925
- });
926
- } catch (err) {
927
- const error = redactErrorMessage(err);
928
- sendWs(ws, {
929
- type: "query-payload",
930
- modelName: message.modelName,
931
- queryKey: message.queryKey,
932
- error
933
- });
934
- return;
935
- }
936
- }
937
- if (!sockets.has(socketId)) return;
938
- addSocketSubscription({
939
- socketId,
940
- tenantId: meta.tenantId,
941
- userId: meta.userId,
942
- modelName: message.modelName,
943
- queryKey: message.queryKey,
944
- query: message.query,
945
- options,
946
- dependencyModelNames
947
- });
948
- try {
949
- const modelNamesToWatch = /* @__PURE__ */ new Set([message.modelName, ...dependencyModelNames]);
950
- for (const modelName of modelNamesToWatch) {
951
- await ensureChangeStream(meta.tenantId, modelName);
952
- }
953
- } catch (err) {
954
- const error = redactErrorMessage(err);
955
- sendWs(ws, {
956
- type: "query-payload",
957
- modelName: message.modelName,
958
- queryKey: message.queryKey,
959
- error
960
- });
961
- return;
962
- }
963
- if (!sockets.has(socketId)) {
964
- for (const modelName of /* @__PURE__ */ new Set([message.modelName, ...dependencyModelNames])) {
965
- closeUnusedChangeStream(meta.tenantId, modelName);
966
- }
967
- return;
968
- }
969
- if (message.runInitialQuery === false) {
970
- return;
971
- }
972
- const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
973
- if (!subscription) return;
974
- try {
975
- await runAndSendSubscriptionQuery({
976
- tenantId: meta.tenantId,
977
- targetSocketIds: [socketId],
978
- ability,
979
- modelName: message.modelName,
980
- queryKey: message.queryKey,
981
- subscription
982
- });
983
- } catch (err) {
984
- const error = redactErrorMessage(err);
985
- sendWs(ws, {
986
- type: "query-payload",
987
- modelName: message.modelName,
988
- queryKey: message.queryKey,
989
- error
990
- });
991
- }
992
- return;
993
- }
994
- try {
995
- await runAndSendQuery({
996
- tenantId: meta.tenantId,
997
- targetSocketIds: [socketId],
998
- ability,
999
- modelName: message.modelName,
1000
- queryKey: message.queryKey,
1001
- query: message.query,
1002
- options
1003
- });
1004
- } catch (err) {
1005
- const error = redactErrorMessage(err);
1006
- sendWs(ws, {
1007
- type: "query-payload",
1008
- modelName: message.modelName,
1009
- queryKey: message.queryKey,
1010
- error
1011
- });
1012
- }
1013
- return;
1014
- }
1015
- if (message.type === "register-count" || message.type === "run-count") {
1016
- if (message.type === "register-count") {
1017
- const existing = socketCountSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false;
1018
- if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {
1019
- sendWs(ws, {
1020
- type: "count-payload",
1021
- modelName: message.modelName,
1022
- queryKey: message.queryKey,
1023
- error: "Too many subscriptions"
1024
- });
1025
- return;
1026
- }
1027
- addSocketCountSubscription({
1028
- socketId,
1029
- tenantId: meta.tenantId,
1030
- userId: meta.userId,
1031
- modelName: message.modelName,
1032
- queryKey: message.queryKey,
1033
- query: message.query
1034
- });
1035
- try {
1036
- await ensureChangeStream(meta.tenantId, message.modelName);
1037
- } catch (err) {
1038
- const error = redactErrorMessage(err);
1039
- sendWs(ws, {
1040
- type: "count-payload",
1041
- modelName: message.modelName,
1042
- queryKey: message.queryKey,
1043
- error
1044
- });
1045
- return;
1046
- }
1047
- if (!sockets.has(socketId)) {
1048
- closeUnusedChangeStream(meta.tenantId, message.modelName);
1049
- return;
1050
- }
1051
- if (message.runInitialQuery === false) {
1052
- return;
1053
- }
1054
- }
1055
- try {
1056
- await runAndSendCount({
1057
- tenantId: meta.tenantId,
1058
- targetSocketIds: [socketId],
1059
- ability,
1060
- modelName: message.modelName,
1061
- queryKey: message.queryKey,
1062
- query: message.query
1063
- });
1064
- } catch (err) {
1065
- const error = redactErrorMessage(err);
1066
- sendWs(ws, {
1067
- type: "count-payload",
1068
- modelName: message.modelName,
1069
- queryKey: message.queryKey,
1070
- error
1071
- });
1072
- }
1073
- }
593
+ var cleanupSocket = (socketId) => {
594
+ const meta = socketMeta.get(socketId);
595
+ if (meta) {
596
+ const byModel = socketSubscriptions.get(socketId);
597
+ if (byModel) for (const [modelName, keys] of byModel.entries()) for (const queryKey of keys.values()) removeSocketSubscription({
598
+ socketId,
599
+ tenantId: meta.tenantId,
600
+ userId: meta.userId,
601
+ modelName,
602
+ queryKey
603
+ });
604
+ const countByModel = socketCountSubscriptions.get(socketId);
605
+ if (countByModel) for (const [modelName, keys] of countByModel.entries()) for (const queryKey of keys.values()) removeSocketCountSubscription({
606
+ socketId,
607
+ tenantId: meta.tenantId,
608
+ userId: meta.userId,
609
+ modelName,
610
+ queryKey
611
+ });
612
+ }
613
+ socketSubscriptions.delete(socketId);
614
+ socketCountSubscriptions.delete(socketId);
615
+ const cleanupFns = socketCleanup.get(socketId) ?? [];
616
+ socketCleanup.delete(socketId);
617
+ for (const fn of cleanupFns) try {
618
+ fn();
619
+ } catch {}
620
+ sockets.delete(socketId);
621
+ socketMeta.delete(socketId);
622
+ socketWrappers.delete(socketId);
1074
623
  };
1075
- const initRts = ({
1076
- server,
1077
- path = "/rts",
1078
- sessionMiddleware,
1079
- postSyncSessionMiddleware,
1080
- maxPayloadBytes: maxPayloadBytesArg,
1081
- maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg,
1082
- dispatchDebounceMs: dispatchDebounceMsArg,
1083
- allowInternalModels: allowInternalModelsArg
1084
- }) => {
1085
- if (initializedServers.has(server)) return;
1086
- initializedServers.add(server);
1087
- if (typeof maxPayloadBytesArg === "number" && Number.isFinite(maxPayloadBytesArg) && maxPayloadBytesArg > 0) {
1088
- maxPayloadBytes = Math.floor(maxPayloadBytesArg);
1089
- }
1090
- if (typeof maxSubscriptionsPerSocketArg === "number" && Number.isFinite(maxSubscriptionsPerSocketArg) && maxSubscriptionsPerSocketArg > 0) {
1091
- maxSubscriptionsPerSocket = Math.floor(maxSubscriptionsPerSocketArg);
1092
- }
1093
- if (typeof dispatchDebounceMsArg === "number" && Number.isFinite(dispatchDebounceMsArg) && dispatchDebounceMsArg >= 0) {
1094
- dispatchDebounceMs = Math.floor(dispatchDebounceMsArg);
1095
- }
1096
- allowInternalModels = Boolean(allowInternalModelsArg);
1097
- const wss = new WebSocketServer({
1098
- noServer: true,
1099
- maxPayload: maxPayloadBytes
1100
- });
1101
- server.on("upgrade", (req, socket, head) => {
1102
- ensureSocketErrorHandler(socket, () => ({
1103
- upgradeHost: req.headers.host ?? "",
1104
- upgradeUrl: req.url ?? "",
1105
- userAgent: typeof req.headers["user-agent"] === "string" ? req.headers["user-agent"] : ""
1106
- }));
1107
- upgradeMeta.delete(req);
1108
- let url;
1109
- try {
1110
- url = new URL(req.url ?? "", `http://${req.headers.host ?? "localhost"}`);
1111
- } catch {
1112
- badRequest(socket, "Invalid URL");
1113
- return;
1114
- }
1115
- if (url.pathname !== path) return;
1116
- void (async () => {
1117
- try {
1118
- const meta = await parseUpgradeMeta({
1119
- req,
1120
- url,
1121
- sessionMiddleware,
1122
- postSyncSessionMiddleware
1123
- });
1124
- upgradeMeta.set(req, meta);
1125
- wss.handleUpgrade(req, socket, head, (ws) => {
1126
- wss.emit("connection", ws, req);
1127
- });
1128
- } catch (err) {
1129
- const message = err instanceof Error ? err.message : "RTS upgrade failed";
1130
- const upgradeReq = req;
1131
- const sessionUser = upgradeReq.session?.user;
1132
- const sessionUserId = typeof sessionUser?.id === "string" ? sessionUser.id.trim() : "";
1133
- const sessionTenantId = typeof sessionUser?.currentTenantId === "string" ? sessionUser.currentTenantId.trim() : "";
1134
- const authenticatedUserIdHeader = req.headers["rb-authenticated-user-id"];
1135
- const authenticatedTenantIdHeader = req.headers["rb-authenticated-tenant-id"];
1136
- console.warn("[rb/rts] upgrade rejected", {
1137
- reason: message,
1138
- host: req.headers.host ?? "",
1139
- url: req.url ?? "",
1140
- hasSessionUserId: Boolean(sessionUserId),
1141
- hasCurrentTenantId: Boolean(sessionTenantId),
1142
- hasAuthenticatedUserIdHeader: Boolean(Array.isArray(authenticatedUserIdHeader) ? authenticatedUserIdHeader[0] : authenticatedUserIdHeader),
1143
- hasAuthenticatedTenantIdHeader: Boolean(Array.isArray(authenticatedTenantIdHeader) ? authenticatedTenantIdHeader[0] : authenticatedTenantIdHeader),
1144
- userAgent: typeof req.headers["user-agent"] === "string" ? req.headers["user-agent"] : ""
1145
- });
1146
- if (message === "Missing current tenant in session") {
1147
- badRequest(socket, message);
1148
- return;
1149
- }
1150
- unauthorized(socket, message);
1151
- return;
1152
- }
1153
- })().catch(() => {
1154
- badRequest(socket, "RTS upgrade failed");
1155
- });
1156
- });
1157
- wss.on("connection", (ws, req) => {
1158
- const meta = upgradeMeta.get(req);
1159
- upgradeMeta.delete(req);
1160
- if (!meta) {
1161
- try {
1162
- ws.close();
1163
- } catch {
1164
- }
1165
- return;
1166
- }
1167
- const socketId = randomUUID();
1168
- sockets.set(socketId, ws);
1169
- socketMeta.set(socketId, meta);
1170
- const wrapper = new RtsSocket({
1171
- id: socketId,
1172
- ws,
1173
- meta
1174
- });
1175
- socketWrappers.set(socketId, wrapper);
1176
- const cleanupFns = [];
1177
- for (const handler of customHandlers) {
1178
- try {
1179
- const cleanup = handler(wrapper);
1180
- if (typeof cleanup === "function") cleanupFns.push(cleanup);
1181
- } catch {
1182
- }
1183
- }
1184
- if (cleanupFns.length) socketCleanup.set(socketId, cleanupFns);
1185
- let messageQueue = Promise.resolve();
1186
- ws.on("message", (raw) => {
1187
- let parsed;
1188
- try {
1189
- parsed = safeJsonParse(raw);
1190
- } catch {
1191
- return;
1192
- }
1193
- if (!parsed || typeof parsed !== "object") return;
1194
- const message = parsed;
1195
- if (message.type !== "event" && message.type !== "rts-message" && message.type !== "run-query" && message.type !== "register-query" && message.type !== "set-query-window" && message.type !== "remove-query" && message.type !== "run-count" && message.type !== "register-count" && message.type !== "remove-count") return;
1196
- messageQueue = messageQueue.then(() => handleClientMessage({
1197
- socketId,
1198
- meta,
1199
- message
1200
- })).catch(() => void 0);
1201
- });
1202
- ws.on("close", () => {
1203
- cleanupSocket(socketId);
1204
- });
1205
- ws.on("error", () => {
1206
- cleanupSocket(socketId);
1207
- });
1208
- });
624
+ var handleClientMessage = async ({ socketId, meta, message }) => {
625
+ const ws = sockets.get(socketId);
626
+ if (!ws) return;
627
+ if (message.type === "event") {
628
+ socketWrappers.get(socketId)?.dispatch(message.event, message.payload);
629
+ return;
630
+ }
631
+ if (message.type === "rts-message") {
632
+ socketWrappers.get(socketId)?.dispatchRtsMessage(message.channel, message.payload);
633
+ return;
634
+ }
635
+ const isCountMessage = message.type === "run-count" || message.type === "register-count" || message.type === "remove-count";
636
+ const sendAccessError = (error) => {
637
+ if (isCountMessage) {
638
+ sendWs(ws, {
639
+ type: "count-payload",
640
+ modelName: message.modelName ?? "",
641
+ queryKey: message.queryKey ?? "",
642
+ error
643
+ });
644
+ return;
645
+ }
646
+ sendWs(ws, {
647
+ type: "query-payload",
648
+ modelName: message.modelName ?? "",
649
+ queryKey: message.queryKey ?? "",
650
+ error
651
+ });
652
+ };
653
+ if (!message.modelName || typeof message.modelName !== "string") return;
654
+ if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(message.modelName)) {
655
+ sendAccessError("Model not allowed");
656
+ return;
657
+ }
658
+ if (!message.queryKey || typeof message.queryKey !== "string") return;
659
+ if (message.queryKey.length > QUERY_KEY_MAX_LEN) return;
660
+ if (message.type === "remove-query") {
661
+ removeSocketSubscription({
662
+ socketId,
663
+ tenantId: meta.tenantId,
664
+ userId: meta.userId,
665
+ modelName: message.modelName,
666
+ queryKey: message.queryKey
667
+ });
668
+ return;
669
+ }
670
+ if (message.type === "remove-count") {
671
+ removeSocketCountSubscription({
672
+ socketId,
673
+ tenantId: meta.tenantId,
674
+ userId: meta.userId,
675
+ modelName: message.modelName,
676
+ queryKey: message.queryKey
677
+ });
678
+ return;
679
+ }
680
+ const ability = meta.ability;
681
+ if (!ability.can("read", message.modelName)) {
682
+ sendAccessError("forbidden");
683
+ return;
684
+ }
685
+ if (message.type === "set-query-window") {
686
+ if (!isValidQueryWindowCount(message.requestedCount)) {
687
+ sendWs(ws, {
688
+ type: "query-payload",
689
+ modelName: message.modelName,
690
+ queryKey: message.queryKey,
691
+ error: "Invalid requestedCount"
692
+ });
693
+ return;
694
+ }
695
+ const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
696
+ const window = subscription?.windows.get(socketId);
697
+ if (!subscription || !subscription.options.pagination || !window) {
698
+ sendWs(ws, {
699
+ type: "query-payload",
700
+ modelName: message.modelName,
701
+ queryKey: message.queryKey,
702
+ error: "Paginated query subscription not found"
703
+ });
704
+ return;
705
+ }
706
+ window.requestedCount = message.requestedCount;
707
+ await runAndSendSubscriptionQuery({
708
+ tenantId: meta.tenantId,
709
+ targetSocketIds: [socketId],
710
+ ability,
711
+ modelName: message.modelName,
712
+ queryKey: message.queryKey,
713
+ subscription
714
+ });
715
+ return;
716
+ }
717
+ if (!message.query || typeof message.query !== "object") return;
718
+ if (message.type === "register-query" || message.type === "run-query") {
719
+ const options = normalizeRtsQueryOptions(message.options);
720
+ if (message.type === "register-query") {
721
+ if (options.pagination && !isValidQueryWindowCount(options.pagination.limit)) {
722
+ sendWs(ws, {
723
+ type: "query-payload",
724
+ modelName: message.modelName,
725
+ queryKey: message.queryKey,
726
+ error: "Invalid requestedCount"
727
+ });
728
+ return;
729
+ }
730
+ if (!(socketSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false) && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {
731
+ sendWs(ws, {
732
+ type: "query-payload",
733
+ modelName: message.modelName,
734
+ queryKey: message.queryKey,
735
+ error: "Too many subscriptions"
736
+ });
737
+ return;
738
+ }
739
+ let dependencyModelNames = [];
740
+ if (options.populate !== void 0) try {
741
+ dependencyModelNames = await resolveRtsQueryDependencyModelNames({
742
+ tenantId: meta.tenantId,
743
+ ability,
744
+ modelName: message.modelName,
745
+ options,
746
+ allowInternalModels
747
+ });
748
+ } catch (err) {
749
+ const error = redactErrorMessage(err);
750
+ sendWs(ws, {
751
+ type: "query-payload",
752
+ modelName: message.modelName,
753
+ queryKey: message.queryKey,
754
+ error
755
+ });
756
+ return;
757
+ }
758
+ if (!sockets.has(socketId)) return;
759
+ addSocketSubscription({
760
+ socketId,
761
+ tenantId: meta.tenantId,
762
+ userId: meta.userId,
763
+ modelName: message.modelName,
764
+ queryKey: message.queryKey,
765
+ query: message.query,
766
+ options,
767
+ dependencyModelNames
768
+ });
769
+ try {
770
+ const modelNamesToWatch = /* @__PURE__ */ new Set([message.modelName, ...dependencyModelNames]);
771
+ for (const modelName of modelNamesToWatch) await ensureChangeStream(meta.tenantId, modelName);
772
+ } catch (err) {
773
+ const error = redactErrorMessage(err);
774
+ sendWs(ws, {
775
+ type: "query-payload",
776
+ modelName: message.modelName,
777
+ queryKey: message.queryKey,
778
+ error
779
+ });
780
+ return;
781
+ }
782
+ if (!sockets.has(socketId)) {
783
+ for (const modelName of /* @__PURE__ */ new Set([message.modelName, ...dependencyModelNames])) closeUnusedChangeStream(meta.tenantId, modelName);
784
+ return;
785
+ }
786
+ if (message.runInitialQuery === false) return;
787
+ const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
788
+ if (!subscription) return;
789
+ try {
790
+ await runAndSendSubscriptionQuery({
791
+ tenantId: meta.tenantId,
792
+ targetSocketIds: [socketId],
793
+ ability,
794
+ modelName: message.modelName,
795
+ queryKey: message.queryKey,
796
+ subscription
797
+ });
798
+ } catch (err) {
799
+ const error = redactErrorMessage(err);
800
+ sendWs(ws, {
801
+ type: "query-payload",
802
+ modelName: message.modelName,
803
+ queryKey: message.queryKey,
804
+ error
805
+ });
806
+ }
807
+ return;
808
+ }
809
+ try {
810
+ await runAndSendQuery({
811
+ tenantId: meta.tenantId,
812
+ targetSocketIds: [socketId],
813
+ ability,
814
+ modelName: message.modelName,
815
+ queryKey: message.queryKey,
816
+ query: message.query,
817
+ options
818
+ });
819
+ } catch (err) {
820
+ const error = redactErrorMessage(err);
821
+ sendWs(ws, {
822
+ type: "query-payload",
823
+ modelName: message.modelName,
824
+ queryKey: message.queryKey,
825
+ error
826
+ });
827
+ }
828
+ return;
829
+ }
830
+ if (message.type === "register-count" || message.type === "run-count") {
831
+ if (message.type === "register-count") {
832
+ if (!(socketCountSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false) && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {
833
+ sendWs(ws, {
834
+ type: "count-payload",
835
+ modelName: message.modelName,
836
+ queryKey: message.queryKey,
837
+ error: "Too many subscriptions"
838
+ });
839
+ return;
840
+ }
841
+ addSocketCountSubscription({
842
+ socketId,
843
+ tenantId: meta.tenantId,
844
+ userId: meta.userId,
845
+ modelName: message.modelName,
846
+ queryKey: message.queryKey,
847
+ query: message.query
848
+ });
849
+ try {
850
+ await ensureChangeStream(meta.tenantId, message.modelName);
851
+ } catch (err) {
852
+ const error = redactErrorMessage(err);
853
+ sendWs(ws, {
854
+ type: "count-payload",
855
+ modelName: message.modelName,
856
+ queryKey: message.queryKey,
857
+ error
858
+ });
859
+ return;
860
+ }
861
+ if (!sockets.has(socketId)) {
862
+ closeUnusedChangeStream(meta.tenantId, message.modelName);
863
+ return;
864
+ }
865
+ if (message.runInitialQuery === false) return;
866
+ }
867
+ try {
868
+ await runAndSendCount({
869
+ tenantId: meta.tenantId,
870
+ targetSocketIds: [socketId],
871
+ ability,
872
+ modelName: message.modelName,
873
+ queryKey: message.queryKey,
874
+ query: message.query
875
+ });
876
+ } catch (err) {
877
+ const error = redactErrorMessage(err);
878
+ sendWs(ws, {
879
+ type: "count-payload",
880
+ modelName: message.modelName,
881
+ queryKey: message.queryKey,
882
+ error
883
+ });
884
+ }
885
+ }
1209
886
  };
1210
- const registerRtsHandler = (handler) => {
1211
- customHandlers.push(handler);
887
+ var initRts = ({ server, path = "/rts", sessionMiddleware, postSyncSessionMiddleware, maxPayloadBytes: maxPayloadBytesArg, maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg, dispatchDebounceMs: dispatchDebounceMsArg, allowInternalModels: allowInternalModelsArg }) => {
888
+ if (initializedServers.has(server)) return;
889
+ initializedServers.add(server);
890
+ if (typeof maxPayloadBytesArg === "number" && Number.isFinite(maxPayloadBytesArg) && maxPayloadBytesArg > 0) maxPayloadBytes = Math.floor(maxPayloadBytesArg);
891
+ if (typeof maxSubscriptionsPerSocketArg === "number" && Number.isFinite(maxSubscriptionsPerSocketArg) && maxSubscriptionsPerSocketArg > 0) maxSubscriptionsPerSocket = Math.floor(maxSubscriptionsPerSocketArg);
892
+ if (typeof dispatchDebounceMsArg === "number" && Number.isFinite(dispatchDebounceMsArg) && dispatchDebounceMsArg >= 0) dispatchDebounceMs = Math.floor(dispatchDebounceMsArg);
893
+ allowInternalModels = Boolean(allowInternalModelsArg);
894
+ const wss = new WebSocketServer({
895
+ noServer: true,
896
+ maxPayload: maxPayloadBytes
897
+ });
898
+ server.on("upgrade", (req, socket, head) => {
899
+ ensureSocketErrorHandler(socket, () => ({
900
+ upgradeHost: req.headers.host ?? "",
901
+ upgradeUrl: req.url ?? "",
902
+ userAgent: typeof req.headers["user-agent"] === "string" ? req.headers["user-agent"] : ""
903
+ }));
904
+ upgradeMeta.delete(req);
905
+ let url;
906
+ try {
907
+ url = new URL(req.url ?? "", `http://${req.headers.host ?? "localhost"}`);
908
+ } catch {
909
+ badRequest(socket, "Invalid URL");
910
+ return;
911
+ }
912
+ if (url.pathname !== path) return;
913
+ (async () => {
914
+ try {
915
+ const meta = await parseUpgradeMeta({
916
+ req,
917
+ url,
918
+ sessionMiddleware,
919
+ postSyncSessionMiddleware
920
+ });
921
+ upgradeMeta.set(req, meta);
922
+ wss.handleUpgrade(req, socket, head, (ws) => {
923
+ wss.emit("connection", ws, req);
924
+ });
925
+ } catch (err) {
926
+ const message = err instanceof Error ? err.message : "RTS upgrade failed";
927
+ const sessionUser = req.session?.user;
928
+ const sessionUserId = typeof sessionUser?.id === "string" ? sessionUser.id.trim() : "";
929
+ const sessionTenantId = typeof sessionUser?.currentTenantId === "string" ? sessionUser.currentTenantId.trim() : "";
930
+ const authenticatedUserIdHeader = req.headers["rb-authenticated-user-id"];
931
+ const authenticatedTenantIdHeader = req.headers["rb-authenticated-tenant-id"];
932
+ console.warn("[rb/rts] upgrade rejected", {
933
+ reason: message,
934
+ host: req.headers.host ?? "",
935
+ url: req.url ?? "",
936
+ hasSessionUserId: Boolean(sessionUserId),
937
+ hasCurrentTenantId: Boolean(sessionTenantId),
938
+ hasAuthenticatedUserIdHeader: Boolean(Array.isArray(authenticatedUserIdHeader) ? authenticatedUserIdHeader[0] : authenticatedUserIdHeader),
939
+ hasAuthenticatedTenantIdHeader: Boolean(Array.isArray(authenticatedTenantIdHeader) ? authenticatedTenantIdHeader[0] : authenticatedTenantIdHeader),
940
+ userAgent: typeof req.headers["user-agent"] === "string" ? req.headers["user-agent"] : ""
941
+ });
942
+ if (message === "Missing current tenant in session") {
943
+ badRequest(socket, message);
944
+ return;
945
+ }
946
+ unauthorized(socket, message);
947
+ return;
948
+ }
949
+ })().catch(() => {
950
+ badRequest(socket, "RTS upgrade failed");
951
+ });
952
+ });
953
+ wss.on("connection", (ws, req) => {
954
+ const meta = upgradeMeta.get(req);
955
+ upgradeMeta.delete(req);
956
+ if (!meta) {
957
+ try {
958
+ ws.close();
959
+ } catch {}
960
+ return;
961
+ }
962
+ const socketId = randomUUID();
963
+ sockets.set(socketId, ws);
964
+ socketMeta.set(socketId, meta);
965
+ const wrapper = new RtsSocket({
966
+ id: socketId,
967
+ ws,
968
+ meta
969
+ });
970
+ socketWrappers.set(socketId, wrapper);
971
+ const cleanupFns = [];
972
+ for (const handler of customHandlers) try {
973
+ const cleanup = handler(wrapper);
974
+ if (typeof cleanup === "function") cleanupFns.push(cleanup);
975
+ } catch {}
976
+ if (cleanupFns.length) socketCleanup.set(socketId, cleanupFns);
977
+ let messageQueue = Promise.resolve();
978
+ ws.on("message", (raw) => {
979
+ let parsed;
980
+ try {
981
+ parsed = safeJsonParse(raw);
982
+ } catch {
983
+ return;
984
+ }
985
+ if (!parsed || typeof parsed !== "object") return;
986
+ const message = parsed;
987
+ if (message.type !== "event" && message.type !== "rts-message" && message.type !== "run-query" && message.type !== "register-query" && message.type !== "set-query-window" && message.type !== "remove-query" && message.type !== "run-count" && message.type !== "register-count" && message.type !== "remove-count") return;
988
+ messageQueue = messageQueue.then(() => handleClientMessage({
989
+ socketId,
990
+ meta,
991
+ message
992
+ })).catch(() => void 0);
993
+ });
994
+ ws.on("close", () => {
995
+ cleanupSocket(socketId);
996
+ });
997
+ ws.on("error", () => {
998
+ cleanupSocket(socketId);
999
+ });
1000
+ });
1212
1001
  };
1213
- const publishRtsMessage = ({
1214
- tenantId,
1215
- userId,
1216
- channel,
1217
- payload
1218
- }) => {
1219
- const normalizedTenantId = tenantId.trim();
1220
- const normalizedUserId = userId?.trim();
1221
- const normalizedChannel = channel.trim();
1222
- if (!normalizedTenantId || !normalizedChannel) return;
1223
- for (const [socketId, meta] of socketMeta.entries()) {
1224
- if (meta.tenantId !== normalizedTenantId) continue;
1225
- if (normalizedUserId && meta.userId !== normalizedUserId) continue;
1226
- const ws = sockets.get(socketId);
1227
- if (!ws) continue;
1228
- sendWs(ws, {
1229
- type: "rts-message",
1230
- channel: normalizedChannel,
1231
- payload
1232
- });
1233
- }
1002
+ var registerRtsHandler = (handler) => {
1003
+ customHandlers.push(handler);
1234
1004
  };
1235
- const notifyRtsModelChanged = (tenantId, modelName) => {
1236
- scheduleDispatchSubscriptionsForModel(tenantId, modelName);
1005
+ var publishRtsMessage = ({ tenantId, userId, channel, payload }) => {
1006
+ const normalizedTenantId = tenantId.trim();
1007
+ const normalizedUserId = userId?.trim();
1008
+ const normalizedChannel = channel.trim();
1009
+ if (!normalizedTenantId || !normalizedChannel) return;
1010
+ for (const [socketId, meta] of socketMeta.entries()) {
1011
+ if (meta.tenantId !== normalizedTenantId) continue;
1012
+ if (normalizedUserId && meta.userId !== normalizedUserId) continue;
1013
+ const ws = sockets.get(socketId);
1014
+ if (!ws) continue;
1015
+ sendWs(ws, {
1016
+ type: "rts-message",
1017
+ channel: normalizedChannel,
1018
+ payload
1019
+ });
1020
+ }
1237
1021
  };
1238
- export {
1239
- initRts,
1240
- notifyRtsModelChanged,
1241
- publishRtsMessage,
1242
- registerRtsHandler,
1243
- routes
1022
+ var notifyRtsModelChanged = (tenantId, modelName) => {
1023
+ scheduleDispatchSubscriptionsForModel(tenantId, modelName);
1244
1024
  };
1245
- //# sourceMappingURL=index.js.map
1025
+ //#endregion
1026
+ export { initRts, notifyRtsModelChanged, publishRtsMessage, registerRtsHandler, routes };
1027
+
1028
+ //# sourceMappingURL=index.js.map