@rpcbase/server 0.636.0 → 0.638.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.
@@ -125,13 +125,44 @@ var deleteFile = async (_payload, ctx) => {
125
125
  return { ok: true };
126
126
  };
127
127
  //#endregion
128
+ //#region src/uploads/fileContentHeaders.ts
129
+ var inlineMimeTypes = /* @__PURE__ */ new Set([
130
+ "image/png",
131
+ "image/jpeg",
132
+ "image/gif",
133
+ "image/webp",
134
+ "image/avif",
135
+ "image/bmp",
136
+ "image/x-icon",
137
+ "image/svg+xml",
138
+ "text/plain",
139
+ "audio/mpeg",
140
+ "audio/ogg",
141
+ "audio/wav",
142
+ "audio/webm",
143
+ "audio/mp4",
144
+ "video/mp4",
145
+ "video/webm",
146
+ "video/ogg"
147
+ ]);
148
+ var getFileContentHeaders = (mimeType, filename) => {
149
+ const normalizedMimeType = mimeType.split(";")[0].trim().toLowerCase();
150
+ const inline = inlineMimeTypes.has(normalizedMimeType);
151
+ const safeFilename = filename.replace(/[^\x20-\x7e]|[\\"]/g, "_");
152
+ return {
153
+ "Content-Type": inline ? normalizedMimeType : "application/octet-stream",
154
+ "Content-Disposition": `${inline ? "inline" : "attachment"}; filename="${safeFilename}"; filename*=UTF-8''${encodeURIComponent(Buffer.from(filename).toString("utf8")).replace(/['()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`)}`,
155
+ "X-Content-Type-Options": "nosniff",
156
+ "Content-Security-Policy": "default-src 'none'; style-src 'unsafe-inline'; sandbox; base-uri 'none'; form-action 'none'"
157
+ };
158
+ };
159
+ //#endregion
128
160
  //#region src/uploads/api/files/handlers/getFile.ts
129
161
  var resolveHeaderString = (value) => {
130
162
  if (typeof value !== "string") return null;
131
163
  const normalized = value.trim();
132
164
  return normalized ? normalized : null;
133
165
  };
134
- var escapeHeaderFilename = (filename) => filename.replace(/[\\"]/g, "_");
135
166
  var parseRequestedWidth = (value) => {
136
167
  if (typeof value !== "string") return null;
137
168
  const parsed = Number(value.trim());
@@ -234,12 +265,13 @@ var getFile = async (_payload, ctx) => {
234
265
  const selectedFileObjectId = variantFile ? variantFileObjectId : blobObjectId;
235
266
  const selectedFile = variantFile ?? file;
236
267
  const mimeType = resolveHeaderString(selectedFile?.metadata?.mimeType) ?? "application/octet-stream";
237
- const filenameSafe = escapeHeaderFilename(resolveHeaderString(reference?.filename ?? selectedFile?.filename) ?? fileIdRaw);
268
+ const filename = resolveHeaderString(reference?.filename ?? selectedFile?.filename) ?? fileIdRaw;
269
+ for (const [name, value] of Object.entries(getFileContentHeaders(mimeType, filename))) ctx.res.setHeader(name, value);
238
270
  const cacheControl = "private, max-age=0, must-revalidate";
239
271
  const md5 = resolveHeaderString(selectedFile?.md5);
240
272
  const uploadDate = selectedFile?.uploadDate instanceof Date ? selectedFile.uploadDate : null;
241
273
  const etagValue = md5 ?? `${selectedFileObjectId.toHexString()}-${String(selectedFile?.length ?? 0)}-${String(uploadDate?.getTime() ?? 0)}`;
242
- const etag = md5 ? `"${etagValue}"` : `W/"${etagValue}"`;
274
+ const etag = md5 ? `"${etagValue}-safe-v1"` : `W/"${etagValue}-safe-v1"`;
243
275
  const ifNoneMatch = resolveHeaderString(ctx.req.headers?.["if-none-match"]);
244
276
  if (ifNoneMatch) {
245
277
  const candidates = ifNoneMatch.split(",").map((value) => value.trim()).filter(Boolean);
@@ -252,13 +284,9 @@ var getFile = async (_payload, ctx) => {
252
284
  }
253
285
  }
254
286
  ctx.res.status(200);
255
- ctx.res.setHeader("Content-Type", mimeType);
256
287
  ctx.res.setHeader("Content-Length", String(selectedFile?.length ?? 0));
257
- ctx.res.setHeader("Content-Disposition", `inline; filename="${filenameSafe}"`);
258
288
  ctx.res.setHeader("Cache-Control", cacheControl);
259
289
  ctx.res.setHeader("ETag", etag);
260
- ctx.res.setHeader("X-Content-Type-Options", "nosniff");
261
- if (mimeType === "image/svg+xml") ctx.res.setHeader("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox; base-uri 'none'; form-action 'none'");
262
290
  ctx.res.flushHeaders();
263
291
  if (ctx.req.method === "HEAD") {
264
292
  ctx.res.end();
@@ -285,4 +313,4 @@ var handler_default = (api) => {
285
313
  //#endregion
286
314
  export { handler_default as default };
287
315
 
288
- //# sourceMappingURL=handler-C34TFH28.js.map
316
+ //# sourceMappingURL=handler-Dy_L6_-U.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-Dy_L6_-U.js","names":[],"sources":["../src/uploads/api/files/handlers/deleteFile.ts","../src/uploads/fileContentHeaders.ts","../src/uploads/api/files/handlers/getFile.ts","../src/uploads/api/files/index.ts","../src/uploads/api/files/handler.ts"],"sourcesContent":["import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\n\nimport {\n deleteUploadFileReference,\n findUploadFileReference,\n} from \"../../file-uploads/fileReferences\"\nimport {\n getBucketName,\n getTenantId,\n getUploadKeyHash,\n getUserId,\n resolveStoredUploadAccessScope,\n type SessionUser,\n} from \"../../file-uploads/shared\"\n\n\ntype DeleteResponsePayload = {\n ok: boolean\n error?: string\n}\n\nconst resolveHeaderString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized ? normalized : null\n}\n\nconst isFileNotFoundError = (error: unknown): boolean => {\n const message = error instanceof Error ? error.message : String(error)\n return message.includes(\"FileNotFound\")\n}\n\nconst deleteGridFsFile = async (bucket: GridFSBucket, fileId: ObjectId): Promise<void> => {\n try {\n await bucket.delete(fileId)\n } catch (error) {\n if (!isFileNotFoundError(error)) throw error\n }\n}\n\nexport const deleteFile: ApiHandler<Record<string, never>, DeleteResponsePayload, SessionUser> = async (\n _payload,\n ctx,\n): Promise<DeleteResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const fileIdRaw = String(ctx.req.params?.fileId ?? \"\").trim()\n let fileObjectId: ObjectId\n try {\n fileObjectId = new ObjectId(fileIdRaw)\n } catch {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_file_id\" }\n }\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) {\n ctx.res.status(500)\n return { ok: false, error: \"filesystem_db_unavailable\" }\n }\n\n const bucketName = getBucketName()\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n\n const userId = getUserId(ctx)\n const uploadKeyHash = getUploadKeyHash(ctx)\n if (!userId && !uploadKeyHash) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId)\n if (reference) {\n const referenceMetadata = reference as unknown as Record<string, unknown>\n const metadataUserId = resolveHeaderString(reference.userId)\n const ownerKeyHash = resolveHeaderString(reference.ownerKeyHash)\n const accessScope = resolveStoredUploadAccessScope(referenceMetadata)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n const authorizedByTenant = accessScope === \"tenant\" && Boolean(userId)\n\n if (!authorizedByUser && !authorizedByKey && !authorizedByTenant) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n try {\n await deleteUploadFileReference({\n tenantId,\n bucketName,\n referenceId: fileObjectId,\n })\n } catch {\n ctx.res.status(500)\n return { ok: false, error: \"delete_failed\" }\n }\n\n ctx.res.status(204)\n return { ok: true }\n }\n\n const [file] = await bucket.find({ _id: fileObjectId }).limit(1).toArray()\n if (!file) {\n ctx.res.status(204)\n return { ok: true }\n }\n\n const metadataUserId = resolveHeaderString((file as any)?.metadata?.userId)\n const ownerKeyHash = resolveHeaderString((file as any)?.metadata?.ownerKeyHash)\n const rawMetadata = (file as any)?.metadata\n const fileMetadata = rawMetadata && typeof rawMetadata === \"object\"\n ? rawMetadata as Record<string, unknown>\n : {}\n const accessScope = resolveStoredUploadAccessScope(fileMetadata)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n const authorizedByTenant = accessScope === \"tenant\" && Boolean(userId)\n\n if (!authorizedByUser && !authorizedByKey && !authorizedByTenant) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n if (fileMetadata.deduplication && typeof fileMetadata.deduplication === \"object\") {\n ctx.res.status(409)\n return { ok: false, error: \"file_reference_required\" }\n }\n\n try {\n const variants = await bucket.find({ \"metadata.variantOf\": fileObjectId.toHexString() }).toArray()\n const variantIds = variants\n .map((variant) => (variant as any)?._id)\n .filter((id): id is ObjectId => id instanceof ObjectId)\n\n await deleteGridFsFile(bucket, fileObjectId)\n for (const variantId of variantIds) {\n await deleteGridFsFile(bucket, variantId)\n }\n } catch {\n ctx.res.status(500)\n return { ok: false, error: \"delete_failed\" }\n }\n\n ctx.res.status(204)\n return { ok: true }\n}\n","const inlineMimeTypes = new Set([\n \"image/png\", \"image/jpeg\", \"image/gif\", \"image/webp\", \"image/avif\", \"image/bmp\", \"image/x-icon\",\n \"image/svg+xml\", \"text/plain\",\n \"audio/mpeg\", \"audio/ogg\", \"audio/wav\", \"audio/webm\", \"audio/mp4\",\n \"video/mp4\", \"video/webm\", \"video/ogg\",\n])\n\nexport const getFileContentHeaders = (mimeType: string, filename: string): Record<string, string> => {\n const normalizedMimeType = mimeType.split(\";\")[0].trim().toLowerCase()\n const inline = inlineMimeTypes.has(normalizedMimeType)\n const safeFilename = filename.replace(/[^\\x20-\\x7e]|[\\\\\"]/g, \"_\")\n\n return {\n \"Content-Type\": inline ? normalizedMimeType : \"application/octet-stream\",\n \"Content-Disposition\": `${inline ? \"inline\" : \"attachment\"}; filename=\"${safeFilename}\"; filename*=UTF-8''${encodeURIComponent(Buffer.from(filename).toString(\"utf8\")).replace(/['()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`)}`,\n \"X-Content-Type-Options\": \"nosniff\",\n \"Content-Security-Policy\": \"default-src 'none'; style-src 'unsafe-inline'; sandbox; base-uri 'none'; form-action 'none'\",\n }\n}\n","import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\n\nimport { getFileContentHeaders } from \"../../../fileContentHeaders\"\nimport { findUploadFileReference } from \"../../file-uploads/fileReferences\"\nimport {\n getBucketName,\n getTenantId,\n getUploadKeyHash,\n getUserId,\n resolveStoredUploadAccessScope,\n type SessionUser,\n} from \"../../file-uploads/shared\"\n\n\nconst resolveHeaderString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized ? normalized : null\n}\n\nconst parseRequestedWidth = (value: unknown): number | null => {\n if (typeof value !== \"string\") return null\n const parsed = Number(value.trim())\n if (!Number.isFinite(parsed) || parsed <= 0) return null\n return Math.floor(parsed)\n}\n\nconst resolveImageVariants = (file: unknown): Record<string, unknown> | null => {\n const metadata = (file as any)?.metadata\n if (!metadata || typeof metadata !== \"object\") return null\n const image = (metadata as Record<string, unknown>).image\n if (!image || typeof image !== \"object\") return null\n const variants = (image as Record<string, unknown>).variants\n if (!variants || typeof variants !== \"object\") return null\n return variants as Record<string, unknown>\n}\n\nconst resolveVariantFileId = (variant: unknown): ObjectId | null => {\n if (!variant || typeof variant !== \"object\") return null\n const fileId = (variant as Record<string, unknown>).fileId\n if (typeof fileId !== \"string\") return null\n try {\n return new ObjectId(fileId)\n } catch {\n return null\n }\n}\n\nconst selectVariantFileId = (file: unknown, requestedWidth: number | null, requestedVariant: unknown): ObjectId | null => {\n const variants = resolveImageVariants(file)\n if (!variants) return null\n\n let aliasWidth: number | null = null\n if (typeof requestedVariant === \"string\") {\n const normalized = requestedVariant.trim().toLowerCase()\n aliasWidth = normalized === \"thumb\" ? 320 : normalized === \"small\" ? 640 : normalized === \"medium\" ? 960 : normalized === \"large\" ? 1600 : null\n if (aliasWidth) {\n const variantFileId = resolveVariantFileId(variants[String(aliasWidth)])\n if (variantFileId) return variantFileId\n }\n }\n\n const targetWidth = aliasWidth ?? requestedWidth\n if (!targetWidth) return null\n\n const widths = Object.keys(variants)\n .map((width) => Number(width))\n .filter((width) => Number.isInteger(width) && width > 0)\n .sort((a, b) => a - b)\n\n const selectedWidth = widths.reduce<number | null>((selected, width) => {\n if (selected === null) return width\n\n const selectedDistance = Math.abs(selected - targetWidth)\n const distance = Math.abs(width - targetWidth)\n if (distance < selectedDistance) return width\n if (distance === selectedDistance && width > selected) return width\n return selected\n }, null)\n return selectedWidth ? resolveVariantFileId(variants[String(selectedWidth)]) : null\n}\n\nexport const getFile: ApiHandler<Record<string, never>, Record<string, never>, SessionUser> = async (\n _payload,\n ctx,\n): Promise<Record<string, never>> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400).end()\n return {}\n }\n\n const fileIdRaw = String(ctx.req.params?.fileId ?? \"\").trim()\n let fileObjectId: ObjectId\n try {\n fileObjectId = new ObjectId(fileIdRaw)\n } catch {\n ctx.res.status(400).end()\n return {}\n }\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) {\n ctx.res.status(500).end()\n return {}\n }\n\n const bucketName = getBucketName()\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId)\n const blobObjectId = reference?.blobId ?? fileObjectId\n\n const [file] = await bucket.find({ _id: blobObjectId }).limit(1).toArray()\n if (!file) {\n ctx.res.status(404).end()\n return {}\n }\n\n const rawMetadata = reference ?? (file as any)?.metadata\n const fileMetadata = rawMetadata && typeof rawMetadata === \"object\"\n ? rawMetadata as Record<string, unknown>\n : {}\n const accessScope = resolveStoredUploadAccessScope(fileMetadata)\n if (accessScope !== \"public\") {\n const userId = getUserId(ctx)\n if (accessScope === \"tenant\") {\n if (!userId) {\n ctx.res.status(401).end()\n return {}\n }\n } else {\n const uploadKeyHash = getUploadKeyHash(ctx)\n const metadataUserId = resolveHeaderString(fileMetadata.userId)\n const ownerKeyHash = resolveHeaderString(fileMetadata.ownerKeyHash)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n\n if (!authorizedByUser && !authorizedByKey) {\n ctx.res.status(401).end()\n return {}\n }\n }\n }\n\n const requestedWidth = parseRequestedWidth((ctx.req.query as any)?.w)\n const variantFileObjectId = selectVariantFileId(file, requestedWidth, (ctx.req.query as any)?.variant)\n const [variantFile] = variantFileObjectId\n ? await bucket.find({ _id: variantFileObjectId }).limit(1).toArray()\n : []\n const selectedFileObjectId = variantFile ? variantFileObjectId as ObjectId : blobObjectId\n const selectedFile = variantFile ?? file\n\n const mimeTypeFromMetadata = resolveHeaderString((selectedFile as any)?.metadata?.mimeType)\n const mimeType = mimeTypeFromMetadata ?? \"application/octet-stream\"\n const filenameFromDb = resolveHeaderString(reference?.filename ?? (selectedFile as any)?.filename)\n const filename = filenameFromDb ?? fileIdRaw\n for (const [name, value] of Object.entries(getFileContentHeaders(mimeType, filename))) {\n ctx.res.setHeader(name, value)\n }\n\n const cacheControl = \"private, max-age=0, must-revalidate\"\n const md5 = resolveHeaderString((selectedFile as any)?.md5)\n const uploadDate = (selectedFile as any)?.uploadDate instanceof Date ? (selectedFile as any).uploadDate : null\n const etagValue = md5 ?? `${selectedFileObjectId.toHexString()}-${String((selectedFile as any)?.length ?? 0)}-${String(uploadDate?.getTime() ?? 0)}`\n const etag = md5 ? `\"${etagValue}-safe-v1\"` : `W/\"${etagValue}-safe-v1\"`\n const ifNoneMatch = resolveHeaderString((ctx.req.headers as any)?.[\"if-none-match\"])\n if (ifNoneMatch) {\n const candidates = ifNoneMatch.split(\",\").map((value) => value.trim()).filter(Boolean)\n if (candidates.includes(\"*\") || candidates.includes(etag)) {\n ctx.res.status(304)\n ctx.res.setHeader(\"Cache-Control\", cacheControl)\n ctx.res.setHeader(\"ETag\", etag)\n ctx.res.end()\n return {}\n }\n }\n\n ctx.res.status(200)\n ctx.res.setHeader(\"Content-Length\", String((selectedFile as any)?.length ?? 0))\n ctx.res.setHeader(\"Cache-Control\", cacheControl)\n ctx.res.setHeader(\"ETag\", etag)\n ctx.res.flushHeaders()\n\n if (ctx.req.method === \"HEAD\") {\n ctx.res.end()\n return {}\n }\n\n const stream = bucket.openDownloadStream(selectedFileObjectId)\n\n stream.on(\"error\", () => {\n try {\n ctx.res.destroy()\n } catch {\n //\n }\n })\n\n stream.pipe(ctx.res)\n return {}\n}\n","export const ROUTE = \"/api/rb/files/:fileId\"\n","import { Api } from \"@rpcbase/api\"\n\nimport { deleteFile } from \"./handlers/deleteFile\"\nimport { getFile } from \"./handlers/getFile\"\n\nimport * as Files from \"./index\"\n\n\nexport default (api: Api) => {\n api.get(Files.ROUTE, getFile)\n api.delete(Files.ROUTE, deleteFile)\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-BPOCksWG.js";
2
- import { c as runRtsQuery, d as getDerivedKey, i as normalizeRtsQueryOptions, n as buildRtsAbilityFromRequest, o as resolveRtsRequestTenantId, r as isRtsRequestAuthorized, s as runRtsCount, t as RTS_QUERY_WINDOW_MAX_COUNT, u as syncAuthenticatedSessionMiddleware } from "./queryWindow-NCe5vJHt.js";
2
+ import { c as runRtsQuery, d as syncAuthenticatedSessionMiddleware, i as normalizeRtsQueryOptions, n as buildRtsAbilityFromRequest, o as resolveRtsRequestTenantId, p as getDerivedKey, r as isRtsRequestAuthorized, s as runRtsCount, t as RTS_QUERY_WINDOW_MAX_COUNT } from "./queryWindow-RHVy3D0L.js";
3
3
  import { i as sendEmail, n as configureEmailTransport, r as createResendEmailTransport, t as EmailDeliveryError } from "./email-6gJ8ibKp.js";
4
4
  import { DISPOSABLE_EMAIL_ERROR_CODE, INVALID_EMAIL_DOMAIN_ERROR_CODE, clearEmailDomainValidationCache, getEmailAddressDomain, getEmailAddressValidationErrorCode, isEmailAddressValid, validateEmailDomain } from "./email-validation/index.js";
5
5
  import { l as getFileReferencesCollectionName, s as getBucketName, y as resolveStoredUploadAccessScope } from "./shared-B1VLaHsk.js";
@@ -1,17 +1,20 @@
1
1
  export declare const AUTHENTICATED_USER_ID_HEADER = "rb-authenticated-user-id";
2
2
  export declare const AUTHENTICATED_TENANT_ID_HEADER = "rb-authenticated-tenant-id";
3
+ export declare const AUTH_VERSION_HEADER = "rb-auth-version";
3
4
  export declare const PROXY_AUTH_TIMESTAMP_HEADER = "rb-proxy-auth-timestamp";
4
5
  export declare const PROXY_AUTH_SIGNATURE_HEADER = "rb-proxy-auth-signature";
5
6
  type HeadersLike = Record<string, string | string[] | undefined>;
6
- export declare const buildProxyAuthSignature: ({ userId, tenantId, timestamp, secret, }: {
7
+ export declare const buildProxyAuthSignature: ({ userId, tenantId, timestamp, secret, authVersion, }: {
7
8
  userId: string;
8
9
  tenantId: string;
9
10
  timestamp: string;
10
11
  secret: string;
12
+ authVersion?: number;
11
13
  }) => string;
12
14
  export declare const getTrustedProxyAuth: (headers: HeadersLike | undefined) => {
13
15
  userId: string;
14
16
  tenantId: string;
17
+ authVersion: number;
15
18
  } | null;
16
19
  export {};
17
20
  //# sourceMappingURL=proxyAuth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"proxyAuth.d.ts","sourceRoot":"","sources":["../src/proxyAuth.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,6BAA6B,CAAA;AACtE,eAAO,MAAM,8BAA8B,+BAA+B,CAAA;AAC1E,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AACpE,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AAIpE,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;AA0BhE,eAAO,MAAM,uBAAuB,GAAI,0CAKrC;IACD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf,KAAG,MAIH,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,GAAG,SAAS,KAC/B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IA0BzC,CAAA"}
1
+ {"version":3,"file":"proxyAuth.d.ts","sourceRoot":"","sources":["../src/proxyAuth.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,6BAA6B,CAAA;AACtE,eAAO,MAAM,8BAA8B,+BAA+B,CAAA;AAC1E,eAAO,MAAM,mBAAmB,oBAAoB,CAAA;AACpD,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AACpE,eAAO,MAAM,2BAA2B,4BAA4B,CAAA;AAIpE,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;AA0BhE,eAAO,MAAM,uBAAuB,GAAI,uDAMrC;IACD,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,KAAG,MAIH,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,SAAS,WAAW,GAAG,SAAS,KAC/B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IA8B9D,CAAA"}
@@ -12,6 +12,7 @@ var getDerivedKey = (masterKey, info, length = 32, salt = "") => {
12
12
  //#region src/proxyAuth.ts
13
13
  var AUTHENTICATED_USER_ID_HEADER = "rb-authenticated-user-id";
14
14
  var AUTHENTICATED_TENANT_ID_HEADER = "rb-authenticated-tenant-id";
15
+ var AUTH_VERSION_HEADER = "rb-auth-version";
15
16
  var PROXY_AUTH_TIMESTAMP_HEADER = "rb-proxy-auth-timestamp";
16
17
  var PROXY_AUTH_SIGNATURE_HEADER = "rb-proxy-auth-signature";
17
18
  var MAX_PROXY_AUTH_AGE_MS = 3e5;
@@ -33,14 +34,17 @@ var timingSafeEqualText = (left, right) => {
33
34
  if (leftBuffer.length !== rightBuffer.length) return false;
34
35
  return timingSafeEqual(leftBuffer, rightBuffer);
35
36
  };
36
- var buildProxyAuthSignature = ({ userId, tenantId, timestamp, secret }) => {
37
- return createHmac("sha256", secret).update(`${timestamp}:${userId}:${tenantId}`).digest("hex");
37
+ var buildProxyAuthSignature = ({ userId, tenantId, timestamp, secret, authVersion }) => {
38
+ return createHmac("sha256", secret).update(`${timestamp}:${userId}:${tenantId}${authVersion === void 0 ? "" : `:${authVersion}`}`).digest("hex");
38
39
  };
39
40
  var getTrustedProxyAuth = (headers) => {
40
41
  const userId = getHeaderValue(headers, AUTHENTICATED_USER_ID_HEADER);
41
42
  const tenantId = getHeaderValue(headers, AUTHENTICATED_TENANT_ID_HEADER);
42
43
  const timestamp = getHeaderValue(headers, PROXY_AUTH_TIMESTAMP_HEADER);
43
44
  const signature = getHeaderValue(headers, PROXY_AUTH_SIGNATURE_HEADER);
45
+ const versionHeader = getHeaderValue(headers, AUTH_VERSION_HEADER);
46
+ const authVersion = versionHeader === null ? void 0 : Number(versionHeader);
47
+ if (authVersion !== void 0 && (!Number.isSafeInteger(authVersion) || authVersion < 0)) return null;
44
48
  if (!userId || !tenantId || !timestamp || !signature) return null;
45
49
  const parsedTimestamp = Number(timestamp);
46
50
  if (!Number.isInteger(parsedTimestamp)) return null;
@@ -51,11 +55,13 @@ var getTrustedProxyAuth = (headers) => {
51
55
  userId,
52
56
  tenantId,
53
57
  timestamp,
54
- secret
58
+ secret,
59
+ authVersion
55
60
  }))) return null;
56
61
  return {
57
62
  userId,
58
- tenantId
63
+ tenantId,
64
+ authVersion: authVersion ?? 0
59
65
  };
60
66
  };
61
67
  //#endregion
@@ -89,18 +95,16 @@ var normalizeTenantRoles = (value) => {
89
95
  }).filter((entry) => Boolean(entry));
90
96
  return nextRoles.length ? Object.fromEntries(nextRoles) : void 0;
91
97
  };
92
- var isSessionAuthorizedForTenant = (sessionUser, tenantId) => {
93
- if (!sessionUser) return false;
94
- const signedInTenants = normalizeStringArray(sessionUser.signedInTenants);
95
- if (signedInTenants.length > 0) return signedInTenants.includes(tenantId);
96
- return normalizeString$1(sessionUser.currentTenantId) === tenantId;
97
- };
98
- var loadSessionUser = async (userId, tenantId) => {
98
+ var loadSessionUser = async (userId, tenantId, authVersion) => {
99
99
  const user = await (await models.getGlobal("RBUser", { req: { session: null } })).findById(userId, {
100
100
  tenants: 1,
101
- tenantRoles: 1
101
+ tenantRoles: 1,
102
+ authVersion: 1,
103
+ registrationStatus: 1,
104
+ emailVerificationCode: 1
102
105
  }).lean();
103
- if (!user) return null;
106
+ if (!user || user.registrationStatus === "pending_verification" || typeof user.emailVerificationCode === "string") return null;
107
+ if ((user.authVersion ?? 0) !== (authVersion ?? 0)) return null;
104
108
  const signedInTenants = normalizeStringArray(user.tenants);
105
109
  if (!signedInTenants.includes(tenantId)) return null;
106
110
  const tenantRoles = normalizeTenantRoles(user.tenantRoles);
@@ -109,32 +113,44 @@ var loadSessionUser = async (userId, tenantId) => {
109
113
  currentTenantId: tenantId,
110
114
  signedInTenants,
111
115
  isEntryGateAuthorized: true,
116
+ authVersion: user.authVersion ?? 0,
112
117
  ...tenantRoles ? { tenantRoles } : {}
113
118
  };
114
119
  };
120
+ var revalidateAuthenticatedSession = async (req) => {
121
+ const session = req.session;
122
+ const userId = normalizeString$1(session?.user?.id);
123
+ const tenantId = normalizeString$1(session?.user?.currentTenantId);
124
+ if (!session || !userId || !tenantId) return;
125
+ const nextUser = await loadSessionUser(userId, tenantId, session.user?.authVersion);
126
+ if (!nextUser) {
127
+ delete session.user;
128
+ return;
129
+ }
130
+ session.user = {
131
+ ...session.user,
132
+ tenantRoles: void 0,
133
+ ...nextUser
134
+ };
135
+ };
115
136
  var syncAuthenticatedSessionFromRequest = async (req) => {
116
137
  const proxyAuth = getTrustedProxyAuth(req.headers);
117
- if (!proxyAuth) return;
118
- const { userId, tenantId } = proxyAuth;
119
- const session = req.session;
120
- if (!session) return;
121
- const sessionUser = session.user;
122
- if (normalizeString$1(sessionUser?.id) === userId && isSessionAuthorizedForTenant(sessionUser, tenantId)) {
123
- if (normalizeString$1(sessionUser?.currentTenantId) === tenantId) return;
124
- session.user = {
125
- ...sessionUser && typeof sessionUser === "object" ? sessionUser : {},
126
- id: userId,
127
- currentTenantId: tenantId,
128
- isEntryGateAuthorized: true
129
- };
138
+ if (!proxyAuth) {
139
+ await revalidateAuthenticatedSession(req);
130
140
  return;
131
141
  }
132
- const nextSessionUser = await loadSessionUser(userId, tenantId);
133
- if (!nextSessionUser) {
134
- if (session.user) delete session.user;
142
+ const session = req.session;
143
+ if (!session) return;
144
+ const nextUser = await loadSessionUser(proxyAuth.userId, proxyAuth.tenantId, proxyAuth.authVersion);
145
+ if (!nextUser) {
146
+ delete session.user;
135
147
  return;
136
148
  }
137
- session.user = nextSessionUser;
149
+ session.user = {
150
+ ...session.user?.id === proxyAuth.userId ? session.user : void 0,
151
+ tenantRoles: void 0,
152
+ ...nextUser
153
+ };
138
154
  };
139
155
  var syncAuthenticatedSessionMiddleware = (req, _res, next) => {
140
156
  syncAuthenticatedSessionFromRequest(req).then(() => {
@@ -212,8 +228,8 @@ var getTenantModel = async (tenantId, modelName, ability) => {
212
228
  var getUnsafeTenantModel = async (tenantId, modelName) => models.getUnsafe(modelName, { tenantId });
213
229
  var normalizeLimit = (limit) => {
214
230
  if (typeof limit !== "number") return QUERY_MAX_LIMIT;
215
- if (!Number.isFinite(limit)) return QUERY_MAX_LIMIT;
216
- return Math.min(QUERY_MAX_LIMIT, Math.abs(limit));
231
+ if (!Number.isSafeInteger(limit) || limit <= 0) return QUERY_MAX_LIMIT;
232
+ return Math.min(QUERY_MAX_LIMIT, limit);
217
233
  };
218
234
  var normalizeNonNegativeInteger = (value) => {
219
235
  if (typeof value !== "number") return 0;
@@ -326,7 +342,7 @@ var normalizePopulateOptions = (value) => {
326
342
  const raw = value;
327
343
  const normalized = {};
328
344
  if (raw.sort && typeof raw.sort === "object" && !Array.isArray(raw.sort)) normalized.sort = raw.sort;
329
- if (typeof raw.limit === "number" && Number.isFinite(raw.limit)) normalized.limit = Math.max(0, Math.floor(Math.abs(raw.limit)));
345
+ if (raw.limit !== void 0) normalized.limit = normalizeLimit(typeof raw.limit === "number" ? raw.limit : void 0);
330
346
  if (!normalized.sort && normalized.limit === void 0) return void 0;
331
347
  return normalized;
332
348
  };
@@ -551,6 +567,6 @@ var runRtsCount = async ({ tenantId, ability, modelName, query, allowInternalMod
551
567
  //#region src/rts/queryWindow.ts
552
568
  var RTS_QUERY_WINDOW_MAX_COUNT = 4096;
553
569
  //#endregion
554
- export { resolveRtsQueryDependencyModelNames as a, runRtsQuery as c, getDerivedKey as d, normalizeRtsQueryOptions as i, syncAuthenticatedSessionFromRequest as l, buildRtsAbilityFromRequest as n, resolveRtsRequestTenantId as o, isRtsRequestAuthorized as r, runRtsCount as s, RTS_QUERY_WINDOW_MAX_COUNT as t, syncAuthenticatedSessionMiddleware as u };
570
+ export { resolveRtsQueryDependencyModelNames as a, runRtsQuery as c, syncAuthenticatedSessionMiddleware as d, getTrustedProxyAuth as f, normalizeRtsQueryOptions as i, revalidateAuthenticatedSession as l, buildRtsAbilityFromRequest as n, resolveRtsRequestTenantId as o, getDerivedKey as p, isRtsRequestAuthorized as r, runRtsCount as s, RTS_QUERY_WINDOW_MAX_COUNT as t, syncAuthenticatedSessionFromRequest as u };
555
571
 
556
- //# sourceMappingURL=queryWindow-NCe5vJHt.js.map
572
+ //# sourceMappingURL=queryWindow-RHVy3D0L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryWindow-RHVy3D0L.js","names":[],"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 AUTH_VERSION_HEADER = \"rb-auth-version\"\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 authVersion,\n}: {\n userId: string\n tenantId: string\n timestamp: string\n secret: string\n authVersion?: number\n}): string => {\n return createHmac(\"sha256\", secret)\n .update(`${timestamp}:${userId}:${tenantId}${authVersion === undefined ? \"\" : `:${authVersion}`}`)\n .digest(\"hex\")\n}\n\nexport const getTrustedProxyAuth = (\n headers: HeadersLike | undefined,\n): { userId: string; tenantId: string; authVersion: number } | 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 const versionHeader = getHeaderValue(headers, AUTH_VERSION_HEADER)\n const authVersion = versionHeader === null ? undefined : Number(versionHeader)\n if (authVersion !== undefined && (!Number.isSafeInteger(authVersion) || authVersion < 0)) return null\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 authVersion,\n })\n\n if (!timingSafeEqualText(signature, expectedSignature)) return null\n\n return { userId, tenantId, authVersion: authVersion ?? 0 }\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 authVersion?: 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 authVersion?: unknown\n registrationStatus?: unknown\n emailVerificationCode?: 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 loadSessionUser = async (userId: string, tenantId: string, authVersion: unknown): 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, authVersion: 1, registrationStatus: 1, emailVerificationCode: 1 }).lean() as LoadedUserDoc | null\n if (!user || user.registrationStatus === \"pending_verification\" || typeof user.emailVerificationCode === \"string\") return null\n if ((user.authVersion ?? 0) !== (authVersion ?? 0)) 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 authVersion: user.authVersion ?? 0,\n ...(tenantRoles ? { tenantRoles } : {}),\n }\n}\n\nexport const revalidateAuthenticatedSession = async (req: RequestLike): Promise<void> => {\n const session = req.session\n const userId = normalizeString(session?.user?.id)\n const tenantId = normalizeString(session?.user?.currentTenantId)\n if (!session || !userId || !tenantId) return\n\n const nextUser = await loadSessionUser(userId, tenantId, session.user?.authVersion)\n if (!nextUser) {\n delete session.user\n return\n }\n session.user = { ...session.user, tenantRoles: undefined, ...nextUser }\n}\n\nexport const syncAuthenticatedSessionFromRequest = async (req: RequestLike): Promise<void> => {\n const proxyAuth = getTrustedProxyAuth(req.headers)\n if (!proxyAuth) {\n await revalidateAuthenticatedSession(req)\n return\n }\n const session = req.session\n if (!session) return\n const nextUser = await loadSessionUser(proxyAuth.userId, proxyAuth.tenantId, proxyAuth.authVersion)\n if (!nextUser) {\n delete session.user\n return\n }\n const previousUser = session.user?.id === proxyAuth.userId ? session.user : undefined\n session.user = { ...previousUser, tenantRoles: undefined, ...nextUser }\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 getUnsafeTenantModel = async (tenantId: string, modelName: string): Promise<Model<any>> =>\n models.getUnsafe(modelName, { tenantId })\n\nconst normalizeLimit = (limit?: number): number => {\n if (typeof limit !== \"number\") return QUERY_MAX_LIMIT\n if (!Number.isSafeInteger(limit) || limit <= 0) return QUERY_MAX_LIMIT\n return Math.min(QUERY_MAX_LIMIT, 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 (raw.limit !== undefined) {\n normalized.limit = normalizeLimit(typeof raw.limit === \"number\" ? raw.limit : undefined)\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 getUnsafeTenantModel(tenantId, modelName)\n .then((estimatedCountModel) => runApproximateRtsCount(\n model,\n estimatedCountModel,\n finalQuery,\n ))\n .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 (\n model: Model<any>,\n estimatedCountModel: Model<any>,\n query: JsonObject,\n): 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(\n await estimatedCountModel.estimatedDocumentCount(),\n )\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 const estimatedCountModel = await getUnsafeTenantModel(tenantId, modelName)\n return await runApproximateRtsCount(model, estimatedCountModel, finalQuery)\n}\n","export const RTS_QUERY_WINDOW_MAX_COUNT = 4096\n"],"mappings":"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"}
@@ -12,6 +12,7 @@ type SocketMeta = {
12
12
  tenantId: string;
13
13
  userId: string;
14
14
  ability: AppAbility;
15
+ validate: () => Promise<boolean>;
15
16
  };
16
17
  type HandlerFn = (socket: RtsSocket) => void | (() => void);
17
18
  declare class RtsSocket {
@@ -36,7 +37,7 @@ declare class RtsSocket {
36
37
  dispatch(event: string, payload: unknown): void;
37
38
  dispatchRtsMessage(channel: string, payload: unknown): void;
38
39
  }
39
- export declare const initRts: ({ server, path, sessionMiddleware, postSyncSessionMiddleware, maxPayloadBytes: maxPayloadBytesArg, maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg, dispatchDebounceMs: dispatchDebounceMsArg, allowInternalModels: allowInternalModelsArg, }: {
40
+ export declare const initRts: ({ server, path, sessionMiddleware, postSyncSessionMiddleware, maxPayloadBytes: maxPayloadBytesArg, maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg, dispatchDebounceMs: dispatchDebounceMsArg, allowInternalModels: allowInternalModelsArg, allowedOrigins, }: {
40
41
  server: HttpServer;
41
42
  path?: string;
42
43
  sessionMiddleware: RequestHandler;
@@ -45,6 +46,7 @@ export declare const initRts: ({ server, path, sessionMiddleware, postSyncSessio
45
46
  maxSubscriptionsPerSocket?: number;
46
47
  dispatchDebounceMs?: number;
47
48
  allowInternalModels?: boolean;
49
+ allowedOrigins?: string[];
48
50
  }) => void;
49
51
  export declare const registerRtsHandler: (handler: HandlerFn) => void;
50
52
  export declare const publishRtsMessage: ({ tenantId, userId, channel, payload }: PublishRtsMessageInput) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rts/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rts/index.ts"],"names":[],"mappings":"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"}