@rpcbase/server 0.594.0 → 0.596.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/convertHeifToWebp-BT1n72DQ.js +148 -0
- package/dist/convertHeifToWebp-BT1n72DQ.js.map +1 -0
- package/dist/email-Co1GNjlT.js +7204 -0
- package/dist/email-Co1GNjlT.js.map +1 -0
- package/dist/handler-BqlcQ9sE.js +245 -0
- package/dist/handler-BqlcQ9sE.js.map +1 -0
- package/dist/handler-C92_gJkX.js +743 -0
- package/dist/handler-C92_gJkX.js.map +1 -0
- package/dist/handler-CapJTGzc.js +795 -0
- package/dist/handler-CapJTGzc.js.map +1 -0
- package/dist/handler-Fk-5fOSm.js +119 -0
- package/dist/handler-Fk-5fOSm.js.map +1 -0
- package/dist/htmlTemplate.d.ts +16 -0
- package/dist/htmlTemplate.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5140 -5286
- package/dist/index.js.map +1 -1
- package/dist/notifications.js +273 -382
- package/dist/notifications.js.map +1 -1
- package/dist/postProcessors-iffHvje4.js +89 -0
- package/dist/postProcessors-iffHvje4.js.map +1 -0
- package/dist/queryWindow-DP8zD0lb.js +555 -0
- package/dist/queryWindow-DP8zD0lb.js.map +1 -0
- package/dist/render_resend-B1SSQ4f7.js +7 -0
- package/dist/render_resend-B1SSQ4f7.js.map +1 -0
- package/dist/rts/index.js +990 -1207
- package/dist/rts/index.js.map +1 -1
- package/dist/schemas-B2fUvgYo.js +4151 -0
- package/dist/schemas-B2fUvgYo.js.map +1 -0
- package/dist/shared-DfrVDSp0.js +79 -0
- package/dist/shared-DfrVDSp0.js.map +1 -0
- package/dist/ssrMiddleware.d.ts +7 -3
- package/dist/ssrMiddleware.d.ts.map +1 -1
- package/dist/uploads/worker.js +139 -168
- package/dist/uploads/worker.js.map +1 -1
- package/dist/uploads.js +12 -22
- package/dist/uploads.js.map +1 -1
- package/package.json +1 -1
- package/dist/convertHeifToWebp-C-DGXZ2k.js +0 -169
- package/dist/convertHeifToWebp-C-DGXZ2k.js.map +0 -1
- package/dist/email-BCf24GmK.js +0 -8071
- package/dist/email-BCf24GmK.js.map +0 -1
- package/dist/handler-BqoKvylN.js +0 -147
- package/dist/handler-BqoKvylN.js.map +0 -1
- package/dist/handler-CUOJ51-w.js +0 -903
- package/dist/handler-CUOJ51-w.js.map +0 -1
- package/dist/handler-D-XdgeG_.js +0 -986
- package/dist/handler-D-XdgeG_.js.map +0 -1
- package/dist/handler-F0gFTzvh.js +0 -275
- package/dist/handler-F0gFTzvh.js.map +0 -1
- package/dist/postProcessors-D27fGZP0.js +0 -107
- package/dist/postProcessors-D27fGZP0.js.map +0 -1
- package/dist/queryWindow-Cdr7K-S1.js +0 -714
- package/dist/queryWindow-Cdr7K-S1.js.map +0 -1
- package/dist/render_resend_false-MiC__Smr.js +0 -6
- package/dist/render_resend_false-MiC__Smr.js.map +0 -1
- package/dist/schemas-Drf83ni9.js +0 -4517
- package/dist/schemas-Drf83ni9.js.map +0 -1
- package/dist/shared-CJrm9Wjp.js +0 -104
- package/dist/shared-CJrm9Wjp.js.map +0 -1
package/dist/rts/index.js
CHANGED
|
@@ -1,1245 +1,1028 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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
|
-
|
|
414
|
-
|
|
415
|
-
|
|
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
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
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
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
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
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
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
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
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
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
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
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
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
|
-
|
|
1211
|
-
|
|
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
|
-
|
|
1214
|
-
|
|
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
|
-
|
|
1236
|
-
|
|
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
|
-
|
|
1239
|
-
|
|
1240
|
-
notifyRtsModelChanged,
|
|
1241
|
-
publishRtsMessage,
|
|
1242
|
-
registerRtsHandler,
|
|
1243
|
-
routes
|
|
1022
|
+
var notifyRtsModelChanged = (tenantId, modelName) => {
|
|
1023
|
+
scheduleDispatchSubscriptionsForModel(tenantId, modelName);
|
|
1244
1024
|
};
|
|
1245
|
-
//#
|
|
1025
|
+
//#endregion
|
|
1026
|
+
export { initRts, notifyRtsModelChanged, publishRtsMessage, registerRtsHandler, routes };
|
|
1027
|
+
|
|
1028
|
+
//# sourceMappingURL=index.js.map
|