@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
@@ -1,714 +0,0 @@
1
- import { models } from "@rpcbase/db";
2
- import { createHmac, timingSafeEqual } from "node:crypto";
3
- import { getAccessibleByQuery, buildAbilityFromSession } from "@rpcbase/db/acl";
4
- import assert from "assert";
5
- import { hkdfSync } from "crypto";
6
- const getDerivedKey = (masterKey, info, length = 32, salt = "") => {
7
- assert(masterKey?.length >= 32, "MASTER_KEY must be 32 chars or longer.");
8
- return Buffer.from(hkdfSync("sha256", masterKey, Buffer.from(salt), Buffer.from(info), length)).toString("hex");
9
- };
10
- const AUTHENTICATED_USER_ID_HEADER = "rb-authenticated-user-id";
11
- const AUTHENTICATED_TENANT_ID_HEADER = "rb-authenticated-tenant-id";
12
- const PROXY_AUTH_TIMESTAMP_HEADER = "rb-proxy-auth-timestamp";
13
- const PROXY_AUTH_SIGNATURE_HEADER = "rb-proxy-auth-signature";
14
- const MAX_PROXY_AUTH_AGE_MS = 5 * 60 * 1e3;
15
- const normalizeString$2 = (value) => {
16
- if (typeof value !== "string") return null;
17
- const normalized = value.trim();
18
- return normalized || null;
19
- };
20
- const getHeaderValue = (headers, name) => {
21
- const value = headers?.[name];
22
- if (Array.isArray(value)) return normalizeString$2(value[0]);
23
- return normalizeString$2(value);
24
- };
25
- const getProxySharedSecret = () => {
26
- const secret = process.env.RB_PROXY_SHARED_SECRET?.trim();
27
- return secret || null;
28
- };
29
- const timingSafeEqualText = (left, right) => {
30
- const leftBuffer = Buffer.from(left);
31
- const rightBuffer = Buffer.from(right);
32
- if (leftBuffer.length !== rightBuffer.length) return false;
33
- return timingSafeEqual(leftBuffer, rightBuffer);
34
- };
35
- const buildProxyAuthSignature = ({
36
- userId,
37
- tenantId,
38
- timestamp,
39
- secret
40
- }) => {
41
- return createHmac("sha256", secret).update(`${timestamp}:${userId}:${tenantId}`).digest("hex");
42
- };
43
- const getTrustedProxyAuth = (headers) => {
44
- const userId = getHeaderValue(headers, AUTHENTICATED_USER_ID_HEADER);
45
- const tenantId = getHeaderValue(headers, AUTHENTICATED_TENANT_ID_HEADER);
46
- const timestamp = getHeaderValue(headers, PROXY_AUTH_TIMESTAMP_HEADER);
47
- const signature = getHeaderValue(headers, PROXY_AUTH_SIGNATURE_HEADER);
48
- if (!userId || !tenantId || !timestamp || !signature) return null;
49
- const parsedTimestamp = Number(timestamp);
50
- if (!Number.isInteger(parsedTimestamp)) return null;
51
- const now = Date.now();
52
- if (Math.abs(now - parsedTimestamp) > MAX_PROXY_AUTH_AGE_MS) return null;
53
- const secret = getProxySharedSecret();
54
- if (!secret) return null;
55
- const expectedSignature = buildProxyAuthSignature({
56
- userId,
57
- tenantId,
58
- timestamp,
59
- secret
60
- });
61
- if (!timingSafeEqualText(signature, expectedSignature)) return null;
62
- return {
63
- userId,
64
- tenantId
65
- };
66
- };
67
- const normalizeString$1 = (value) => {
68
- if (typeof value !== "string") return null;
69
- const normalized = value.trim();
70
- return normalized || null;
71
- };
72
- const normalizeStringArray = (value) => {
73
- if (!Array.isArray(value)) return [];
74
- return value.map((entry) => normalizeString$1(String(entry))).filter((entry) => Boolean(entry));
75
- };
76
- const normalizeRoles = (value) => {
77
- if (!Array.isArray(value)) return [];
78
- return value.map((entry) => normalizeString$1(entry)).filter((entry) => Boolean(entry));
79
- };
80
- const normalizeTenantRoles = (value) => {
81
- if (!value || typeof value !== "object") return void 0;
82
- if (value instanceof Map) {
83
- const entries = Array.from(value.entries()).map(([tenantId, roles]) => {
84
- const normalizedTenantId = normalizeString$1(String(tenantId));
85
- if (!normalizedTenantId) return null;
86
- return [normalizedTenantId, normalizeRoles(roles)];
87
- }).filter((entry) => Boolean(entry));
88
- return entries.length ? Object.fromEntries(entries) : void 0;
89
- }
90
- const nextRoles = Object.entries(value).map(([tenantId, roles]) => {
91
- const normalizedTenantId = normalizeString$1(tenantId);
92
- if (!normalizedTenantId) return null;
93
- return [normalizedTenantId, normalizeRoles(roles)];
94
- }).filter((entry) => Boolean(entry));
95
- return nextRoles.length ? Object.fromEntries(nextRoles) : void 0;
96
- };
97
- const isSessionAuthorizedForTenant = (sessionUser, tenantId) => {
98
- if (!sessionUser) return false;
99
- const signedInTenants = normalizeStringArray(sessionUser.signedInTenants);
100
- if (signedInTenants.length > 0) {
101
- return signedInTenants.includes(tenantId);
102
- }
103
- const currentTenantId = normalizeString$1(sessionUser.currentTenantId);
104
- return currentTenantId === tenantId;
105
- };
106
- const loadSessionUser = async (userId, tenantId) => {
107
- const ctx = {
108
- req: {
109
- session: null
110
- }
111
- };
112
- const User = await models.getGlobal("RBUser", ctx);
113
- const user = await User.findById(userId, {
114
- tenants: 1,
115
- tenantRoles: 1
116
- }).lean();
117
- if (!user) return null;
118
- const signedInTenants = normalizeStringArray(user.tenants);
119
- if (!signedInTenants.includes(tenantId)) return null;
120
- const tenantRoles = normalizeTenantRoles(user.tenantRoles);
121
- return {
122
- id: userId,
123
- currentTenantId: tenantId,
124
- signedInTenants,
125
- isEntryGateAuthorized: true,
126
- ...tenantRoles ? {
127
- tenantRoles
128
- } : {}
129
- };
130
- };
131
- const syncAuthenticatedSessionFromRequest = async (req) => {
132
- const proxyAuth = getTrustedProxyAuth(req.headers);
133
- if (!proxyAuth) return;
134
- const {
135
- userId,
136
- tenantId
137
- } = proxyAuth;
138
- const session = req.session;
139
- if (!session) return;
140
- const sessionUser = session.user;
141
- const sessionUserId = normalizeString$1(sessionUser?.id);
142
- if (sessionUserId === userId && isSessionAuthorizedForTenant(sessionUser, tenantId)) {
143
- const currentTenantId = normalizeString$1(sessionUser?.currentTenantId);
144
- if (currentTenantId === tenantId) return;
145
- const baseUser = sessionUser && typeof sessionUser === "object" ? sessionUser : {};
146
- session.user = {
147
- ...baseUser,
148
- id: userId,
149
- currentTenantId: tenantId,
150
- isEntryGateAuthorized: true
151
- };
152
- return;
153
- }
154
- const nextSessionUser = await loadSessionUser(userId, tenantId);
155
- if (!nextSessionUser) {
156
- if (session.user) {
157
- delete session.user;
158
- }
159
- return;
160
- }
161
- session.user = nextSessionUser;
162
- };
163
- const syncAuthenticatedSessionMiddleware = (req, _res, next) => {
164
- void syncAuthenticatedSessionFromRequest(req).then(() => {
165
- next();
166
- }, next);
167
- };
168
- const QUERY_MAX_LIMIT = 4096;
169
- const INTERNAL_MODEL_NAMES = /* @__PURE__ */ new Set(["RBRtsChange", "RBRtsCounter"]);
170
- const DEFAULT_APPROX_COUNT_SAMPLE_SIZE = 1e3;
171
- const MAX_APPROX_COUNT_SAMPLE_SIZE = 1e4;
172
- const UNSUPPORTED_APPROX_COUNT_OPERATORS = /* @__PURE__ */ new Set(["$text", "$near", "$nearSphere", "$where"]);
173
- let paginationCursorSigningSecret = null;
174
- const getPaginationCursorSigningSecret = () => {
175
- if (paginationCursorSigningSecret) return paginationCursorSigningSecret;
176
- const masterKey = process.env.MASTER_KEY?.trim();
177
- if (!masterKey) {
178
- throw new Error("MASTER_KEY must be defined to derive pagination cursor signing secret");
179
- }
180
- paginationCursorSigningSecret = getDerivedKey(masterKey, "pagination_cursor_signing");
181
- return paginationCursorSigningSecret;
182
- };
183
- const normalizeTenantId = (value) => {
184
- if (typeof value !== "string") return null;
185
- const normalized = value.trim();
186
- return normalized ? normalized : null;
187
- };
188
- const getTenantIdFromRequest = (req) => {
189
- return normalizeTenantId(req.session?.user?.currentTenantId);
190
- };
191
- const resolveRtsRequestTenantId = (req) => {
192
- return getTenantIdFromRequest(req);
193
- };
194
- const isRtsRequestAuthorized = (req, tenantId) => {
195
- const sessionUser = req.session?.user;
196
- if (!sessionUser) return false;
197
- const currentTenantId = normalizeTenantId(sessionUser.currentTenantId);
198
- if (!currentTenantId) return false;
199
- return currentTenantId === tenantId;
200
- };
201
- const buildRtsAbilityFromRequest = async (req, tenantId) => {
202
- const sessionUserId = normalizeTenantId(req.session?.user?.id);
203
- if (!sessionUserId) {
204
- const currentTenantId2 = normalizeTenantId(req.session?.user?.currentTenantId);
205
- if (!currentTenantId2 || currentTenantId2 !== tenantId) {
206
- throw new Error("Tenant not authorized for this session");
207
- }
208
- return {
209
- ability: buildAbilityFromSession({
210
- tenantId,
211
- session: req.session
212
- }),
213
- userId: null
214
- };
215
- }
216
- const currentTenantId = normalizeTenantId(req.session?.user?.currentTenantId);
217
- if (!currentTenantId || currentTenantId !== tenantId) {
218
- throw new Error("Tenant not authorized for this session");
219
- }
220
- return {
221
- ability: buildAbilityFromSession({
222
- tenantId,
223
- session: req.session
224
- }),
225
- userId: sessionUserId
226
- };
227
- };
228
- const getTenantModel = async (tenantId, modelName, ability) => {
229
- const ctx = {
230
- req: {
231
- session: {
232
- user: {
233
- currentTenantId: tenantId
234
- }
235
- }
236
- },
237
- ability
238
- };
239
- return models.get(modelName, ctx);
240
- };
241
- const normalizeLimit = (limit) => {
242
- if (typeof limit !== "number") return QUERY_MAX_LIMIT;
243
- if (!Number.isFinite(limit)) return QUERY_MAX_LIMIT;
244
- return Math.min(QUERY_MAX_LIMIT, Math.abs(limit));
245
- };
246
- const normalizeNonNegativeInteger = (value) => {
247
- if (typeof value !== "number") return 0;
248
- if (!Number.isFinite(value) || value < 0) return 0;
249
- return Math.floor(value);
250
- };
251
- const getApproxCountSampleSize = () => {
252
- const raw = process.env.RB_RTS_APPROX_COUNT_SAMPLE_SIZE?.trim() ?? "";
253
- if (!raw) return DEFAULT_APPROX_COUNT_SAMPLE_SIZE;
254
- const parsed = Number(raw);
255
- if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_APPROX_COUNT_SAMPLE_SIZE;
256
- return Math.min(MAX_APPROX_COUNT_SAMPLE_SIZE, Math.floor(parsed));
257
- };
258
- const findUnsupportedApproxCountOperator = (value) => {
259
- if (!value || typeof value !== "object") return null;
260
- if (Array.isArray(value)) {
261
- for (const entry of value) {
262
- const unsupportedOperator = findUnsupportedApproxCountOperator(entry);
263
- if (unsupportedOperator) return unsupportedOperator;
264
- }
265
- return null;
266
- }
267
- for (const [key, nestedValue] of Object.entries(value)) {
268
- if (UNSUPPORTED_APPROX_COUNT_OPERATORS.has(key)) {
269
- return key;
270
- }
271
- const unsupportedOperator = findUnsupportedApproxCountOperator(nestedValue);
272
- if (unsupportedOperator) return unsupportedOperator;
273
- }
274
- return null;
275
- };
276
- const castApproxCountQuery = (model, query) => {
277
- const castedQuery = model.find(query).cast(model);
278
- if (!castedQuery || typeof castedQuery !== "object" || Array.isArray(castedQuery)) {
279
- return query;
280
- }
281
- return castedQuery;
282
- };
283
- const normalizeString = (value) => {
284
- return typeof value === "string" ? value.trim() : "";
285
- };
286
- const normalizeObject = (value) => {
287
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
288
- return value;
289
- };
290
- const normalizePagination = (value) => {
291
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
292
- return value;
293
- };
294
- const prepareCursorProjection = (projection, pagination, includeCursors) => {
295
- if (!projection || !includeCursors) return {
296
- projection,
297
- addedPaths: []
298
- };
299
- const inclusionProjection = Object.entries(projection).some(([, value]) => value === 1);
300
- const nextProjection = {
301
- ...projection
302
- };
303
- const addedPaths = [];
304
- const sortFields = Array.isArray(pagination.sort) ? pagination.sort.map((entry) => entry?.field).filter((field) => typeof field === "string") : [];
305
- const cursorPaths = Array.from(/* @__PURE__ */ new Set([...sortFields, "_id"]));
306
- if (!inclusionProjection) {
307
- for (const path of cursorPaths) {
308
- const excludedPath = Object.entries(projection).find(([projectedPath, value]) => value === 0 && (projectedPath === path || path.startsWith(`${projectedPath}.`)))?.[0];
309
- if (!excludedPath) continue;
310
- if (excludedPath !== path) {
311
- throw new Error(`Pagination projection cannot exclude cursor path: ${path}`);
312
- }
313
- delete nextProjection[path];
314
- addedPaths.push(path);
315
- }
316
- return {
317
- projection: nextProjection,
318
- addedPaths
319
- };
320
- }
321
- for (const path of cursorPaths) {
322
- const isIncluded = path === "_id" ? projection._id !== 0 : Object.entries(projection).some(([projectedPath, value]) => value === 1 && (projectedPath === path || path.startsWith(`${projectedPath}.`)));
323
- if (isIncluded) continue;
324
- nextProjection[path] = 1;
325
- addedPaths.push(path);
326
- }
327
- return {
328
- projection: nextProjection,
329
- addedPaths
330
- };
331
- };
332
- const stripPath = (target, path) => {
333
- const parts = path.split(".");
334
- let current = target;
335
- for (let index = 0; index < parts.length - 1; index += 1) {
336
- const part = parts[index];
337
- const child = current[part];
338
- if (!child || typeof child !== "object" || Array.isArray(child)) return;
339
- const cloned = {
340
- ...child
341
- };
342
- current[part] = cloned;
343
- current = cloned;
344
- }
345
- delete current[parts[parts.length - 1]];
346
- };
347
- const stripAddedProjectionPaths = (nodes, addedPaths) => {
348
- if (!addedPaths.length) return nodes;
349
- return nodes.map((node) => {
350
- if (!node || typeof node !== "object" || Array.isArray(node)) return node;
351
- const toObject = node.toObject;
352
- const raw = typeof toObject === "function" ? toObject.call(node) : node;
353
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return raw;
354
- const projected = {
355
- ...raw
356
- };
357
- for (const path of addedPaths) stripPath(projected, path);
358
- return projected;
359
- });
360
- };
361
- const normalizePopulateSelect = (value) => {
362
- if (typeof value === "string") {
363
- const normalized = value.trim();
364
- return normalized || void 0;
365
- }
366
- return normalizeObject(value);
367
- };
368
- const normalizePopulateOptions = (value) => {
369
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
370
- const raw = value;
371
- const normalized = {};
372
- if (raw.sort && typeof raw.sort === "object" && !Array.isArray(raw.sort)) {
373
- normalized.sort = raw.sort;
374
- }
375
- if (typeof raw.limit === "number" && Number.isFinite(raw.limit)) {
376
- normalized.limit = Math.max(0, Math.floor(Math.abs(raw.limit)));
377
- }
378
- if (!normalized.sort && normalized.limit === void 0) return void 0;
379
- return normalized;
380
- };
381
- const normalizePopulateObject = (value) => {
382
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
383
- const raw = value;
384
- const path = normalizeString(raw.path);
385
- if (!path) return void 0;
386
- const normalized = {
387
- path
388
- };
389
- const model = normalizeString(raw.model);
390
- if (model) normalized.model = model;
391
- const select = normalizePopulateSelect(raw.select);
392
- if (select !== void 0) normalized.select = select;
393
- const match = normalizeObject(raw.match);
394
- if (match) normalized.match = match;
395
- const nestedPopulate = normalizeRtsPopulateOption(raw.populate);
396
- if (nestedPopulate !== void 0) normalized.populate = nestedPopulate;
397
- const options = normalizePopulateOptions(raw.options);
398
- if (options) normalized.options = options;
399
- return normalized;
400
- };
401
- const normalizeRtsPopulateOption = (value) => {
402
- if (typeof value === "string") {
403
- const normalized = value.trim();
404
- return normalized || void 0;
405
- }
406
- if (Array.isArray(value)) {
407
- const normalized = value.map((entry) => {
408
- if (typeof entry === "string") {
409
- const path = entry.trim();
410
- return path || null;
411
- }
412
- return normalizePopulateObject(entry) ?? null;
413
- }).filter((entry) => entry !== null);
414
- return normalized.length > 0 ? normalized : void 0;
415
- }
416
- return normalizePopulateObject(value);
417
- };
418
- const normalizeModelName = (value) => {
419
- if (typeof value !== "string") return null;
420
- const normalized = value.trim();
421
- return normalized || null;
422
- };
423
- const resolvePopulateRefModelName = (model, path, explicitModelName) => {
424
- if (explicitModelName) return explicitModelName;
425
- const schema = model.schema;
426
- const schemaPath = typeof schema.path === "function" ? schema.path(path) : null;
427
- const directRef = normalizeModelName(schemaPath?.options?.ref);
428
- if (directRef) return directRef;
429
- const arrayRef = normalizeModelName(schemaPath?.caster?.options?.ref);
430
- if (arrayRef) return arrayRef;
431
- const virtualPath = typeof schema.virtualpath === "function" ? schema.virtualpath(path) : null;
432
- const virtualRef = normalizeModelName(virtualPath?.options?.ref);
433
- if (virtualRef) return virtualRef;
434
- return null;
435
- };
436
- const mergePopulateMatchWithAcl = (populateMatch, aclMatch) => {
437
- if (!populateMatch || Object.keys(populateMatch).length === 0) return aclMatch;
438
- return {
439
- $and: [populateMatch, aclMatch]
440
- };
441
- };
442
- const resolvePopulateSpecForModel = async ({
443
- tenantId,
444
- model,
445
- ability,
446
- populate,
447
- allowInternalModels,
448
- modelCache,
449
- dependencyModelNames
450
- }) => {
451
- if (!populate) return void 0;
452
- const getModelCached = async (targetModelName) => {
453
- const cached = modelCache.get(targetModelName);
454
- if (cached) return cached;
455
- const loaded = await getTenantModel(tenantId, targetModelName, ability);
456
- modelCache.set(targetModelName, loaded);
457
- return loaded;
458
- };
459
- const resolveOne = async (entry, parentModel) => {
460
- if (typeof entry === "string") {
461
- const path2 = entry.trim();
462
- if (!path2) return null;
463
- const refModelName2 = resolvePopulateRefModelName(parentModel, path2, null);
464
- if (!refModelName2) return path2;
465
- if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(refModelName2)) {
466
- throw new Error("Model not allowed");
467
- }
468
- if (!ability.can("read", refModelName2)) {
469
- throw new Error("forbidden");
470
- }
471
- dependencyModelNames.add(refModelName2);
472
- const aclMatch = getAccessibleByQuery(ability, "read", refModelName2);
473
- return {
474
- path: path2,
475
- match: aclMatch
476
- };
477
- }
478
- const path = entry.path.trim();
479
- if (!path) return null;
480
- const explicitModelName = normalizeModelName(entry.model);
481
- const refModelName = resolvePopulateRefModelName(parentModel, path, explicitModelName);
482
- let nestedModel = parentModel;
483
- const normalizedEntry = {
484
- path
485
- };
486
- if (entry.select !== void 0) normalizedEntry.select = entry.select;
487
- if (entry.options !== void 0) normalizedEntry.options = entry.options;
488
- if (explicitModelName) normalizedEntry.model = explicitModelName;
489
- if (entry.match !== void 0) normalizedEntry.match = entry.match;
490
- if (refModelName) {
491
- if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(refModelName)) {
492
- throw new Error("Model not allowed");
493
- }
494
- if (!ability.can("read", refModelName)) {
495
- throw new Error("forbidden");
496
- }
497
- dependencyModelNames.add(refModelName);
498
- nestedModel = await getModelCached(refModelName);
499
- const aclMatch = getAccessibleByQuery(ability, "read", refModelName);
500
- normalizedEntry.match = mergePopulateMatchWithAcl(normalizedEntry.match, aclMatch);
501
- } else if (entry.populate !== void 0) {
502
- throw new Error("Populate path must reference a model when nested populate is used");
503
- }
504
- const nestedPopulate = await resolvePopulateSpecForModel({
505
- tenantId,
506
- model: nestedModel,
507
- ability,
508
- populate: entry.populate,
509
- allowInternalModels,
510
- modelCache,
511
- dependencyModelNames
512
- });
513
- if (nestedPopulate !== void 0) normalizedEntry.populate = nestedPopulate;
514
- return normalizedEntry;
515
- };
516
- if (Array.isArray(populate)) {
517
- const resolved2 = await Promise.all(populate.map((entry) => resolveOne(entry, model)));
518
- const filtered = resolved2.filter((entry) => entry !== null);
519
- return filtered.length > 0 ? filtered : void 0;
520
- }
521
- const resolved = await resolveOne(populate, model);
522
- return resolved ?? void 0;
523
- };
524
- const normalizeRtsQueryOptions = (options) => {
525
- if (!options || typeof options !== "object") return {};
526
- const normalized = {};
527
- if (options.projection && typeof options.projection === "object" && !Array.isArray(options.projection)) {
528
- normalized.projection = options.projection;
529
- }
530
- if (options.sort && typeof options.sort === "object" && !Array.isArray(options.sort)) {
531
- normalized.sort = options.sort;
532
- }
533
- normalized.limit = normalizeLimit(options.limit);
534
- normalized.populate = normalizeRtsPopulateOption(options.populate);
535
- normalized.pagination = normalizePagination(options.pagination);
536
- return normalized;
537
- };
538
- const resolveRtsQueryDependencyModelNames = async ({
539
- tenantId,
540
- ability,
541
- modelName,
542
- options,
543
- allowInternalModels = false
544
- }) => {
545
- const model = await getTenantModel(tenantId, modelName, ability);
546
- const modelCache = /* @__PURE__ */ new Map();
547
- modelCache.set(modelName, model);
548
- const dependencyModelNames = /* @__PURE__ */ new Set();
549
- await resolvePopulateSpecForModel({
550
- tenantId,
551
- model,
552
- ability,
553
- populate: options.populate,
554
- allowInternalModels,
555
- modelCache,
556
- dependencyModelNames
557
- });
558
- return Array.from(dependencyModelNames);
559
- };
560
- const runRtsQuery = async ({
561
- tenantId,
562
- ability,
563
- modelName,
564
- query,
565
- options,
566
- allowInternalModels = false,
567
- paginationMaxLimit,
568
- includePaginationCursors = true
569
- }) => {
570
- const {
571
- model,
572
- finalQuery
573
- } = await prepareRtsExecution({
574
- tenantId,
575
- ability,
576
- modelName,
577
- query,
578
- allowInternalModels
579
- });
580
- const projection = options.projection ?? void 0;
581
- const sort = options.sort;
582
- const limit = normalizeLimit(options.limit);
583
- const modelCache = /* @__PURE__ */ new Map();
584
- modelCache.set(modelName, model);
585
- const populate = await resolvePopulateSpecForModel({
586
- tenantId,
587
- model,
588
- ability,
589
- populate: options.populate,
590
- allowInternalModels,
591
- modelCache,
592
- dependencyModelNames: /* @__PURE__ */ new Set()
593
- });
594
- if (options.pagination) {
595
- const cursorProjection = prepareCursorProjection(projection, options.pagination, includePaginationCursors);
596
- const paginatedQuery = model.find(finalQuery, cursorProjection.projection);
597
- if (populate !== void 0) {
598
- paginatedQuery.populate(populate);
599
- }
600
- const paginatedResult = await paginatedQuery.paginate(options.pagination, {
601
- cursor: {
602
- signingSecret: getPaginationCursorSigningSecret(),
603
- ...paginationMaxLimit !== void 0 ? {
604
- maxLimit: paginationMaxLimit
605
- } : {}
606
- },
607
- includeCursors: includePaginationCursors
608
- });
609
- const totalCount = typeof paginatedResult.totalCount === "number" && Number.isFinite(paginatedResult.totalCount) && paginatedResult.totalCount >= 0 ? Math.floor(paginatedResult.totalCount) : void 0;
610
- const approximateTotalCount = totalCount === void 0 ? await runApproximateRtsCount(model, finalQuery).catch(() => void 0) : void 0;
611
- const resolvedTotalCount = totalCount ?? approximateTotalCount;
612
- return {
613
- data: Array.isArray(paginatedResult.nodes) ? stripAddedProjectionPaths(paginatedResult.nodes, cursorProjection.addedPaths) : [],
614
- pageInfo: paginatedResult.pageInfo,
615
- ...resolvedTotalCount !== void 0 ? {
616
- totalCount: resolvedTotalCount
617
- } : {}
618
- };
619
- }
620
- const queryPromise = model.find(finalQuery, projection);
621
- if (populate !== void 0) {
622
- queryPromise.populate(populate);
623
- }
624
- if (sort && Object.keys(sort).length) {
625
- queryPromise.sort(sort);
626
- }
627
- queryPromise.limit(limit);
628
- const data = await queryPromise;
629
- return {
630
- data: Array.isArray(data) ? data : []
631
- };
632
- };
633
- const prepareRtsExecution = async ({
634
- tenantId,
635
- ability,
636
- modelName,
637
- query,
638
- allowInternalModels = false
639
- }) => {
640
- if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(modelName)) {
641
- throw new Error("Model not allowed");
642
- }
643
- if (!ability.can("read", modelName)) {
644
- throw new Error("forbidden");
645
- }
646
- const model = await getTenantModel(tenantId, modelName, ability);
647
- const accessQuery = getAccessibleByQuery(ability, "read", modelName);
648
- const finalQuery = {
649
- $and: [query, accessQuery]
650
- };
651
- return {
652
- model,
653
- finalQuery
654
- };
655
- };
656
- const runApproximateRtsCount = async (model, query) => {
657
- const unsupportedOperator = findUnsupportedApproxCountOperator(query);
658
- if (unsupportedOperator) {
659
- throw new Error(`Approximate RTS count does not support ${unsupportedOperator} queries`);
660
- }
661
- const castedQuery = castApproxCountQuery(model, query);
662
- const estimatedTotal = normalizeNonNegativeInteger(await model.estimatedDocumentCount());
663
- if (estimatedTotal === 0) return 0;
664
- const sampleSize = Math.min(getApproxCountSampleSize(), estimatedTotal);
665
- const sampleResult = await model.aggregate([{
666
- $sample: {
667
- size: sampleSize
668
- }
669
- }, {
670
- $match: castedQuery
671
- }, {
672
- $count: "count"
673
- }]);
674
- const sampleMatches = normalizeNonNegativeInteger(sampleResult[0]?.count);
675
- if (sampleSize >= estimatedTotal) {
676
- return Math.min(sampleMatches, estimatedTotal);
677
- }
678
- const estimatedMatches = Math.round(estimatedTotal * sampleMatches / sampleSize);
679
- return Math.max(0, Math.min(estimatedTotal, estimatedMatches));
680
- };
681
- const runRtsCount = async ({
682
- tenantId,
683
- ability,
684
- modelName,
685
- query,
686
- allowInternalModels = false
687
- }) => {
688
- const {
689
- model,
690
- finalQuery
691
- } = await prepareRtsExecution({
692
- tenantId,
693
- ability,
694
- modelName,
695
- query,
696
- allowInternalModels
697
- });
698
- return await runApproximateRtsCount(model, finalQuery);
699
- };
700
- const RTS_QUERY_WINDOW_MAX_COUNT = 4096;
701
- export {
702
- RTS_QUERY_WINDOW_MAX_COUNT as R,
703
- runRtsQuery as a,
704
- buildRtsAbilityFromRequest as b,
705
- runRtsCount as c,
706
- syncAuthenticatedSessionFromRequest as d,
707
- resolveRtsQueryDependencyModelNames as e,
708
- getDerivedKey as g,
709
- isRtsRequestAuthorized as i,
710
- normalizeRtsQueryOptions as n,
711
- resolveRtsRequestTenantId as r,
712
- syncAuthenticatedSessionMiddleware as s
713
- };
714
- //# sourceMappingURL=queryWindow-Cdr7K-S1.js.map