@rpcbase/server 0.582.0 → 0.584.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/developmentSessionMiddleware.d.ts +4 -0
- package/dist/developmentSessionMiddleware.d.ts.map +1 -0
- package/dist/index.js +33 -3
- package/dist/index.js.map +1 -1
- package/dist/initServer.d.ts.map +1 -1
- package/dist/{queryExecutor-DW7iAdRY.js → queryWindow-Cdr7K-S1.js} +82 -6
- package/dist/queryWindow-Cdr7K-S1.js.map +1 -0
- package/dist/rts/index.d.ts.map +1 -1
- package/dist/rts/index.js +212 -9
- package/dist/rts/index.js.map +1 -1
- package/dist/rts/queryExecutor.d.ts +3 -1
- package/dist/rts/queryExecutor.d.ts.map +1 -1
- package/dist/rts/queryWindow.d.ts +2 -0
- package/dist/rts/queryWindow.d.ts.map +1 -0
- package/dist/rts/ssrHydration.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/queryExecutor-DW7iAdRY.js.map +0 -1
package/dist/initServer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"initServer.d.ts","sourceRoot":"","sources":["../src/initServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AA8BrC,KAAK,SAAS,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AA0EtD,eAAO,MAAM,UAAU,GAAU,KAAK,WAAW,EAAE,WAAW,SAAS;;EAmFtE,CAAA"}
|
|
@@ -291,6 +291,73 @@ const normalizePagination = (value) => {
|
|
|
291
291
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
292
292
|
return value;
|
|
293
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
|
+
};
|
|
294
361
|
const normalizePopulateSelect = (value) => {
|
|
295
362
|
if (typeof value === "string") {
|
|
296
363
|
const normalized = value.trim();
|
|
@@ -496,7 +563,9 @@ const runRtsQuery = async ({
|
|
|
496
563
|
modelName,
|
|
497
564
|
query,
|
|
498
565
|
options,
|
|
499
|
-
allowInternalModels = false
|
|
566
|
+
allowInternalModels = false,
|
|
567
|
+
paginationMaxLimit,
|
|
568
|
+
includePaginationCursors = true
|
|
500
569
|
}) => {
|
|
501
570
|
const {
|
|
502
571
|
model,
|
|
@@ -523,20 +592,25 @@ const runRtsQuery = async ({
|
|
|
523
592
|
dependencyModelNames: /* @__PURE__ */ new Set()
|
|
524
593
|
});
|
|
525
594
|
if (options.pagination) {
|
|
526
|
-
const
|
|
595
|
+
const cursorProjection = prepareCursorProjection(projection, options.pagination, includePaginationCursors);
|
|
596
|
+
const paginatedQuery = model.find(finalQuery, cursorProjection.projection);
|
|
527
597
|
if (populate !== void 0) {
|
|
528
598
|
paginatedQuery.populate(populate);
|
|
529
599
|
}
|
|
530
600
|
const paginatedResult = await paginatedQuery.paginate(options.pagination, {
|
|
531
601
|
cursor: {
|
|
532
|
-
signingSecret: getPaginationCursorSigningSecret()
|
|
533
|
-
|
|
602
|
+
signingSecret: getPaginationCursorSigningSecret(),
|
|
603
|
+
...paginationMaxLimit !== void 0 ? {
|
|
604
|
+
maxLimit: paginationMaxLimit
|
|
605
|
+
} : {}
|
|
606
|
+
},
|
|
607
|
+
includeCursors: includePaginationCursors
|
|
534
608
|
});
|
|
535
609
|
const totalCount = typeof paginatedResult.totalCount === "number" && Number.isFinite(paginatedResult.totalCount) && paginatedResult.totalCount >= 0 ? Math.floor(paginatedResult.totalCount) : void 0;
|
|
536
610
|
const approximateTotalCount = totalCount === void 0 ? await runApproximateRtsCount(model, finalQuery).catch(() => void 0) : void 0;
|
|
537
611
|
const resolvedTotalCount = totalCount ?? approximateTotalCount;
|
|
538
612
|
return {
|
|
539
|
-
data: Array.isArray(paginatedResult.nodes) ? paginatedResult.nodes : [],
|
|
613
|
+
data: Array.isArray(paginatedResult.nodes) ? stripAddedProjectionPaths(paginatedResult.nodes, cursorProjection.addedPaths) : [],
|
|
540
614
|
pageInfo: paginatedResult.pageInfo,
|
|
541
615
|
...resolvedTotalCount !== void 0 ? {
|
|
542
616
|
totalCount: resolvedTotalCount
|
|
@@ -623,7 +697,9 @@ const runRtsCount = async ({
|
|
|
623
697
|
});
|
|
624
698
|
return await runApproximateRtsCount(model, finalQuery);
|
|
625
699
|
};
|
|
700
|
+
const RTS_QUERY_WINDOW_MAX_COUNT = 4096;
|
|
626
701
|
export {
|
|
702
|
+
RTS_QUERY_WINDOW_MAX_COUNT as R,
|
|
627
703
|
runRtsQuery as a,
|
|
628
704
|
buildRtsAbilityFromRequest as b,
|
|
629
705
|
runRtsCount as c,
|
|
@@ -635,4 +711,4 @@ export {
|
|
|
635
711
|
resolveRtsRequestTenantId as r,
|
|
636
712
|
syncAuthenticatedSessionMiddleware as s
|
|
637
713
|
};
|
|
638
|
-
//# sourceMappingURL=
|
|
714
|
+
//# sourceMappingURL=queryWindow-Cdr7K-S1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryWindow-Cdr7K-S1.js","sources":["../src/getDerivedKey.ts","../src/proxyAuth.ts","../src/syncAuthenticatedSession.ts","../src/rts/queryExecutor.ts","../src/rts/queryWindow.ts"],"sourcesContent":["import assert from \"assert\"\nimport { hkdfSync } from \"crypto\"\n\n\nexport const getDerivedKey = (\n masterKey: string,\n info: string,\n length: number = 32, // Default to 256-bit keys\n salt: string = \"\",\n): string => {\n assert(masterKey?.length >= 32, \"MASTER_KEY must be 32 chars or longer.\")\n\n return Buffer.from(hkdfSync(\n \"sha256\",\n masterKey,\n Buffer.from(salt),\n Buffer.from(info),\n length,\n )).toString(\"hex\")\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\"\n\n\nexport const AUTHENTICATED_USER_ID_HEADER = \"rb-authenticated-user-id\"\nexport const AUTHENTICATED_TENANT_ID_HEADER = \"rb-authenticated-tenant-id\"\nexport const PROXY_AUTH_TIMESTAMP_HEADER = \"rb-proxy-auth-timestamp\"\nexport const PROXY_AUTH_SIGNATURE_HEADER = \"rb-proxy-auth-signature\"\n\nconst MAX_PROXY_AUTH_AGE_MS = 5 * 60 * 1000\n\ntype HeadersLike = Record<string, string | string[] | undefined>\n\nconst normalizeString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized || null\n}\n\nconst getHeaderValue = (headers: HeadersLike | undefined, name: string): string | null => {\n const value = headers?.[name]\n if (Array.isArray(value)) return normalizeString(value[0])\n return normalizeString(value)\n}\n\nconst getProxySharedSecret = (): string | null => {\n const secret = process.env.RB_PROXY_SHARED_SECRET?.trim()\n return secret || null\n}\n\nconst timingSafeEqualText = (left: string, right: string): boolean => {\n const leftBuffer = Buffer.from(left)\n const rightBuffer = Buffer.from(right)\n if (leftBuffer.length !== rightBuffer.length) return false\n return timingSafeEqual(leftBuffer, rightBuffer)\n}\n\nexport const buildProxyAuthSignature = ({\n userId,\n tenantId,\n timestamp,\n secret,\n}: {\n userId: string\n tenantId: string\n timestamp: string\n secret: string\n}): string => {\n return createHmac(\"sha256\", secret)\n .update(`${timestamp}:${userId}:${tenantId}`)\n .digest(\"hex\")\n}\n\nexport const getTrustedProxyAuth = (\n headers: HeadersLike | undefined,\n): { userId: string; tenantId: string } | null => {\n const userId = getHeaderValue(headers, AUTHENTICATED_USER_ID_HEADER)\n const tenantId = getHeaderValue(headers, AUTHENTICATED_TENANT_ID_HEADER)\n const timestamp = getHeaderValue(headers, PROXY_AUTH_TIMESTAMP_HEADER)\n const signature = getHeaderValue(headers, PROXY_AUTH_SIGNATURE_HEADER)\n if (!userId || !tenantId || !timestamp || !signature) return null\n\n const parsedTimestamp = Number(timestamp)\n if (!Number.isInteger(parsedTimestamp)) return null\n\n const now = Date.now()\n if (Math.abs(now - parsedTimestamp) > MAX_PROXY_AUTH_AGE_MS) return null\n\n const secret = getProxySharedSecret()\n if (!secret) return null\n\n const expectedSignature = buildProxyAuthSignature({\n userId,\n tenantId,\n timestamp,\n secret,\n })\n\n if (!timingSafeEqualText(signature, expectedSignature)) return null\n\n return { userId, tenantId }\n}\n","import type { RequestHandler } from \"express\"\nimport { models, type LoadModelCtx } from \"@rpcbase/db\"\n\nimport {\n getTrustedProxyAuth,\n} from \"./proxyAuth\"\n\n\ntype SessionUserLike = {\n id?: unknown\n currentTenantId?: unknown\n signedInTenants?: unknown\n tenantRoles?: unknown\n isEntryGateAuthorized?: unknown\n}\n\ntype RequestLike = {\n headers?: Record<string, string | string[] | undefined>\n session?: {\n user?: SessionUserLike\n }\n}\n\ntype LoadedUserDoc = {\n tenants?: unknown\n tenantRoles?: unknown\n}\n\nconst normalizeString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized || null\n}\n\nconst normalizeStringArray = (value: unknown): string[] => {\n if (!Array.isArray(value)) return []\n return value\n .map((entry) => normalizeString(String(entry)))\n .filter((entry): entry is string => Boolean(entry))\n}\n\nconst normalizeRoles = (value: unknown): string[] => {\n if (!Array.isArray(value)) return []\n return value\n .map((entry) => normalizeString(entry))\n .filter((entry): entry is string => Boolean(entry))\n}\n\nconst normalizeTenantRoles = (value: unknown): Record<string, string[]> | undefined => {\n if (!value || typeof value !== \"object\") return undefined\n\n if (value instanceof Map) {\n const entries = Array.from(value.entries())\n .map(([tenantId, roles]) => {\n const normalizedTenantId = normalizeString(String(tenantId))\n if (!normalizedTenantId) return null\n return [normalizedTenantId, normalizeRoles(roles)] as const\n })\n .filter((entry): entry is readonly [string, string[]] => Boolean(entry))\n return entries.length ? Object.fromEntries(entries) : undefined\n }\n\n const nextRoles = Object.entries(value as Record<string, unknown>)\n .map(([tenantId, roles]) => {\n const normalizedTenantId = normalizeString(tenantId)\n if (!normalizedTenantId) return null\n return [normalizedTenantId, normalizeRoles(roles)] as const\n })\n .filter((entry): entry is readonly [string, string[]] => Boolean(entry))\n\n return nextRoles.length ? Object.fromEntries(nextRoles) : undefined\n}\n\nconst isSessionAuthorizedForTenant = (sessionUser: SessionUserLike | undefined, tenantId: string): boolean => {\n if (!sessionUser) return false\n\n const signedInTenants = normalizeStringArray(sessionUser.signedInTenants)\n if (signedInTenants.length > 0) {\n return signedInTenants.includes(tenantId)\n }\n\n const currentTenantId = normalizeString(sessionUser.currentTenantId)\n return currentTenantId === tenantId\n}\n\nconst loadSessionUser = async (userId: string, tenantId: string): Promise<Record<string, unknown> | null> => {\n const ctx: LoadModelCtx = { req: { session: null } }\n const User = await models.getGlobal(\"RBUser\", ctx)\n const user = await User.findById(userId, { tenants: 1, tenantRoles: 1 }).lean() as LoadedUserDoc | null\n if (!user) return null\n\n const signedInTenants = normalizeStringArray(user.tenants)\n if (!signedInTenants.includes(tenantId)) return null\n\n const tenantRoles = normalizeTenantRoles(user.tenantRoles)\n\n return {\n id: userId,\n currentTenantId: tenantId,\n signedInTenants,\n isEntryGateAuthorized: true,\n ...(tenantRoles ? { tenantRoles } : {}),\n }\n}\n\nexport const syncAuthenticatedSessionFromRequest = async (req: RequestLike): Promise<void> => {\n const proxyAuth = getTrustedProxyAuth(req.headers)\n if (!proxyAuth) return\n\n const { userId, tenantId } = proxyAuth\n\n const session = req.session\n if (!session) return\n\n const sessionUser = session.user\n const sessionUserId = normalizeString(sessionUser?.id)\n\n if (sessionUserId === userId && isSessionAuthorizedForTenant(sessionUser, tenantId)) {\n const currentTenantId = normalizeString(sessionUser?.currentTenantId)\n if (currentTenantId === tenantId) return\n\n const baseUser = sessionUser && typeof sessionUser === \"object\" ? sessionUser as Record<string, unknown> : {}\n session.user = {\n ...baseUser,\n id: userId,\n currentTenantId: tenantId,\n isEntryGateAuthorized: true,\n }\n return\n }\n\n const nextSessionUser = await loadSessionUser(userId, tenantId)\n if (!nextSessionUser) {\n if (session.user) {\n delete session.user\n }\n return\n }\n\n session.user = nextSessionUser as SessionUserLike\n}\n\nexport const syncAuthenticatedSessionMiddleware: RequestHandler = (req, _res, next) => {\n void syncAuthenticatedSessionFromRequest(req).then(() => {\n next()\n }, next)\n}\n","import type { Request } from \"express\"\nimport type { PaginationPageInfo, PaginationSpec } from \"@rpcbase/api\"\nimport { models, type LoadModelCtx } from \"@rpcbase/db\"\nimport { buildAbilityFromSession, getAccessibleByQuery, type AclSubjectType, type AppAbility } from \"@rpcbase/db/acl\"\nimport type { Model } from \"mongoose\"\n\nimport { getDerivedKey } from \"../getDerivedKey\"\n\n\ntype JsonObject = Record<string, unknown>\n\ntype SessionUser = {\n id?: unknown\n currentTenantId?: unknown\n}\n\nexport type RtsPopulateObject = {\n path: string\n model?: string\n select?: string | JsonObject\n match?: JsonObject\n options?: {\n sort?: Record<string, 1 | -1>\n limit?: number\n }\n populate?: RtsPopulateOption\n}\n\nexport type RtsPopulateOption =\n | string\n | RtsPopulateObject\n | Array<string | RtsPopulateObject>\n\nexport type RtsQueryOptions = {\n projection?: JsonObject\n sort?: Record<string, 1 | -1>\n limit?: number\n populate?: RtsPopulateOption\n pagination?: PaginationSpec\n}\n\nexport type RtsQueryResult = {\n data: unknown[]\n pageInfo?: PaginationPageInfo\n totalCount?: number\n}\n\ntype PreparedRtsExecution = {\n model: Model<any>\n finalQuery: JsonObject\n}\n\nconst QUERY_MAX_LIMIT = 4096\nconst INTERNAL_MODEL_NAMES = new Set([\"RBRtsChange\", \"RBRtsCounter\"])\nconst DEFAULT_APPROX_COUNT_SAMPLE_SIZE = 1000\nconst MAX_APPROX_COUNT_SAMPLE_SIZE = 10_000\nconst UNSUPPORTED_APPROX_COUNT_OPERATORS = new Set([\"$text\", \"$near\", \"$nearSphere\", \"$where\"])\nlet paginationCursorSigningSecret: string | null = null\n\nconst getPaginationCursorSigningSecret = (): string => {\n if (paginationCursorSigningSecret) return paginationCursorSigningSecret\n const masterKey = process.env.MASTER_KEY?.trim()\n if (!masterKey) {\n throw new Error(\"MASTER_KEY must be defined to derive pagination cursor signing secret\")\n }\n paginationCursorSigningSecret = getDerivedKey(masterKey, \"pagination_cursor_signing\")\n return paginationCursorSigningSecret\n}\n\nconst normalizeTenantId = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized ? normalized : null\n}\n\nconst getTenantIdFromRequest = (req: Request): string | null => {\n return normalizeTenantId((req.session?.user as SessionUser | undefined)?.currentTenantId)\n}\n\nexport const resolveRtsRequestTenantId = (req: Request): string | null => {\n return getTenantIdFromRequest(req)\n}\n\nexport const resolveRtsRequestUserId = (req: Request): string | null => {\n return normalizeTenantId((req.session?.user as SessionUser | undefined)?.id)\n}\n\nexport const isRtsRequestAuthorized = (req: Request, tenantId: string): boolean => {\n const sessionUser = req.session?.user as SessionUser | undefined\n if (!sessionUser) return false\n\n const currentTenantId = normalizeTenantId(sessionUser.currentTenantId)\n if (!currentTenantId) return false\n return currentTenantId === tenantId\n}\n\nexport const buildRtsAbilityFromRequest = async (\n req: Request,\n tenantId: string,\n): Promise<{ ability: AppAbility; userId: string | null }> => {\n const sessionUserId = normalizeTenantId((req.session?.user as SessionUser | undefined)?.id)\n if (!sessionUserId) {\n const currentTenantId = normalizeTenantId((req.session?.user as SessionUser | undefined)?.currentTenantId)\n if (!currentTenantId || currentTenantId !== tenantId) {\n throw new Error(\"Tenant not authorized for this session\")\n }\n\n return {\n ability: buildAbilityFromSession({ tenantId, session: req.session }),\n userId: null,\n }\n }\n\n const currentTenantId = normalizeTenantId((req.session?.user as SessionUser | undefined)?.currentTenantId)\n if (!currentTenantId || currentTenantId !== tenantId) {\n throw new Error(\"Tenant not authorized for this session\")\n }\n\n return {\n ability: buildAbilityFromSession({ tenantId, session: req.session }),\n userId: sessionUserId,\n }\n}\n\nconst getTenantModel = async (tenantId: string, modelName: string, ability: AppAbility): Promise<Model<any>> => {\n const ctx: LoadModelCtx = {\n req: {\n session: {\n user: {\n currentTenantId: tenantId,\n },\n },\n },\n ability,\n }\n\n return models.get(modelName, ctx)\n}\n\nconst normalizeLimit = (limit?: number): number => {\n if (typeof limit !== \"number\") return QUERY_MAX_LIMIT\n if (!Number.isFinite(limit)) return QUERY_MAX_LIMIT\n return Math.min(QUERY_MAX_LIMIT, Math.abs(limit))\n}\n\nconst normalizeNonNegativeInteger = (value: unknown): number => {\n if (typeof value !== \"number\") return 0\n if (!Number.isFinite(value) || value < 0) return 0\n return Math.floor(value)\n}\n\nconst getApproxCountSampleSize = (): number => {\n const raw = process.env.RB_RTS_APPROX_COUNT_SAMPLE_SIZE?.trim() ?? \"\"\n if (!raw) return DEFAULT_APPROX_COUNT_SAMPLE_SIZE\n\n const parsed = Number(raw)\n if (!Number.isFinite(parsed) || parsed <= 0) return DEFAULT_APPROX_COUNT_SAMPLE_SIZE\n return Math.min(MAX_APPROX_COUNT_SAMPLE_SIZE, Math.floor(parsed))\n}\n\nconst findUnsupportedApproxCountOperator = (value: unknown): string | null => {\n if (!value || typeof value !== \"object\") return null\n\n if (Array.isArray(value)) {\n for (const entry of value) {\n const unsupportedOperator = findUnsupportedApproxCountOperator(entry)\n if (unsupportedOperator) return unsupportedOperator\n }\n return null\n }\n\n for (const [key, nestedValue] of Object.entries(value as Record<string, unknown>)) {\n if (UNSUPPORTED_APPROX_COUNT_OPERATORS.has(key)) {\n return key\n }\n\n const unsupportedOperator = findUnsupportedApproxCountOperator(nestedValue)\n if (unsupportedOperator) return unsupportedOperator\n }\n\n return null\n}\n\nconst castApproxCountQuery = (model: Model<any>, query: JsonObject): JsonObject => {\n const castedQuery = model.find(query).cast(model)\n if (!castedQuery || typeof castedQuery !== \"object\" || Array.isArray(castedQuery)) {\n return query\n }\n\n return castedQuery as JsonObject\n}\n\nconst normalizeString = (value: unknown): string => {\n return typeof value === \"string\" ? value.trim() : \"\"\n}\n\nconst normalizeObject = (value: unknown): JsonObject | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined\n return value as JsonObject\n}\n\nconst normalizePagination = (value: unknown): PaginationSpec | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined\n return value as PaginationSpec\n}\n\nconst prepareCursorProjection = (\n projection: JsonObject | undefined,\n pagination: PaginationSpec,\n includeCursors: boolean,\n): { projection: JsonObject | undefined; addedPaths: string[] } => {\n if (!projection || !includeCursors) return { projection, addedPaths: [] }\n\n const inclusionProjection = Object.entries(projection).some(([, value]) => value === 1)\n const nextProjection = { ...projection }\n const addedPaths: string[] = []\n const sortFields = Array.isArray(pagination.sort)\n ? pagination.sort\n .map((entry) => entry?.field)\n .filter((field): field is string => typeof field === \"string\")\n : []\n const cursorPaths = Array.from(new Set([...sortFields, \"_id\"]))\n\n if (!inclusionProjection) {\n for (const path of cursorPaths) {\n const excludedPath = Object.entries(projection).find(([projectedPath, value]) =>\n value === 0 && (projectedPath === path || path.startsWith(`${projectedPath}.`)),\n )?.[0]\n if (!excludedPath) continue\n if (excludedPath !== path) {\n throw new Error(`Pagination projection cannot exclude cursor path: ${path}`)\n }\n delete nextProjection[path]\n addedPaths.push(path)\n }\n return { projection: nextProjection, addedPaths }\n }\n\n for (const path of cursorPaths) {\n const isIncluded = path === \"_id\"\n ? projection._id !== 0\n : Object.entries(projection).some(([projectedPath, value]) =>\n value === 1 && (projectedPath === path || path.startsWith(`${projectedPath}.`)),\n )\n if (isIncluded) continue\n nextProjection[path] = 1\n addedPaths.push(path)\n }\n\n return { projection: nextProjection, addedPaths }\n}\n\nconst stripPath = (target: JsonObject, path: string): void => {\n const parts = path.split(\".\")\n let current = target\n\n for (let index = 0; index < parts.length - 1; index += 1) {\n const part = parts[index]!\n const child = current[part]\n if (!child || typeof child !== \"object\" || Array.isArray(child)) return\n const cloned = { ...(child as JsonObject) }\n current[part] = cloned\n current = cloned\n }\n\n delete current[parts[parts.length - 1]!]\n}\n\nconst stripAddedProjectionPaths = (nodes: unknown[], addedPaths: string[]): unknown[] => {\n if (!addedPaths.length) return nodes\n\n return nodes.map((node) => {\n if (!node || typeof node !== \"object\" || Array.isArray(node)) return node\n const toObject = (node as { toObject?: unknown }).toObject\n const raw = typeof toObject === \"function\"\n ? toObject.call(node)\n : node\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return raw\n const projected = { ...(raw as JsonObject) }\n for (const path of addedPaths) stripPath(projected, path)\n return projected\n })\n}\n\nconst normalizePopulateSelect = (value: unknown): string | JsonObject | undefined => {\n if (typeof value === \"string\") {\n const normalized = value.trim()\n return normalized || undefined\n }\n return normalizeObject(value)\n}\n\nconst normalizePopulateOptions = (value: unknown): RtsPopulateObject[\"options\"] | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined\n const raw = value as { sort?: unknown; limit?: unknown }\n const normalized: RtsPopulateObject[\"options\"] = {}\n\n if (raw.sort && typeof raw.sort === \"object\" && !Array.isArray(raw.sort)) {\n normalized.sort = raw.sort as Record<string, 1 | -1>\n }\n\n if (typeof raw.limit === \"number\" && Number.isFinite(raw.limit)) {\n normalized.limit = Math.max(0, Math.floor(Math.abs(raw.limit)))\n }\n\n if (!normalized.sort && normalized.limit === undefined) return undefined\n return normalized\n}\n\nconst normalizePopulateObject = (value: unknown): RtsPopulateObject | undefined => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined\n const raw = value as Record<string, unknown>\n const path = normalizeString(raw.path)\n if (!path) return undefined\n\n const normalized: RtsPopulateObject = { path }\n\n const model = normalizeString(raw.model)\n if (model) normalized.model = model\n\n const select = normalizePopulateSelect(raw.select)\n if (select !== undefined) normalized.select = select\n\n const match = normalizeObject(raw.match)\n if (match) normalized.match = match\n\n const nestedPopulate = normalizeRtsPopulateOption(raw.populate)\n if (nestedPopulate !== undefined) normalized.populate = nestedPopulate\n\n const options = normalizePopulateOptions(raw.options)\n if (options) normalized.options = options\n\n return normalized\n}\n\nconst normalizeRtsPopulateOption = (value: unknown): RtsPopulateOption | undefined => {\n if (typeof value === \"string\") {\n const normalized = value.trim()\n return normalized || undefined\n }\n\n if (Array.isArray(value)) {\n const normalized = value\n .map((entry) => {\n if (typeof entry === \"string\") {\n const path = entry.trim()\n return path || null\n }\n return normalizePopulateObject(entry) ?? null\n })\n .filter((entry): entry is string | RtsPopulateObject => entry !== null)\n\n return normalized.length > 0 ? normalized : undefined\n }\n\n return normalizePopulateObject(value)\n}\n\nconst normalizeModelName = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized || null\n}\n\nconst resolvePopulateRefModelName = (\n model: Model<any>,\n path: string,\n explicitModelName: string | null,\n): string | null => {\n if (explicitModelName) return explicitModelName\n\n const schema = model.schema as any\n const schemaPath = typeof schema.path === \"function\" ? schema.path(path) : null\n const directRef = normalizeModelName(schemaPath?.options?.ref)\n if (directRef) return directRef\n\n const arrayRef = normalizeModelName(schemaPath?.caster?.options?.ref)\n if (arrayRef) return arrayRef\n\n const virtualPath = typeof schema.virtualpath === \"function\" ? schema.virtualpath(path) : null\n const virtualRef = normalizeModelName(virtualPath?.options?.ref)\n if (virtualRef) return virtualRef\n\n return null\n}\n\nconst mergePopulateMatchWithAcl = (\n populateMatch: JsonObject | undefined,\n aclMatch: JsonObject,\n): JsonObject => {\n if (!populateMatch || Object.keys(populateMatch).length === 0) return aclMatch\n return { $and: [populateMatch, aclMatch] }\n}\n\ntype PreparedPopulateObject = {\n path: string\n model?: string\n select?: string | JsonObject\n match?: JsonObject\n options?: {\n sort?: Record<string, 1 | -1>\n limit?: number\n }\n populate?: PreparedPopulateOption\n}\n\ntype PreparedPopulateOption =\n | string\n | PreparedPopulateObject\n | Array<string | PreparedPopulateObject>\n\nconst resolvePopulateSpecForModel = async ({\n tenantId,\n model,\n ability,\n populate,\n allowInternalModels,\n modelCache,\n dependencyModelNames,\n}: {\n tenantId: string\n model: Model<any>\n ability: AppAbility\n populate: RtsPopulateOption | undefined\n allowInternalModels: boolean\n modelCache: Map<string, Model<any>>\n dependencyModelNames: Set<string>\n}): Promise<PreparedPopulateOption | undefined> => {\n if (!populate) return undefined\n\n const getModelCached = async (targetModelName: string): Promise<Model<any>> => {\n const cached = modelCache.get(targetModelName)\n if (cached) return cached\n const loaded = await getTenantModel(tenantId, targetModelName, ability)\n modelCache.set(targetModelName, loaded)\n return loaded\n }\n\n const resolveOne = async (\n entry: string | RtsPopulateObject,\n parentModel: Model<any>,\n ): Promise<string | PreparedPopulateObject | null> => {\n if (typeof entry === \"string\") {\n const path = entry.trim()\n if (!path) return null\n\n const refModelName = resolvePopulateRefModelName(parentModel, path, null)\n if (!refModelName) return path\n if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(refModelName)) {\n throw new Error(\"Model not allowed\")\n }\n if (!ability.can(\"read\", refModelName as AclSubjectType)) {\n throw new Error(\"forbidden\")\n }\n\n dependencyModelNames.add(refModelName)\n\n const aclMatch = getAccessibleByQuery(\n ability,\n \"read\",\n refModelName as Exclude<AclSubjectType, \"all\">,\n )\n return {\n path,\n match: aclMatch as JsonObject,\n }\n }\n\n const path = entry.path.trim()\n if (!path) return null\n\n const explicitModelName = normalizeModelName(entry.model)\n const refModelName = resolvePopulateRefModelName(parentModel, path, explicitModelName)\n let nestedModel = parentModel\n\n const normalizedEntry: PreparedPopulateObject = {\n path,\n }\n\n if (entry.select !== undefined) normalizedEntry.select = entry.select\n if (entry.options !== undefined) normalizedEntry.options = entry.options\n if (explicitModelName) normalizedEntry.model = explicitModelName\n if (entry.match !== undefined) normalizedEntry.match = entry.match\n\n if (refModelName) {\n if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(refModelName)) {\n throw new Error(\"Model not allowed\")\n }\n if (!ability.can(\"read\", refModelName as AclSubjectType)) {\n throw new Error(\"forbidden\")\n }\n\n dependencyModelNames.add(refModelName)\n nestedModel = await getModelCached(refModelName)\n\n const aclMatch = getAccessibleByQuery(\n ability,\n \"read\",\n refModelName as Exclude<AclSubjectType, \"all\">,\n ) as JsonObject\n normalizedEntry.match = mergePopulateMatchWithAcl(\n normalizedEntry.match,\n aclMatch,\n )\n } else if (entry.populate !== undefined) {\n throw new Error(\"Populate path must reference a model when nested populate is used\")\n }\n\n const nestedPopulate = await resolvePopulateSpecForModel({\n tenantId,\n model: nestedModel,\n ability,\n populate: entry.populate,\n allowInternalModels,\n modelCache,\n dependencyModelNames,\n })\n if (nestedPopulate !== undefined) normalizedEntry.populate = nestedPopulate\n\n return normalizedEntry\n }\n\n if (Array.isArray(populate)) {\n const resolved = await Promise.all(populate.map((entry) => resolveOne(entry, model)))\n const filtered = resolved.filter((entry): entry is string | PreparedPopulateObject => entry !== null)\n return filtered.length > 0 ? filtered : undefined\n }\n\n const resolved = await resolveOne(populate, model)\n return resolved ?? undefined\n}\n\nexport const normalizeRtsQueryOptions = (options: RtsQueryOptions | undefined): RtsQueryOptions => {\n if (!options || typeof options !== \"object\") return {}\n const normalized: RtsQueryOptions = {}\n\n if (options.projection && typeof options.projection === \"object\" && !Array.isArray(options.projection)) {\n normalized.projection = options.projection\n }\n\n if (options.sort && typeof options.sort === \"object\" && !Array.isArray(options.sort)) {\n normalized.sort = options.sort\n }\n\n normalized.limit = normalizeLimit(options.limit)\n normalized.populate = normalizeRtsPopulateOption(options.populate)\n normalized.pagination = normalizePagination(options.pagination)\n\n return normalized\n}\n\nexport const resolveRtsQueryDependencyModelNames = async ({\n tenantId,\n ability,\n modelName,\n options,\n allowInternalModels = false,\n}: {\n tenantId: string\n ability: AppAbility\n modelName: string\n options: RtsQueryOptions\n allowInternalModels?: boolean\n}): Promise<string[]> => {\n const model = await getTenantModel(tenantId, modelName, ability)\n const modelCache = new Map<string, Model<any>>()\n modelCache.set(modelName, model)\n\n const dependencyModelNames = new Set<string>()\n await resolvePopulateSpecForModel({\n tenantId,\n model,\n ability,\n populate: options.populate,\n allowInternalModels,\n modelCache,\n dependencyModelNames,\n })\n\n return Array.from(dependencyModelNames)\n}\n\nexport const runRtsQuery = async ({\n tenantId,\n ability,\n modelName,\n query,\n options,\n allowInternalModels = false,\n paginationMaxLimit,\n includePaginationCursors = true,\n}: {\n tenantId: string\n ability: AppAbility\n modelName: string\n query: JsonObject\n options: RtsQueryOptions\n allowInternalModels?: boolean\n paginationMaxLimit?: number\n includePaginationCursors?: boolean\n}): Promise<RtsQueryResult> => {\n const { model, finalQuery } = await prepareRtsExecution({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels,\n })\n const projection = options.projection ?? undefined\n const sort = options.sort\n const limit = normalizeLimit(options.limit)\n const modelCache = new Map<string, Model<any>>()\n modelCache.set(modelName, model)\n\n const populate = await resolvePopulateSpecForModel({\n tenantId,\n model,\n ability,\n populate: options.populate,\n allowInternalModels,\n modelCache,\n dependencyModelNames: new Set<string>(),\n })\n\n if (options.pagination) {\n const cursorProjection = prepareCursorProjection(\n projection,\n options.pagination,\n includePaginationCursors,\n )\n const paginatedQuery = model.find(finalQuery, cursorProjection.projection)\n if (populate !== undefined) {\n paginatedQuery.populate(populate as any)\n }\n\n const paginatedResult = await paginatedQuery.paginate(options.pagination, {\n cursor: {\n signingSecret: getPaginationCursorSigningSecret(),\n ...(paginationMaxLimit !== undefined ? { maxLimit: paginationMaxLimit } : {}),\n },\n includeCursors: includePaginationCursors,\n })\n const totalCount = typeof paginatedResult.totalCount === \"number\"\n && Number.isFinite(paginatedResult.totalCount)\n && paginatedResult.totalCount >= 0\n ? Math.floor(paginatedResult.totalCount)\n : undefined\n const approximateTotalCount = totalCount === undefined\n ? await runApproximateRtsCount(model, finalQuery).catch(() => undefined)\n : undefined\n const resolvedTotalCount = totalCount ?? approximateTotalCount\n\n return {\n data: Array.isArray(paginatedResult.nodes)\n ? stripAddedProjectionPaths(paginatedResult.nodes, cursorProjection.addedPaths)\n : [],\n pageInfo: paginatedResult.pageInfo,\n ...(resolvedTotalCount !== undefined ? { totalCount: resolvedTotalCount } : {}),\n }\n }\n\n const queryPromise = model.find(finalQuery, projection)\n if (populate !== undefined) {\n queryPromise.populate(populate as any)\n }\n if (sort && Object.keys(sort).length) {\n queryPromise.sort(sort)\n }\n queryPromise.limit(limit)\n\n const data = await queryPromise\n return { data: Array.isArray(data) ? data : [] }\n}\n\nconst prepareRtsExecution = async ({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels = false,\n}: {\n tenantId: string\n ability: AppAbility\n modelName: string\n query: JsonObject\n allowInternalModels?: boolean\n}): Promise<PreparedRtsExecution> => {\n if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(modelName)) {\n throw new Error(\"Model not allowed\")\n }\n\n if (!ability.can(\"read\", modelName as AclSubjectType)) {\n throw new Error(\"forbidden\")\n }\n\n const model = await getTenantModel(tenantId, modelName, ability)\n const accessQuery = getAccessibleByQuery(ability, \"read\", modelName as Exclude<AclSubjectType, \"all\">)\n const finalQuery: JsonObject = { $and: [query, accessQuery] }\n\n return { model, finalQuery }\n}\n\nconst runApproximateRtsCount = async (model: Model<any>, query: JsonObject): Promise<number> => {\n const unsupportedOperator = findUnsupportedApproxCountOperator(query)\n if (unsupportedOperator) {\n throw new Error(`Approximate RTS count does not support ${unsupportedOperator} queries`)\n }\n\n const castedQuery = castApproxCountQuery(model, query)\n const estimatedTotal = normalizeNonNegativeInteger(await model.estimatedDocumentCount())\n if (estimatedTotal === 0) return 0\n\n const sampleSize = Math.min(getApproxCountSampleSize(), estimatedTotal)\n const sampleResult = await model.aggregate([\n { $sample: { size: sampleSize } },\n { $match: castedQuery },\n { $count: \"count\" },\n ]) as Array<{ count?: unknown }>\n const sampleMatches = normalizeNonNegativeInteger(sampleResult[0]?.count)\n\n if (sampleSize >= estimatedTotal) {\n return Math.min(sampleMatches, estimatedTotal)\n }\n\n const estimatedMatches = Math.round((estimatedTotal * sampleMatches) / sampleSize)\n return Math.max(0, Math.min(estimatedTotal, estimatedMatches))\n}\n\nexport const runRtsCount = async ({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels = false,\n}: {\n tenantId: string\n ability: AppAbility\n modelName: string\n query: JsonObject\n allowInternalModels?: boolean\n}): Promise<number> => {\n const { model, finalQuery } = await prepareRtsExecution({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels,\n })\n\n return await runApproximateRtsCount(model, finalQuery)\n}\n","export const RTS_QUERY_WINDOW_MAX_COUNT = 4096\n"],"names":["getDerivedKey","masterKey","info","length","salt","assert","Buffer","from","hkdfSync","toString","AUTHENTICATED_USER_ID_HEADER","AUTHENTICATED_TENANT_ID_HEADER","PROXY_AUTH_TIMESTAMP_HEADER","PROXY_AUTH_SIGNATURE_HEADER","MAX_PROXY_AUTH_AGE_MS","normalizeString","value","normalized","trim","getHeaderValue","headers","name","Array","isArray","getProxySharedSecret","secret","process","env","RB_PROXY_SHARED_SECRET","timingSafeEqualText","left","right","leftBuffer","rightBuffer","timingSafeEqual","buildProxyAuthSignature","userId","tenantId","timestamp","createHmac","update","digest","getTrustedProxyAuth","signature","parsedTimestamp","Number","isInteger","now","Date","Math","abs","expectedSignature","normalizeStringArray","map","entry","String","filter","Boolean","normalizeRoles","normalizeTenantRoles","undefined","Map","entries","roles","normalizedTenantId","Object","fromEntries","nextRoles","isSessionAuthorizedForTenant","sessionUser","signedInTenants","includes","currentTenantId","loadSessionUser","ctx","req","session","User","models","getGlobal","user","findById","tenants","tenantRoles","lean","id","isEntryGateAuthorized","syncAuthenticatedSessionFromRequest","proxyAuth","sessionUserId","baseUser","nextSessionUser","syncAuthenticatedSessionMiddleware","_res","next","then","QUERY_MAX_LIMIT","INTERNAL_MODEL_NAMES","Set","DEFAULT_APPROX_COUNT_SAMPLE_SIZE","MAX_APPROX_COUNT_SAMPLE_SIZE","UNSUPPORTED_APPROX_COUNT_OPERATORS","paginationCursorSigningSecret","getPaginationCursorSigningSecret","MASTER_KEY","Error","normalizeTenantId","getTenantIdFromRequest","resolveRtsRequestTenantId","isRtsRequestAuthorized","buildRtsAbilityFromRequest","ability","buildAbilityFromSession","getTenantModel","modelName","get","normalizeLimit","limit","isFinite","min","normalizeNonNegativeInteger","floor","getApproxCountSampleSize","raw","RB_RTS_APPROX_COUNT_SAMPLE_SIZE","parsed","findUnsupportedApproxCountOperator","unsupportedOperator","key","nestedValue","has","castApproxCountQuery","model","query","castedQuery","find","cast","normalizeObject","normalizePagination","prepareCursorProjection","projection","pagination","includeCursors","addedPaths","inclusionProjection","some","nextProjection","sortFields","sort","field","cursorPaths","path","excludedPath","projectedPath","startsWith","push","isIncluded","_id","stripPath","target","parts","split","current","index","part","child","cloned","stripAddedProjectionPaths","nodes","node","toObject","call","projected","normalizePopulateSelect","normalizePopulateOptions","max","normalizePopulateObject","select","match","nestedPopulate","normalizeRtsPopulateOption","populate","options","normalizeModelName","resolvePopulateRefModelName","explicitModelName","schema","schemaPath","directRef","ref","arrayRef","caster","virtualPath","virtualpath","virtualRef","mergePopulateMatchWithAcl","populateMatch","aclMatch","keys","$and","resolvePopulateSpecForModel","allowInternalModels","modelCache","dependencyModelNames","getModelCached","targetModelName","cached","loaded","set","resolveOne","parentModel","refModelName","can","add","getAccessibleByQuery","nestedModel","normalizedEntry","resolved","Promise","all","filtered","normalizeRtsQueryOptions","resolveRtsQueryDependencyModelNames","runRtsQuery","paginationMaxLimit","includePaginationCursors","finalQuery","prepareRtsExecution","cursorProjection","paginatedQuery","paginatedResult","paginate","cursor","signingSecret","maxLimit","totalCount","approximateTotalCount","runApproximateRtsCount","catch","resolvedTotalCount","data","pageInfo","queryPromise","accessQuery","estimatedTotal","estimatedDocumentCount","sampleSize","sampleResult","aggregate","$sample","size","$match","$count","sampleMatches","count","estimatedMatches","round","runRtsCount","RTS_QUERY_WINDOW_MAX_COUNT"],"mappings":"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"}
|
package/dist/rts/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rts/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAA;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG7C,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG/F,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rts/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,MAAM,IAAI,UAAU,EAAE,MAAM,WAAW,CAAA;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAG7C,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAG/F,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,IAAI,CAAA;AAmElE,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,KAAK,UAAU,GAAG;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,UAAU,CAAA;CACpB,CAAA;AAiCD,KAAK,SAAS,GAAG,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAA;AAqC3D,cAAM,SAAS;IACb,SAAgB,EAAE,EAAE,MAAM,CAAA;IAC1B,SAAgB,QAAQ,EAAE,MAAM,CAAA;IAChC,SAAgB,MAAM,EAAE,MAAM,CAAA;IAE9B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqD;IAC9E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqD;gBAElE,EACjB,EAAE,EACF,EAAE,EACF,IAAI,GACL,EAAE;QACD,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,SAAS,CAAA;QACb,IAAI,EAAE,UAAU,CAAA;KACjB;IAOM,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAOlE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAO7D,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAI5C,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAO9E,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAOzE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI;IAIxD,KAAK,IAAI,IAAI;IAQb,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQ/C,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;CAOnE;AAilCD,eAAO,MAAM,OAAO,GAAI,4NAQrB;IACD,MAAM,EAAE,UAAU,CAAA;IAClB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,cAAc,CAAA;IACjC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B,KAAG,IAkJH,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,SAAS,SAAS,KAAG,IAEvD,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,wCAAwC,sBAAsB,KAAG,IAalG,CAAA;AAED,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,EAAE,WAAW,MAAM,KAAG,IAE3E,CAAA;AAED,cAAc,UAAU,CAAA"}
|
package/dist/rts/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { models } from "@rpcbase/db";
|
|
3
3
|
import { buildAbilityFromSession } from "@rpcbase/db/acl";
|
|
4
4
|
import { WebSocketServer } from "ws";
|
|
5
|
-
import { d as syncAuthenticatedSessionFromRequest, n as normalizeRtsQueryOptions, e as resolveRtsQueryDependencyModelNames, a as runRtsQuery, c as runRtsCount } from "../
|
|
5
|
+
import { d as syncAuthenticatedSessionFromRequest, n as normalizeRtsQueryOptions, e as resolveRtsQueryDependencyModelNames, R as RTS_QUERY_WINDOW_MAX_COUNT, a as runRtsQuery, c as runRtsCount } from "../queryWindow-Cdr7K-S1.js";
|
|
6
6
|
const routes = Object.entries({
|
|
7
7
|
.../* @__PURE__ */ Object.assign({ "./api/changes/handler.ts": () => import("../handler-BqoKvylN.js") })
|
|
8
8
|
}).reduce((acc, [path, mod]) => {
|
|
@@ -31,6 +31,7 @@ let maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES;
|
|
|
31
31
|
let maxSubscriptionsPerSocket = DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET;
|
|
32
32
|
let dispatchDebounceMs = DEFAULT_DISPATCH_DEBOUNCE_MS;
|
|
33
33
|
let allowInternalModels = false;
|
|
34
|
+
const isValidQueryWindowCount = (value) => typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= RTS_QUERY_WINDOW_MAX_COUNT;
|
|
34
35
|
class RtsSocket {
|
|
35
36
|
id;
|
|
36
37
|
tenantId;
|
|
@@ -273,6 +274,107 @@ const runAndSendQuery = async ({
|
|
|
273
274
|
sendWs(ws, payload);
|
|
274
275
|
}
|
|
275
276
|
};
|
|
277
|
+
const getHeadWindowOptions = (options, requestedCount) => {
|
|
278
|
+
if (!options.pagination) return options;
|
|
279
|
+
const pagination = {
|
|
280
|
+
...options.pagination,
|
|
281
|
+
limit: requestedCount
|
|
282
|
+
};
|
|
283
|
+
delete pagination.cursor;
|
|
284
|
+
delete pagination.direction;
|
|
285
|
+
return {
|
|
286
|
+
...options,
|
|
287
|
+
pagination
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
const runAndSendSubscriptionQuery = async ({
|
|
291
|
+
tenantId,
|
|
292
|
+
targetSocketIds,
|
|
293
|
+
ability,
|
|
294
|
+
modelName,
|
|
295
|
+
queryKey,
|
|
296
|
+
subscription
|
|
297
|
+
}) => {
|
|
298
|
+
if (!subscription.options.pagination) {
|
|
299
|
+
await runAndSendQuery({
|
|
300
|
+
tenantId,
|
|
301
|
+
targetSocketIds,
|
|
302
|
+
ability,
|
|
303
|
+
modelName,
|
|
304
|
+
queryKey,
|
|
305
|
+
query: subscription.query,
|
|
306
|
+
options: subscription.options
|
|
307
|
+
});
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const groups = /* @__PURE__ */ new Map();
|
|
311
|
+
for (const socketId of targetSocketIds) {
|
|
312
|
+
const state = subscription.windows.get(socketId);
|
|
313
|
+
if (!state) continue;
|
|
314
|
+
state.version += 1;
|
|
315
|
+
const targets = groups.get(state.requestedCount) ?? [];
|
|
316
|
+
targets.push({
|
|
317
|
+
socketId,
|
|
318
|
+
window: {
|
|
319
|
+
requestedCount: state.requestedCount,
|
|
320
|
+
version: state.version
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
groups.set(state.requestedCount, targets);
|
|
324
|
+
}
|
|
325
|
+
await Promise.all(Array.from(groups.entries()).map(async ([requestedCount, targets]) => {
|
|
326
|
+
try {
|
|
327
|
+
const result = await runRtsQuery({
|
|
328
|
+
tenantId,
|
|
329
|
+
ability,
|
|
330
|
+
modelName,
|
|
331
|
+
query: subscription.query,
|
|
332
|
+
options: getHeadWindowOptions(subscription.options, requestedCount),
|
|
333
|
+
allowInternalModels,
|
|
334
|
+
paginationMaxLimit: RTS_QUERY_WINDOW_MAX_COUNT,
|
|
335
|
+
includePaginationCursors: false
|
|
336
|
+
});
|
|
337
|
+
for (const target of targets) {
|
|
338
|
+
const current = subscription.windows.get(target.socketId);
|
|
339
|
+
if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
const ws = sockets.get(target.socketId);
|
|
343
|
+
if (!ws) continue;
|
|
344
|
+
sendWs(ws, {
|
|
345
|
+
type: "query-payload",
|
|
346
|
+
modelName,
|
|
347
|
+
queryKey,
|
|
348
|
+
data: result.data,
|
|
349
|
+
...result.pageInfo ? {
|
|
350
|
+
pageInfo: result.pageInfo
|
|
351
|
+
} : {},
|
|
352
|
+
...typeof result.totalCount === "number" ? {
|
|
353
|
+
totalCount: result.totalCount
|
|
354
|
+
} : {},
|
|
355
|
+
window: target.window
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
} catch (err) {
|
|
359
|
+
const error = redactErrorMessage(err);
|
|
360
|
+
for (const target of targets) {
|
|
361
|
+
const current = subscription.windows.get(target.socketId);
|
|
362
|
+
if (!current || current.requestedCount !== target.window.requestedCount || current.version !== target.window.version) {
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const ws = sockets.get(target.socketId);
|
|
366
|
+
if (!ws) continue;
|
|
367
|
+
sendWs(ws, {
|
|
368
|
+
type: "query-payload",
|
|
369
|
+
modelName,
|
|
370
|
+
queryKey,
|
|
371
|
+
error,
|
|
372
|
+
window: target.window
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}));
|
|
377
|
+
};
|
|
276
378
|
const runAndSendCount = async ({
|
|
277
379
|
tenantId,
|
|
278
380
|
targetSocketIds,
|
|
@@ -343,14 +445,13 @@ const dispatchSubscriptionsForModel = async (tenantId, modelName) => {
|
|
|
343
445
|
const ability = meta?.ability;
|
|
344
446
|
if (!ability) continue;
|
|
345
447
|
try {
|
|
346
|
-
await
|
|
448
|
+
await runAndSendSubscriptionQuery({
|
|
347
449
|
tenantId,
|
|
348
450
|
targetSocketIds,
|
|
349
451
|
ability,
|
|
350
452
|
modelName: ownerModelName,
|
|
351
453
|
queryKey,
|
|
352
|
-
|
|
353
|
-
options: sub.options
|
|
454
|
+
subscription: sub
|
|
354
455
|
});
|
|
355
456
|
} catch (err) {
|
|
356
457
|
const error = redactErrorMessage(err);
|
|
@@ -435,6 +536,21 @@ const ensureChangeStream = async (tenantId, modelName) => {
|
|
|
435
536
|
});
|
|
436
537
|
tenantStreams.set(modelName, stream);
|
|
437
538
|
};
|
|
539
|
+
const closeUnusedChangeStream = (tenantId, modelName) => {
|
|
540
|
+
if (hasAnySubscriptionsDependingOnModel(tenantId, modelName) || hasAnyCountSubscriptionsForModel(tenantId, modelName)) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const tenantStreams = changeStreams.get(tenantId);
|
|
544
|
+
const stream = tenantStreams?.get(modelName);
|
|
545
|
+
if (!stream) return;
|
|
546
|
+
try {
|
|
547
|
+
stream.close();
|
|
548
|
+
} catch {
|
|
549
|
+
}
|
|
550
|
+
clearDispatchTimer(tenantId, modelName);
|
|
551
|
+
tenantStreams?.delete(modelName);
|
|
552
|
+
if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId);
|
|
553
|
+
};
|
|
438
554
|
const addSocketSubscription = ({
|
|
439
555
|
socketId,
|
|
440
556
|
tenantId,
|
|
@@ -455,12 +571,24 @@ const addSocketSubscription = ({
|
|
|
455
571
|
if (existing) {
|
|
456
572
|
existing.socketIds.add(socketId);
|
|
457
573
|
existing.dependencyModelNames = Array.from(/* @__PURE__ */ new Set([...existing.dependencyModelNames, ...dependencyModelNames]));
|
|
574
|
+
if (options.pagination) {
|
|
575
|
+
existing.windows.set(socketId, {
|
|
576
|
+
requestedCount: options.pagination.limit,
|
|
577
|
+
version: 0
|
|
578
|
+
});
|
|
579
|
+
} else {
|
|
580
|
+
existing.windows.delete(socketId);
|
|
581
|
+
}
|
|
458
582
|
} else {
|
|
459
583
|
modelSubs.set(queryKey, {
|
|
460
584
|
query,
|
|
461
585
|
options,
|
|
462
586
|
dependencyModelNames: Array.from(new Set(dependencyModelNames)),
|
|
463
|
-
socketIds: /* @__PURE__ */ new Set([socketId])
|
|
587
|
+
socketIds: /* @__PURE__ */ new Set([socketId]),
|
|
588
|
+
windows: options.pagination ? /* @__PURE__ */ new Map([[socketId, {
|
|
589
|
+
requestedCount: options.pagination.limit,
|
|
590
|
+
version: 0
|
|
591
|
+
}]]) : /* @__PURE__ */ new Map()
|
|
464
592
|
});
|
|
465
593
|
}
|
|
466
594
|
const byModel = socketSubscriptions.get(socketId) ?? /* @__PURE__ */ new Map();
|
|
@@ -512,6 +640,7 @@ const removeSocketSubscription = ({
|
|
|
512
640
|
const affectedModelNames = /* @__PURE__ */ new Set([modelName, ...sub?.dependencyModelNames ?? []]);
|
|
513
641
|
if (sub) {
|
|
514
642
|
sub.socketIds.delete(socketId);
|
|
643
|
+
sub.windows.delete(socketId);
|
|
515
644
|
if (!sub.socketIds.size) {
|
|
516
645
|
modelSubs?.delete(queryKey);
|
|
517
646
|
}
|
|
@@ -716,15 +845,56 @@ const handleClientMessage = async ({
|
|
|
716
845
|
});
|
|
717
846
|
return;
|
|
718
847
|
}
|
|
719
|
-
if (!message.query || typeof message.query !== "object") return;
|
|
720
848
|
const ability = meta.ability;
|
|
721
849
|
if (!ability.can("read", message.modelName)) {
|
|
722
850
|
sendAccessError("forbidden");
|
|
723
851
|
return;
|
|
724
852
|
}
|
|
853
|
+
if (message.type === "set-query-window") {
|
|
854
|
+
if (!isValidQueryWindowCount(message.requestedCount)) {
|
|
855
|
+
sendWs(ws, {
|
|
856
|
+
type: "query-payload",
|
|
857
|
+
modelName: message.modelName,
|
|
858
|
+
queryKey: message.queryKey,
|
|
859
|
+
error: "Invalid requestedCount"
|
|
860
|
+
});
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
|
|
864
|
+
const window = subscription?.windows.get(socketId);
|
|
865
|
+
if (!subscription || !subscription.options.pagination || !window) {
|
|
866
|
+
sendWs(ws, {
|
|
867
|
+
type: "query-payload",
|
|
868
|
+
modelName: message.modelName,
|
|
869
|
+
queryKey: message.queryKey,
|
|
870
|
+
error: "Paginated query subscription not found"
|
|
871
|
+
});
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
window.requestedCount = message.requestedCount;
|
|
875
|
+
await runAndSendSubscriptionQuery({
|
|
876
|
+
tenantId: meta.tenantId,
|
|
877
|
+
targetSocketIds: [socketId],
|
|
878
|
+
ability,
|
|
879
|
+
modelName: message.modelName,
|
|
880
|
+
queryKey: message.queryKey,
|
|
881
|
+
subscription
|
|
882
|
+
});
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
if (!message.query || typeof message.query !== "object") return;
|
|
725
886
|
if (message.type === "register-query" || message.type === "run-query") {
|
|
726
887
|
const options = normalizeRtsQueryOptions(message.options);
|
|
727
888
|
if (message.type === "register-query") {
|
|
889
|
+
if (options.pagination && !isValidQueryWindowCount(options.pagination.limit)) {
|
|
890
|
+
sendWs(ws, {
|
|
891
|
+
type: "query-payload",
|
|
892
|
+
modelName: message.modelName,
|
|
893
|
+
queryKey: message.queryKey,
|
|
894
|
+
error: "Invalid requestedCount"
|
|
895
|
+
});
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
728
898
|
const existing = socketSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false;
|
|
729
899
|
if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {
|
|
730
900
|
sendWs(ws, {
|
|
@@ -756,6 +926,7 @@ const handleClientMessage = async ({
|
|
|
756
926
|
return;
|
|
757
927
|
}
|
|
758
928
|
}
|
|
929
|
+
if (!sockets.has(socketId)) return;
|
|
759
930
|
addSocketSubscription({
|
|
760
931
|
socketId,
|
|
761
932
|
tenantId: meta.tenantId,
|
|
@@ -781,9 +952,36 @@ const handleClientMessage = async ({
|
|
|
781
952
|
});
|
|
782
953
|
return;
|
|
783
954
|
}
|
|
955
|
+
if (!sockets.has(socketId)) {
|
|
956
|
+
for (const modelName of /* @__PURE__ */ new Set([message.modelName, ...dependencyModelNames])) {
|
|
957
|
+
closeUnusedChangeStream(meta.tenantId, modelName);
|
|
958
|
+
}
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
784
961
|
if (message.runInitialQuery === false) {
|
|
785
962
|
return;
|
|
786
963
|
}
|
|
964
|
+
const subscription = subscriptions.get(meta.tenantId)?.get(meta.userId)?.get(message.modelName)?.get(message.queryKey);
|
|
965
|
+
if (!subscription) return;
|
|
966
|
+
try {
|
|
967
|
+
await runAndSendSubscriptionQuery({
|
|
968
|
+
tenantId: meta.tenantId,
|
|
969
|
+
targetSocketIds: [socketId],
|
|
970
|
+
ability,
|
|
971
|
+
modelName: message.modelName,
|
|
972
|
+
queryKey: message.queryKey,
|
|
973
|
+
subscription
|
|
974
|
+
});
|
|
975
|
+
} catch (err) {
|
|
976
|
+
const error = redactErrorMessage(err);
|
|
977
|
+
sendWs(ws, {
|
|
978
|
+
type: "query-payload",
|
|
979
|
+
modelName: message.modelName,
|
|
980
|
+
queryKey: message.queryKey,
|
|
981
|
+
error
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
return;
|
|
787
985
|
}
|
|
788
986
|
try {
|
|
789
987
|
await runAndSendQuery({
|
|
@@ -838,6 +1036,10 @@ const handleClientMessage = async ({
|
|
|
838
1036
|
});
|
|
839
1037
|
return;
|
|
840
1038
|
}
|
|
1039
|
+
if (!sockets.has(socketId)) {
|
|
1040
|
+
closeUnusedChangeStream(meta.tenantId, message.modelName);
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
841
1043
|
if (message.runInitialQuery === false) {
|
|
842
1044
|
return;
|
|
843
1045
|
}
|
|
@@ -970,6 +1172,7 @@ const initRts = ({
|
|
|
970
1172
|
}
|
|
971
1173
|
}
|
|
972
1174
|
if (cleanupFns.length) socketCleanup.set(socketId, cleanupFns);
|
|
1175
|
+
let messageQueue = Promise.resolve();
|
|
973
1176
|
ws.on("message", (raw) => {
|
|
974
1177
|
let parsed;
|
|
975
1178
|
try {
|
|
@@ -979,12 +1182,12 @@ const initRts = ({
|
|
|
979
1182
|
}
|
|
980
1183
|
if (!parsed || typeof parsed !== "object") return;
|
|
981
1184
|
const message = parsed;
|
|
982
|
-
if (message.type !== "event" && message.type !== "rts-message" && message.type !== "run-query" && message.type !== "register-query" && message.type !== "remove-query" && message.type !== "run-count" && message.type !== "register-count" && message.type !== "remove-count") return;
|
|
983
|
-
|
|
1185
|
+
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;
|
|
1186
|
+
messageQueue = messageQueue.then(() => handleClientMessage({
|
|
984
1187
|
socketId,
|
|
985
1188
|
meta,
|
|
986
1189
|
message
|
|
987
|
-
});
|
|
1190
|
+
})).catch(() => void 0);
|
|
988
1191
|
});
|
|
989
1192
|
ws.on("close", () => {
|
|
990
1193
|
cleanupSocket(socketId);
|