@rpcbase/server 0.635.0 → 0.637.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{convertHeifToWebp-DwSrD30G.js → convertHeifToWebp-CIP6qLY7.js} +2 -2
- package/dist/{convertHeifToWebp-DwSrD30G.js.map → convertHeifToWebp-CIP6qLY7.js.map} +1 -1
- package/dist/{handler-Z6wToZhb.js → handler-BkGfOJ1l.js} +2 -2
- package/dist/{handler-Z6wToZhb.js.map → handler-BkGfOJ1l.js.map} +1 -1
- package/dist/{handler-C34TFH28.js → handler-Dy_L6_-U.js} +36 -8
- package/dist/handler-Dy_L6_-U.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/proxyAuth.d.ts +4 -1
- package/dist/proxyAuth.d.ts.map +1 -1
- package/dist/{queryWindow-NCe5vJHt.js → queryWindow-RHVy3D0L.js} +51 -35
- package/dist/queryWindow-RHVy3D0L.js.map +1 -0
- package/dist/rts/index.d.ts +3 -1
- package/dist/rts/index.d.ts.map +1 -1
- package/dist/rts/index.js +87 -10
- package/dist/rts/index.js.map +1 -1
- package/dist/rts/origin.d.ts +3 -0
- package/dist/rts/origin.d.ts.map +1 -0
- package/dist/sharp.d.ts +3 -0
- package/dist/sharp.d.ts.map +1 -0
- package/dist/sharp.js +2 -0
- package/dist/syncAuthenticatedSession.d.ts +2 -0
- package/dist/syncAuthenticatedSession.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/uploads/api/files/handlers/getFile.d.ts.map +1 -1
- package/dist/uploads/fileContentHeaders.d.ts +2 -0
- package/dist/uploads/fileContentHeaders.d.ts.map +1 -0
- package/dist/uploads/worker.js +1 -1
- package/dist/uploads.js +2 -2
- package/package.json +6 -1
- package/dist/handler-C34TFH28.js.map +0 -1
- package/dist/queryWindow-NCe5vJHt.js.map +0 -1
package/dist/rts/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/rts/routes.ts","../../src/rts/index.ts"],"sourcesContent":["export const routes = Object.entries({\n ...import.meta.glob(\"./api/**/handler.ts\"),\n}).reduce<Record<string, unknown>>((acc, [path, mod]) => {\n acc[path.replace(\"./api/\", \"@rpcbase/server/rts/api/\")] = mod\n return acc\n}, {})\n\n","import { randomUUID } from \"node:crypto\"\nimport type { IncomingMessage, Server as HttpServer } from \"node:http\"\nimport type { Socket } from \"node:net\"\n\nimport type { RequestHandler } from \"express\"\nimport type { PaginationPageInfo } from \"@rpcbase/api\"\nimport { models, type LoadModelCtx } from \"@rpcbase/db\"\nimport { buildAbilityFromSession, type AclSubjectType, type AppAbility } from \"@rpcbase/db/acl\"\nimport type { ChangeStream } from \"mongodb\"\nimport type { Model } from \"mongoose\"\nimport { WebSocketServer, type RawData, type WebSocket } from \"ws\"\n\nimport {\n normalizeRtsQueryOptions,\n resolveRtsQueryDependencyModelNames,\n runRtsCount,\n runRtsQuery,\n type RtsQueryOptions as QueryOptions,\n} from \"./queryExecutor\"\nimport { RTS_QUERY_WINDOW_MAX_COUNT } from \"./queryWindow\"\nimport { syncAuthenticatedSessionFromRequest } from \"../syncAuthenticatedSession\"\n\n\ntype JsonObject = Record<string, unknown>\n\ntype CountOptions = {\n key?: string\n}\n\ntype ClientMessage =\n | { type: \"run-query\"; modelName: string; queryKey: string; query: JsonObject; options?: QueryOptions }\n | {\n type: \"register-query\"\n modelName: string\n queryKey: string\n query: JsonObject\n options?: QueryOptions\n runInitialQuery?: boolean\n }\n | { type: \"set-query-window\"; modelName: string; queryKey: string; requestedCount: number }\n | { type: \"remove-query\"; modelName: string; queryKey: string }\n | { type: \"run-count\"; modelName: string; queryKey: string; query: JsonObject; options?: CountOptions }\n | {\n type: \"register-count\"\n modelName: string\n queryKey: string\n query: JsonObject\n options?: CountOptions\n runInitialQuery?: boolean\n }\n | { type: \"remove-count\"; modelName: string; queryKey: string }\n | { type: \"event\"; event: string; payload?: unknown }\n | { type: \"rts-message\"; channel: string; payload?: unknown }\n\ntype ServerMessage =\n | {\n type: \"query-payload\"\n modelName: string\n queryKey: string\n data?: unknown\n error?: string\n txnId?: string\n pageInfo?: PaginationPageInfo\n totalCount?: number\n window?: QueryWindowPayload\n }\n | {\n type: \"count-payload\"\n modelName: string\n queryKey: string\n count?: number\n error?: string\n txnId?: string\n }\n | { type: \"event\"; event: string; payload?: unknown }\n | { type: \"rts-message\"; channel: string; payload?: unknown }\n\nexport type PublishRtsMessageInput = {\n tenantId: string\n userId?: string\n channel: string\n payload?: unknown\n}\n\ntype SocketMeta = {\n tenantId: string\n userId: string\n ability: AppAbility\n}\n\ntype SessionUser = {\n id?: string\n currentTenantId?: string\n}\n\ntype UpgradeRequest = IncomingMessage & {\n session?: {\n user?: SessionUser\n }\n}\n\ntype Subscription = {\n query: JsonObject\n options: QueryOptions\n dependencyModelNames: string[]\n socketIds: Set<string>\n windows: Map<string, QueryWindowState>\n}\n\ntype QueryWindowPayload = {\n requestedCount: number\n version: number\n}\n\ntype QueryWindowState = QueryWindowPayload\n\ntype CountSubscription = {\n query: JsonObject\n socketIds: Set<string>\n}\n\ntype HandlerFn = (socket: RtsSocket) => void | (() => void)\n\nconst QUERY_KEY_MAX_LEN = 4096\n\nconst INTERNAL_MODEL_NAMES = new Set([\"RBRtsChange\", \"RBRtsCounter\"])\n\nconst DEFAULT_MAX_PAYLOAD_BYTES = 1024 * 1024\nconst DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 256\nconst DEFAULT_DISPATCH_DEBOUNCE_MS = 25\n\nconst initializedServers = new WeakSet<HttpServer>()\nconst customHandlers: HandlerFn[] = []\n\nconst sockets = new Map<string, WebSocket>()\nconst socketMeta = new Map<string, SocketMeta>()\nconst socketWrappers = new Map<string, RtsSocket>()\nconst socketCleanup = new Map<string, Array<() => void>>()\n\nconst socketSubscriptions = new Map<string, Map<string, Set<string>>>()\nconst socketCountSubscriptions = new Map<string, Map<string, Set<string>>>()\nconst subscriptions = new Map<string, Map<string, Map<string, Map<string, Subscription>>>>()\nconst countSubscriptions = new Map<string, Map<string, Map<string, Map<string, CountSubscription>>>>()\nconst changeStreams = new Map<string, Map<string, ChangeStream>>()\nconst dispatchTimers = new Map<string, ReturnType<typeof setTimeout>>()\nconst upgradeMeta = new WeakMap<IncomingMessage, SocketMeta>()\n\nlet maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES\nlet maxSubscriptionsPerSocket = DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET\nlet dispatchDebounceMs = DEFAULT_DISPATCH_DEBOUNCE_MS\nlet allowInternalModels = false\n\nconst isValidQueryWindowCount = (value: unknown): value is number =>\n typeof value === \"number\"\n && Number.isInteger(value)\n && value >= 1\n && value <= RTS_QUERY_WINDOW_MAX_COUNT\n\nclass RtsSocket {\n public readonly id: string\n public readonly tenantId: string\n public readonly userId: string\n\n private readonly ws: WebSocket\n private readonly handlers = new Map<string, Set<(payload: unknown) => void>>()\n private readonly messageHandlers = new Map<string, Set<(payload: unknown) => void>>()\n\n public constructor({\n id,\n ws,\n meta,\n }: {\n id: string\n ws: WebSocket\n meta: SocketMeta\n }) {\n this.id = id\n this.ws = ws\n this.tenantId = meta.tenantId\n this.userId = meta.userId\n }\n\n public on(event: string, handler: (payload: unknown) => void): () => void {\n const set = this.handlers.get(event) ?? new Set()\n set.add(handler)\n this.handlers.set(event, set)\n return () => this.off(event, handler)\n }\n\n public off(event: string, handler: (payload: unknown) => void): void {\n const set = this.handlers.get(event)\n if (!set) return\n set.delete(handler)\n if (!set.size) this.handlers.delete(event)\n }\n\n public emit(event: string, payload?: unknown): void {\n sendWs(this.ws, { type: \"event\", event, payload })\n }\n\n public onRtsMessage(channel: string, handler: (payload: unknown) => void): () => void {\n const set = this.messageHandlers.get(channel) ?? new Set()\n set.add(handler)\n this.messageHandlers.set(channel, set)\n return () => this.offRtsMessage(channel, handler)\n }\n\n public offRtsMessage(channel: string, handler: (payload: unknown) => void): void {\n const set = this.messageHandlers.get(channel)\n if (!set) return\n set.delete(handler)\n if (!set.size) this.messageHandlers.delete(channel)\n }\n\n public emitRtsMessage(channel: string, payload?: unknown): void {\n sendWs(this.ws, { type: \"rts-message\", channel, payload })\n }\n\n public close(): void {\n try {\n this.ws.close()\n } catch {\n // ignore\n }\n }\n\n public dispatch(event: string, payload: unknown): void {\n const set = this.handlers.get(event)\n if (!set) return\n for (const handler of set) {\n handler(payload)\n }\n }\n\n public dispatchRtsMessage(channel: string, payload: unknown): void {\n const set = this.messageHandlers.get(channel)\n if (!set) return\n for (const handler of set) {\n handler(payload)\n }\n }\n}\n\nconst rawToText = (raw: RawData): string => {\n if (typeof raw === \"string\") return raw\n if (raw instanceof ArrayBuffer) return Buffer.from(raw).toString()\n if (Array.isArray(raw)) return Buffer.concat(raw).toString()\n return raw.toString()\n}\n\nconst safeJsonParse = (raw: RawData): unknown => JSON.parse(rawToText(raw))\n\nconst sendWs = (ws: WebSocket, message: ServerMessage): void => {\n if (ws.readyState !== 1) return\n ws.send(JSON.stringify(message))\n}\n\nconst ensureSocketErrorHandler = (socket: Socket, context?: () => Record<string, unknown>): void => {\n if (socket.listenerCount(\"error\") > 0) return\n\n socket.on(\"error\", (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n const name = err instanceof Error ? err.name : typeof err\n const stack = err instanceof Error ? err.stack : undefined\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as any).code : undefined\n\n if (code === \"ECONNRESET\" || (code == null && message.includes(\"ECONNRESET\"))) return\n\n console.warn(\"[rb/rts] socket error\", {\n name,\n code,\n message,\n stack,\n remoteAddress: socket.remoteAddress,\n remotePort: socket.remotePort,\n localAddress: socket.localAddress,\n localPort: socket.localPort,\n ...context?.(),\n })\n })\n}\n\nconst redactErrorMessage = (err: unknown): string => {\n const raw = err instanceof Error ? err.message : \"Unknown error\"\n const trimmedModelList = raw.replace(/\\.\\s+Available models:[\\s\\S]*$/, \"\")\n const maxLen = 256\n if (trimmedModelList.length <= maxLen) return trimmedModelList\n return trimmedModelList.slice(0, maxLen)\n}\n\nconst unauthorized = (socket: Socket, message = \"Unauthorized\"): void => {\n ensureSocketErrorHandler(socket)\n try {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\")\n socket.write(`Error: ${message}\\r\\n`)\n socket.end()\n } catch {\n socket.destroy()\n }\n}\n\nconst badRequest = (socket: Socket, message = \"Bad Request\"): void => {\n ensureSocketErrorHandler(socket)\n try {\n socket.write(\"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\")\n socket.write(`Error: ${message}\\r\\n`)\n socket.end()\n } catch {\n socket.destroy()\n }\n}\n\nconst runSessionMiddleware = async (sessionMiddleware: RequestHandler, req: UpgradeRequest): Promise<void> => {\n type MiddlewareReq = Parameters<RequestHandler>[0]\n type MiddlewareRes = Parameters<RequestHandler>[1]\n type MiddlewareNext = Parameters<RequestHandler>[2]\n\n await new Promise<void>((resolve, reject) => {\n const next: MiddlewareNext = (err) => {\n if (err) reject(err)\n else resolve()\n }\n\n sessionMiddleware(req as unknown as MiddlewareReq, {} as unknown as MiddlewareRes, next)\n })\n}\n\nconst parseUpgradeMeta = async ({\n req,\n url,\n sessionMiddleware,\n postSyncSessionMiddleware,\n}: {\n req: IncomingMessage\n url: URL\n sessionMiddleware: RequestHandler\n postSyncSessionMiddleware?: RequestHandler\n}): Promise<SocketMeta> => {\n const upgradeReq = req as UpgradeRequest\n try {\n await runSessionMiddleware(sessionMiddleware, upgradeReq)\n } catch {\n throw new Error(\"Failed to load session for RTS\")\n }\n\n await syncAuthenticatedSessionFromRequest(upgradeReq as never)\n\n if (postSyncSessionMiddleware) {\n try {\n await runSessionMiddleware(postSyncSessionMiddleware, upgradeReq)\n } catch {\n throw new Error(\"RTS session authorization failed\")\n }\n }\n\n const sessionUser = upgradeReq.session?.user\n const sessionUserId = sessionUser?.id?.trim()\n if (!sessionUserId) {\n throw new Error(\"Not signed in (missing session.user.id)\")\n }\n\n const tenantId = sessionUser?.currentTenantId?.trim()\n if (!tenantId) {\n throw new Error(\"Missing current tenant in session\")\n }\n\n const ability = buildAbilityFromSession({ tenantId, session: upgradeReq.session })\n return { tenantId, userId: sessionUserId, ability }\n}\n\nconst getTenantModel = async (tenantId: string, modelName: string): Promise<Model<any>> => {\n const ctx: LoadModelCtx = {\n req: {\n session: {\n user: {\n currentTenantId: tenantId,\n },\n },\n },\n }\n\n return models.getUnsafe(modelName, ctx)\n}\n\nconst makeDispatchKey = (tenantId: string, modelName: string): string => `${tenantId}:${modelName}`\n\nconst clearDispatchTimer = (tenantId: string, modelName: string): void => {\n const key = makeDispatchKey(tenantId, modelName)\n const timer = dispatchTimers.get(key)\n if (!timer) return\n clearTimeout(timer)\n dispatchTimers.delete(key)\n}\n\nconst scheduleDispatchSubscriptionsForModel = (tenantId: string, modelName: string): void => {\n const key = makeDispatchKey(tenantId, modelName)\n if (dispatchTimers.has(key)) return\n\n const delay = Math.max(0, Math.min(1000, Math.floor(dispatchDebounceMs)))\n dispatchTimers.set(key, setTimeout(() => {\n dispatchTimers.delete(key)\n void Promise.all([\n dispatchSubscriptionsForModel(tenantId, modelName),\n dispatchCountSubscriptionsForModel(tenantId, modelName),\n ]).catch(() => {})\n }, delay))\n}\n\nconst runAndSendQuery = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query,\n options,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n query: JsonObject\n options: QueryOptions\n}): Promise<void> => {\n const result = await runRtsQuery({\n tenantId,\n ability,\n modelName,\n query,\n options,\n allowInternalModels,\n })\n const payload: ServerMessage = {\n type: \"query-payload\",\n modelName,\n queryKey,\n data: result.data,\n ...(result.pageInfo ? { pageInfo: result.pageInfo } : {}),\n ...(typeof result.totalCount === \"number\" ? { totalCount: result.totalCount } : {}),\n }\n\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n}\n\nconst getHeadWindowOptions = (options: QueryOptions, requestedCount: number): QueryOptions => {\n if (!options.pagination) return options\n\n const pagination = { ...options.pagination, limit: requestedCount }\n delete pagination.cursor\n delete pagination.direction\n\n return {\n ...options,\n pagination,\n }\n}\n\nconst runAndSendSubscriptionQuery = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n subscription,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n subscription: Subscription\n}): Promise<void> => {\n if (!subscription.options.pagination) {\n await runAndSendQuery({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query: subscription.query,\n options: subscription.options,\n })\n return\n }\n\n const groups = new Map<number, Array<{ socketId: string; window: QueryWindowPayload }>>()\n for (const socketId of targetSocketIds) {\n const state = subscription.windows.get(socketId)\n if (!state) continue\n\n state.version += 1\n const targets = groups.get(state.requestedCount) ?? []\n targets.push({\n socketId,\n window: {\n requestedCount: state.requestedCount,\n version: state.version,\n },\n })\n groups.set(state.requestedCount, targets)\n }\n\n await Promise.all(Array.from(groups.entries()).map(async ([requestedCount, targets]) => {\n try {\n const result = await runRtsQuery({\n tenantId,\n ability,\n modelName,\n query: subscription.query,\n options: getHeadWindowOptions(subscription.options, requestedCount),\n allowInternalModels,\n paginationMaxLimit: RTS_QUERY_WINDOW_MAX_COUNT,\n includePaginationCursors: false,\n })\n\n for (const target of targets) {\n const current = subscription.windows.get(target.socketId)\n if (\n !current\n || current.requestedCount !== target.window.requestedCount\n || current.version !== target.window.version\n ) {\n continue\n }\n\n const ws = sockets.get(target.socketId)\n if (!ws) continue\n sendWs(ws, {\n type: \"query-payload\",\n modelName,\n queryKey,\n data: result.data,\n ...(result.pageInfo ? { pageInfo: result.pageInfo } : {}),\n ...(typeof result.totalCount === \"number\" ? { totalCount: result.totalCount } : {}),\n window: target.window,\n })\n }\n } catch (err) {\n const error = redactErrorMessage(err)\n for (const target of targets) {\n const current = subscription.windows.get(target.socketId)\n if (\n !current\n || current.requestedCount !== target.window.requestedCount\n || current.version !== target.window.version\n ) {\n continue\n }\n\n const ws = sockets.get(target.socketId)\n if (!ws) continue\n sendWs(ws, {\n type: \"query-payload\",\n modelName,\n queryKey,\n error,\n window: target.window,\n })\n }\n }\n }))\n}\n\nconst runAndSendCount = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n query: JsonObject\n}): Promise<void> => {\n const count = await runRtsCount({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels,\n })\n const payload: ServerMessage = {\n type: \"count-payload\",\n modelName,\n queryKey,\n count,\n }\n\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n}\n\nconst subscriptionDependsOnModel = (\n changedModelName: string,\n ownerModelName: string,\n subscription: Subscription,\n): boolean => {\n if (ownerModelName === changedModelName) return true\n return subscription.dependencyModelNames.includes(changedModelName)\n}\n\nconst hasAnySubscriptionsDependingOnModel = (\n tenantId: string,\n modelName: string,\n): boolean => {\n const tenantSubs = subscriptions.get(tenantId)\n if (!tenantSubs) return false\n\n for (const userSubs of tenantSubs.values()) {\n for (const [ownerModelName, modelSubs] of userSubs.entries()) {\n for (const subscription of modelSubs.values()) {\n if (subscriptionDependsOnModel(modelName, ownerModelName, subscription)) {\n return true\n }\n }\n }\n }\n\n return false\n}\n\nconst hasAnyCountSubscriptionsForModel = (\n tenantId: string,\n modelName: string,\n): boolean => {\n const tenantSubs = countSubscriptions.get(tenantId)\n if (!tenantSubs) return false\n\n for (const userSubs of tenantSubs.values()) {\n const modelSubs = userSubs.get(modelName)\n if (modelSubs?.size) {\n return true\n }\n }\n\n return false\n}\n\nconst dispatchSubscriptionsForModel = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantSubs = subscriptions.get(tenantId)\n if (!tenantSubs || !tenantSubs.size) return\n\n for (const userSubs of tenantSubs.values()) {\n for (const [ownerModelName, modelSubs] of userSubs.entries()) {\n for (const [queryKey, sub] of modelSubs.entries()) {\n if (!subscriptionDependsOnModel(modelName, ownerModelName, sub)) continue\n\n const targetSocketIds = Array.from(sub.socketIds)\n if (!targetSocketIds.length) continue\n\n const socketId = targetSocketIds[0]\n const meta = socketMeta.get(socketId)\n const ability = meta?.ability\n if (!ability) continue\n\n try {\n await runAndSendSubscriptionQuery({\n tenantId,\n targetSocketIds,\n ability,\n modelName: ownerModelName,\n queryKey,\n subscription: sub,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n const payload: ServerMessage = { type: \"query-payload\", modelName: ownerModelName, queryKey, error }\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n }\n }\n }\n }\n}\n\nconst dispatchCountSubscriptionsForModel = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantSubs = countSubscriptions.get(tenantId)\n if (!tenantSubs || !tenantSubs.size) return\n\n for (const userSubs of tenantSubs.values()) {\n const modelSubs = userSubs.get(modelName)\n if (!modelSubs) continue\n\n for (const [queryKey, sub] of modelSubs.entries()) {\n const targetSocketIds = Array.from(sub.socketIds)\n if (!targetSocketIds.length) continue\n\n const socketId = targetSocketIds[0]\n const meta = socketMeta.get(socketId)\n const ability = meta?.ability\n if (!ability) continue\n\n try {\n await runAndSendCount({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query: sub.query,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n const payload: ServerMessage = { type: \"count-payload\", modelName, queryKey, error }\n for (const targetSocketId of targetSocketIds) {\n const ws = sockets.get(targetSocketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n }\n }\n }\n}\n\nconst ensureChangeStream = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantStreams = changeStreams.get(tenantId) ?? new Map()\n changeStreams.set(tenantId, tenantStreams)\n if (tenantStreams.has(modelName)) return\n\n const model = await getTenantModel(tenantId, modelName)\n\n const stream = model.watch([], {\n fullDocument: \"updateLookup\",\n })\n\n stream.on(\"change\", () => {\n scheduleDispatchSubscriptionsForModel(tenantId, modelName)\n })\n\n stream.on(\"close\", () => {\n clearDispatchTimer(tenantId, modelName)\n const map = changeStreams.get(tenantId)\n map?.delete(modelName)\n if (map && map.size === 0) changeStreams.delete(tenantId)\n })\n\n stream.on(\"error\", () => {\n try {\n clearDispatchTimer(tenantId, modelName)\n stream.close()\n } catch {\n // ignore\n }\n })\n\n tenantStreams.set(modelName, stream)\n}\n\nconst closeUnusedChangeStream = (tenantId: string, modelName: string): void => {\n if (hasAnySubscriptionsDependingOnModel(tenantId, modelName) || hasAnyCountSubscriptionsForModel(tenantId, modelName)) {\n return\n }\n\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(modelName)\n if (!stream) return\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, modelName)\n tenantStreams?.delete(modelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n}\n\nconst addSocketSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n query,\n options,\n dependencyModelNames,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n query: JsonObject\n options: QueryOptions\n dependencyModelNames: string[]\n}): void => {\n const tenantSubs = subscriptions.get(tenantId) ?? new Map<string, Map<string, Map<string, Subscription>>>()\n subscriptions.set(tenantId, tenantSubs)\n\n const userSubs = tenantSubs.get(userId) ?? new Map<string, Map<string, Subscription>>()\n tenantSubs.set(userId, userSubs)\n\n const modelSubs = userSubs.get(modelName) ?? new Map<string, Subscription>()\n userSubs.set(modelName, modelSubs)\n\n const existing = modelSubs.get(queryKey)\n if (existing) {\n existing.socketIds.add(socketId)\n existing.dependencyModelNames = Array.from(new Set([...existing.dependencyModelNames, ...dependencyModelNames]))\n if (options.pagination) {\n existing.windows.set(socketId, {\n requestedCount: options.pagination.limit,\n version: 0,\n })\n } else {\n existing.windows.delete(socketId)\n }\n } else {\n modelSubs.set(queryKey, {\n query,\n options,\n dependencyModelNames: Array.from(new Set(dependencyModelNames)),\n socketIds: new Set([socketId]),\n windows: options.pagination\n ? new Map([[socketId, { requestedCount: options.pagination.limit, version: 0 }]])\n : new Map(),\n })\n }\n\n const byModel = socketSubscriptions.get(socketId) ?? new Map()\n socketSubscriptions.set(socketId, byModel)\n\n const querySet = byModel.get(modelName) ?? new Set()\n byModel.set(modelName, querySet)\n querySet.add(queryKey)\n}\n\nconst addSocketCountSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n query,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n query: JsonObject\n}): void => {\n const tenantSubs = countSubscriptions.get(tenantId) ?? new Map<string, Map<string, Map<string, CountSubscription>>>()\n countSubscriptions.set(tenantId, tenantSubs)\n\n const userSubs = tenantSubs.get(userId) ?? new Map<string, Map<string, CountSubscription>>()\n tenantSubs.set(userId, userSubs)\n\n const modelSubs = userSubs.get(modelName) ?? new Map<string, CountSubscription>()\n userSubs.set(modelName, modelSubs)\n\n const existing = modelSubs.get(queryKey)\n if (existing) {\n existing.socketIds.add(socketId)\n } else {\n modelSubs.set(queryKey, {\n query,\n socketIds: new Set([socketId]),\n })\n }\n\n const byModel = socketCountSubscriptions.get(socketId) ?? new Map()\n socketCountSubscriptions.set(socketId, byModel)\n\n const querySet = byModel.get(modelName) ?? new Set()\n byModel.set(modelName, querySet)\n querySet.add(queryKey)\n}\n\nconst removeSocketSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n}): void => {\n const tenantSubs = subscriptions.get(tenantId)\n const userSubs = tenantSubs?.get(userId)\n const modelSubs = userSubs?.get(modelName)\n const sub = modelSubs?.get(queryKey)\n const affectedModelNames = new Set<string>([modelName, ...(sub?.dependencyModelNames ?? [])])\n if (sub) {\n sub.socketIds.delete(socketId)\n sub.windows.delete(socketId)\n if (!sub.socketIds.size) {\n modelSubs?.delete(queryKey)\n }\n }\n\n const byModel = socketSubscriptions.get(socketId)\n const set = byModel?.get(modelName)\n if (set) {\n set.delete(queryKey)\n if (!set.size) {\n byModel?.delete(modelName)\n }\n }\n\n if (modelSubs && modelSubs.size === 0) {\n userSubs?.delete(modelName)\n }\n\n if (userSubs && userSubs.size === 0) {\n tenantSubs?.delete(userId)\n }\n\n for (const affectedModelName of affectedModelNames) {\n if (\n hasAnySubscriptionsDependingOnModel(tenantId, affectedModelName)\n || hasAnyCountSubscriptionsForModel(tenantId, affectedModelName)\n ) {\n continue\n }\n\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(affectedModelName)\n if (stream) {\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, affectedModelName)\n tenantStreams?.delete(affectedModelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n }\n }\n\n if (tenantSubs && tenantSubs.size === 0) subscriptions.delete(tenantId)\n if (byModel && byModel.size === 0) socketSubscriptions.delete(socketId)\n}\n\nconst removeSocketCountSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n}): void => {\n const tenantSubs = countSubscriptions.get(tenantId)\n const userSubs = tenantSubs?.get(userId)\n const modelSubs = userSubs?.get(modelName)\n const sub = modelSubs?.get(queryKey)\n if (sub) {\n sub.socketIds.delete(socketId)\n if (!sub.socketIds.size) {\n modelSubs?.delete(queryKey)\n }\n }\n\n const byModel = socketCountSubscriptions.get(socketId)\n const set = byModel?.get(modelName)\n if (set) {\n set.delete(queryKey)\n if (!set.size) {\n byModel?.delete(modelName)\n }\n }\n\n if (modelSubs && modelSubs.size === 0) {\n userSubs?.delete(modelName)\n }\n\n if (userSubs && userSubs.size === 0) {\n tenantSubs?.delete(userId)\n }\n\n if (!hasAnySubscriptionsDependingOnModel(tenantId, modelName) && !hasAnyCountSubscriptionsForModel(tenantId, modelName)) {\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(modelName)\n if (stream) {\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, modelName)\n tenantStreams?.delete(modelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n }\n }\n\n if (tenantSubs && tenantSubs.size === 0) countSubscriptions.delete(tenantId)\n if (byModel && byModel.size === 0) socketCountSubscriptions.delete(socketId)\n}\n\nconst getSocketSubscriptionCount = (socketId: string): number => {\n let count = 0\n const querySubscriptionsByModel = socketSubscriptions.get(socketId)\n if (querySubscriptionsByModel) {\n for (const set of querySubscriptionsByModel.values()) count += set.size\n }\n\n const countSubscriptionsByModel = socketCountSubscriptions.get(socketId)\n if (countSubscriptionsByModel) {\n for (const set of countSubscriptionsByModel.values()) count += set.size\n }\n\n return count\n}\n\nconst cleanupSocket = (socketId: string): void => {\n const meta = socketMeta.get(socketId)\n if (meta) {\n const byModel = socketSubscriptions.get(socketId)\n if (byModel) {\n for (const [modelName, keys] of byModel.entries()) {\n for (const queryKey of keys.values()) {\n removeSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName,\n queryKey,\n })\n }\n }\n }\n\n const countByModel = socketCountSubscriptions.get(socketId)\n if (countByModel) {\n for (const [modelName, keys] of countByModel.entries()) {\n for (const queryKey of keys.values()) {\n removeSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName,\n queryKey,\n })\n }\n }\n }\n }\n\n socketSubscriptions.delete(socketId)\n socketCountSubscriptions.delete(socketId)\n\n const cleanupFns = socketCleanup.get(socketId) ?? []\n socketCleanup.delete(socketId)\n for (const fn of cleanupFns) {\n try {\n fn()\n } catch {\n // ignore\n }\n }\n\n sockets.delete(socketId)\n socketMeta.delete(socketId)\n socketWrappers.delete(socketId)\n}\n\nconst handleClientMessage = async ({\n socketId,\n meta,\n message,\n}: {\n socketId: string\n meta: SocketMeta\n message: ClientMessage\n}): Promise<void> => {\n const ws = sockets.get(socketId)\n if (!ws) return\n\n if (message.type === \"event\") {\n const wrapper = socketWrappers.get(socketId)\n wrapper?.dispatch(message.event, message.payload)\n return\n }\n\n if (message.type === \"rts-message\") {\n const wrapper = socketWrappers.get(socketId)\n wrapper?.dispatchRtsMessage(message.channel, message.payload)\n return\n }\n\n const isCountMessage =\n message.type === \"run-count\"\n || message.type === \"register-count\"\n || message.type === \"remove-count\"\n const sendAccessError = (error: string) => {\n if (isCountMessage) {\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName ?? \"\", queryKey: message.queryKey ?? \"\", error })\n return\n }\n\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName ?? \"\", queryKey: message.queryKey ?? \"\", error })\n }\n\n if (!message.modelName || typeof message.modelName !== \"string\") return\n if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(message.modelName)) {\n sendAccessError(\"Model not allowed\")\n return\n }\n if (!message.queryKey || typeof message.queryKey !== \"string\") return\n if (message.queryKey.length > QUERY_KEY_MAX_LEN) return\n\n if (message.type === \"remove-query\") {\n removeSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n })\n return\n }\n\n if (message.type === \"remove-count\") {\n removeSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n })\n return\n }\n\n const ability = meta.ability\n\n if (!ability.can(\"read\", message.modelName as AclSubjectType)) {\n sendAccessError(\"forbidden\")\n return\n }\n\n if (message.type === \"set-query-window\") {\n if (!isValidQueryWindowCount(message.requestedCount)) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Invalid requestedCount\",\n })\n return\n }\n\n const subscription = subscriptions\n .get(meta.tenantId)\n ?.get(meta.userId)\n ?.get(message.modelName)\n ?.get(message.queryKey)\n const window = subscription?.windows.get(socketId)\n if (!subscription || !subscription.options.pagination || !window) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Paginated query subscription not found\",\n })\n return\n }\n\n window.requestedCount = message.requestedCount\n await runAndSendSubscriptionQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n subscription,\n })\n return\n }\n\n if (!message.query || typeof message.query !== \"object\") return\n\n if (message.type === \"register-query\" || message.type === \"run-query\") {\n const options = normalizeRtsQueryOptions(message.options)\n if (message.type === \"register-query\") {\n if (options.pagination && !isValidQueryWindowCount(options.pagination.limit)) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Invalid requestedCount\",\n })\n return\n }\n\n const existing = socketSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false\n if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error: \"Too many subscriptions\" })\n return\n }\n\n let dependencyModelNames: string[] = []\n if (options.populate !== undefined) {\n try {\n dependencyModelNames = await resolveRtsQueryDependencyModelNames({\n tenantId: meta.tenantId,\n ability,\n modelName: message.modelName,\n options,\n allowInternalModels,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n }\n\n if (!sockets.has(socketId)) return\n\n addSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n options,\n dependencyModelNames,\n })\n\n try {\n const modelNamesToWatch = new Set<string>([message.modelName, ...dependencyModelNames])\n for (const modelName of modelNamesToWatch) {\n await ensureChangeStream(meta.tenantId, modelName)\n }\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n\n if (!sockets.has(socketId)) {\n for (const modelName of new Set<string>([message.modelName, ...dependencyModelNames])) {\n closeUnusedChangeStream(meta.tenantId, modelName)\n }\n return\n }\n\n if (message.runInitialQuery === false) {\n return\n }\n\n const subscription = subscriptions\n .get(meta.tenantId)\n ?.get(meta.userId)\n ?.get(message.modelName)\n ?.get(message.queryKey)\n if (!subscription) return\n\n try {\n await runAndSendSubscriptionQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n subscription,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n return\n }\n\n try {\n await runAndSendQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n options,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n return\n }\n\n if (message.type === \"register-count\" || message.type === \"run-count\") {\n if (message.type === \"register-count\") {\n const existing = socketCountSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false\n if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error: \"Too many subscriptions\" })\n return\n }\n\n addSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n })\n\n try {\n await ensureChangeStream(meta.tenantId, message.modelName)\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n\n if (!sockets.has(socketId)) {\n closeUnusedChangeStream(meta.tenantId, message.modelName)\n return\n }\n\n if (message.runInitialQuery === false) {\n return\n }\n }\n\n try {\n await runAndSendCount({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n }\n}\n\nexport const initRts = ({\n server,\n path = \"/rts\",\n sessionMiddleware,\n postSyncSessionMiddleware,\n maxPayloadBytes: maxPayloadBytesArg,\n maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg,\n dispatchDebounceMs: dispatchDebounceMsArg,\n allowInternalModels: allowInternalModelsArg,\n}: {\n server: HttpServer\n path?: string\n sessionMiddleware: RequestHandler\n postSyncSessionMiddleware?: RequestHandler\n maxPayloadBytes?: number\n maxSubscriptionsPerSocket?: number\n dispatchDebounceMs?: number\n allowInternalModels?: boolean\n}): void => {\n if (initializedServers.has(server)) return\n initializedServers.add(server)\n\n if (typeof maxPayloadBytesArg === \"number\" && Number.isFinite(maxPayloadBytesArg) && maxPayloadBytesArg > 0) {\n maxPayloadBytes = Math.floor(maxPayloadBytesArg)\n }\n\n if (\n typeof maxSubscriptionsPerSocketArg === \"number\"\n && Number.isFinite(maxSubscriptionsPerSocketArg)\n && maxSubscriptionsPerSocketArg > 0\n ) {\n maxSubscriptionsPerSocket = Math.floor(maxSubscriptionsPerSocketArg)\n }\n\n if (typeof dispatchDebounceMsArg === \"number\" && Number.isFinite(dispatchDebounceMsArg) && dispatchDebounceMsArg >= 0) {\n dispatchDebounceMs = Math.floor(dispatchDebounceMsArg)\n }\n\n allowInternalModels = Boolean(allowInternalModelsArg)\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: maxPayloadBytes })\n\n server.on(\"upgrade\", (req: IncomingMessage, socket: Socket, head: Buffer) => {\n ensureSocketErrorHandler(socket, () => ({\n upgradeHost: req.headers.host ?? \"\",\n upgradeUrl: req.url ?? \"\",\n userAgent: typeof req.headers[\"user-agent\"] === \"string\" ? req.headers[\"user-agent\"] : \"\",\n }))\n upgradeMeta.delete(req)\n\n let url: URL\n try {\n url = new URL(req.url ?? \"\", `http://${req.headers.host ?? \"localhost\"}`)\n } catch {\n badRequest(socket, \"Invalid URL\")\n return\n }\n\n if (url.pathname !== path) return\n\n void (async() => {\n try {\n const meta = await parseUpgradeMeta({\n req,\n url,\n sessionMiddleware,\n postSyncSessionMiddleware,\n })\n upgradeMeta.set(req, meta)\n\n wss.handleUpgrade(req, socket, head, (ws: WebSocket) => {\n wss.emit(\"connection\", ws, req)\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : \"RTS upgrade failed\"\n const upgradeReq = req as UpgradeRequest\n const sessionUser = upgradeReq.session?.user\n const sessionUserId = typeof sessionUser?.id === \"string\" ? sessionUser.id.trim() : \"\"\n const sessionTenantId = typeof sessionUser?.currentTenantId === \"string\" ? sessionUser.currentTenantId.trim() : \"\"\n const authenticatedUserIdHeader = req.headers[\"rb-authenticated-user-id\"]\n const authenticatedTenantIdHeader = req.headers[\"rb-authenticated-tenant-id\"]\n console.warn(\"[rb/rts] upgrade rejected\", {\n reason: message,\n host: req.headers.host ?? \"\",\n url: req.url ?? \"\",\n hasSessionUserId: Boolean(sessionUserId),\n hasCurrentTenantId: Boolean(sessionTenantId),\n hasAuthenticatedUserIdHeader: Boolean(Array.isArray(authenticatedUserIdHeader) ? authenticatedUserIdHeader[0] : authenticatedUserIdHeader),\n hasAuthenticatedTenantIdHeader: Boolean(Array.isArray(authenticatedTenantIdHeader) ? authenticatedTenantIdHeader[0] : authenticatedTenantIdHeader),\n userAgent: typeof req.headers[\"user-agent\"] === \"string\" ? req.headers[\"user-agent\"] : \"\",\n })\n if (message === \"Missing current tenant in session\") {\n badRequest(socket, message)\n return\n }\n unauthorized(socket, message)\n return\n }\n })().catch(() => {\n badRequest(socket, \"RTS upgrade failed\")\n })\n })\n\n wss.on(\"connection\", (ws: WebSocket, req: IncomingMessage) => {\n const meta = upgradeMeta.get(req)\n upgradeMeta.delete(req)\n if (!meta) {\n try {\n ws.close()\n } catch {\n // ignore\n }\n return\n }\n\n const socketId = randomUUID()\n sockets.set(socketId, ws)\n socketMeta.set(socketId, meta)\n\n const wrapper = new RtsSocket({ id: socketId, ws, meta })\n socketWrappers.set(socketId, wrapper)\n\n const cleanupFns: Array<() => void> = []\n for (const handler of customHandlers) {\n try {\n const cleanup = handler(wrapper)\n if (typeof cleanup === \"function\") cleanupFns.push(cleanup)\n } catch {\n // ignore\n }\n }\n if (cleanupFns.length) socketCleanup.set(socketId, cleanupFns)\n\n let messageQueue = Promise.resolve()\n\n ws.on(\"message\", (raw: RawData) => {\n let parsed: unknown\n try {\n parsed = safeJsonParse(raw)\n } catch {\n return\n }\n\n if (!parsed || typeof parsed !== \"object\") return\n const message = parsed as { type?: unknown }\n if (\n message.type !== \"event\"\n && message.type !== \"rts-message\"\n && message.type !== \"run-query\"\n && message.type !== \"register-query\"\n && message.type !== \"set-query-window\"\n && message.type !== \"remove-query\"\n && message.type !== \"run-count\"\n && message.type !== \"register-count\"\n && message.type !== \"remove-count\"\n ) return\n messageQueue = messageQueue\n .then(() => handleClientMessage({ socketId, meta, message: message as ClientMessage }))\n .catch(() => undefined)\n })\n\n ws.on(\"close\", () => {\n cleanupSocket(socketId)\n })\n\n ws.on(\"error\", () => {\n cleanupSocket(socketId)\n })\n })\n}\n\nexport const registerRtsHandler = (handler: HandlerFn): void => {\n customHandlers.push(handler)\n}\n\nexport const publishRtsMessage = ({ tenantId, userId, channel, payload }: PublishRtsMessageInput): void => {\n const normalizedTenantId = tenantId.trim()\n const normalizedUserId = userId?.trim()\n const normalizedChannel = channel.trim()\n if (!normalizedTenantId || !normalizedChannel) return\n\n for (const [socketId, meta] of socketMeta.entries()) {\n if (meta.tenantId !== normalizedTenantId) continue\n if (normalizedUserId && meta.userId !== normalizedUserId) continue\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, { type: \"rts-message\", channel: normalizedChannel, payload })\n }\n}\n\nexport const notifyRtsModelChanged = (tenantId: string, modelName: string): void => {\n scheduleDispatchSubscriptionsForModel(tenantId, modelName)\n}\n\nexport * from \"./routes\"\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/rts/origin.ts","../../src/rts/routes.ts","../../src/rts/index.ts"],"sourcesContent":["import type { IncomingMessage } from \"node:http\"\n\nimport { getTrustedProxyAuth } from \"../proxyAuth\"\n\n\nexport const isRtsOriginAllowed = (req: IncomingMessage, allowedOrigins: string[] = []): boolean => {\n const origin = req.headers.origin\n if (origin === undefined) return true\n try {\n const parsed = new URL(origin)\n if (![\"http:\", \"https:\"].includes(parsed.protocol) || parsed.origin !== origin) return false\n if (allowedOrigins.includes(origin)) return true\n const trustedProxy = getTrustedProxyAuth(req.headers)\n const forwardedHost = trustedProxy && req.headers[\"x-forwarded-host\"]\n const forwardedProto = trustedProxy && req.headers[\"x-forwarded-proto\"]\n const host = typeof forwardedHost === \"string\" ? forwardedHost : req.headers.host\n const protocol = typeof forwardedProto === \"string\"\n ? forwardedProto === \"wss\" ? \"https:\" : forwardedProto === \"ws\" ? \"http:\" : `${forwardedProto}:`\n : \"encrypted\" in req.socket && req.socket.encrypted ? \"https:\" : \"http:\"\n return origin === new URL(`${protocol}//${host}`).origin\n } catch {\n return false\n }\n}\n","export const routes = Object.entries({\n ...import.meta.glob(\"./api/**/handler.ts\"),\n}).reduce<Record<string, unknown>>((acc, [path, mod]) => {\n acc[path.replace(\"./api/\", \"@rpcbase/server/rts/api/\")] = mod\n return acc\n}, {})\n\n","import { randomUUID } from \"node:crypto\"\nimport type { IncomingMessage, Server as HttpServer } from \"node:http\"\nimport type { Socket } from \"node:net\"\n\nimport type { RequestHandler } from \"express\"\nimport type { PaginationPageInfo } from \"@rpcbase/api\"\nimport { models, type LoadModelCtx } from \"@rpcbase/db\"\nimport { buildAbilityFromSession, type AclSubjectType, type AppAbility } from \"@rpcbase/db/acl\"\nimport type { ChangeStream } from \"mongodb\"\nimport type { Model } from \"mongoose\"\nimport { WebSocketServer, type RawData, type WebSocket } from \"ws\"\n\nimport {\n normalizeRtsQueryOptions,\n resolveRtsQueryDependencyModelNames,\n runRtsCount,\n runRtsQuery,\n type RtsQueryOptions as QueryOptions,\n} from \"./queryExecutor\"\nimport { RTS_QUERY_WINDOW_MAX_COUNT } from \"./queryWindow\"\nimport { revalidateAuthenticatedSession, syncAuthenticatedSessionFromRequest } from \"../syncAuthenticatedSession\"\nimport { isRtsOriginAllowed } from \"./origin\"\n\n\ntype JsonObject = Record<string, unknown>\n\ntype CountOptions = {\n key?: string\n}\n\ntype ClientMessage =\n | { type: \"run-query\"; modelName: string; queryKey: string; query: JsonObject; options?: QueryOptions }\n | {\n type: \"register-query\"\n modelName: string\n queryKey: string\n query: JsonObject\n options?: QueryOptions\n runInitialQuery?: boolean\n }\n | { type: \"set-query-window\"; modelName: string; queryKey: string; requestedCount: number }\n | { type: \"remove-query\"; modelName: string; queryKey: string }\n | { type: \"run-count\"; modelName: string; queryKey: string; query: JsonObject; options?: CountOptions }\n | {\n type: \"register-count\"\n modelName: string\n queryKey: string\n query: JsonObject\n options?: CountOptions\n runInitialQuery?: boolean\n }\n | { type: \"remove-count\"; modelName: string; queryKey: string }\n | { type: \"event\"; event: string; payload?: unknown }\n | { type: \"rts-message\"; channel: string; payload?: unknown }\n\ntype ServerMessage =\n | {\n type: \"query-payload\"\n modelName: string\n queryKey: string\n data?: unknown\n error?: string\n txnId?: string\n pageInfo?: PaginationPageInfo\n totalCount?: number\n window?: QueryWindowPayload\n }\n | {\n type: \"count-payload\"\n modelName: string\n queryKey: string\n count?: number\n error?: string\n txnId?: string\n }\n | { type: \"event\"; event: string; payload?: unknown }\n | { type: \"rts-message\"; channel: string; payload?: unknown }\n\nexport type PublishRtsMessageInput = {\n tenantId: string\n userId?: string\n channel: string\n payload?: unknown\n}\n\ntype SocketMeta = {\n tenantId: string\n userId: string\n ability: AppAbility\n validate: () => Promise<boolean>\n}\n\ntype SessionUser = {\n id?: string\n currentTenantId?: string\n authVersion?: number\n}\n\ntype UpgradeRequest = IncomingMessage & {\n session?: {\n user?: SessionUser\n cookie?: { expires?: Date | string | null }\n reload?: (callback: (err?: unknown) => void) => unknown\n save?: (callback: (err?: unknown) => void) => unknown\n }\n}\n\ntype Subscription = {\n query: JsonObject\n options: QueryOptions\n dependencyModelNames: string[]\n socketIds: Set<string>\n windows: Map<string, QueryWindowState>\n}\n\ntype QueryWindowPayload = {\n requestedCount: number\n version: number\n}\n\ntype QueryWindowState = QueryWindowPayload\n\ntype CountSubscription = {\n query: JsonObject\n socketIds: Set<string>\n}\n\ntype HandlerFn = (socket: RtsSocket) => void | (() => void)\n\nconst QUERY_KEY_MAX_LEN = 4096\n\nconst INTERNAL_MODEL_NAMES = new Set([\"RBRtsChange\", \"RBRtsCounter\"])\n\nconst DEFAULT_MAX_PAYLOAD_BYTES = 1024 * 1024\nconst DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET = 256\nconst DEFAULT_DISPATCH_DEBOUNCE_MS = 25\n\nconst initializedServers = new WeakSet<HttpServer>()\nconst customHandlers: HandlerFn[] = []\n\nconst sockets = new Map<string, WebSocket>()\nconst socketMeta = new Map<string, SocketMeta>()\nconst socketValidators = new WeakMap<WebSocket, () => Promise<boolean>>()\nconst socketWrappers = new Map<string, RtsSocket>()\nconst socketCleanup = new Map<string, Array<() => void>>()\n\nconst socketSubscriptions = new Map<string, Map<string, Set<string>>>()\nconst socketCountSubscriptions = new Map<string, Map<string, Set<string>>>()\nconst subscriptions = new Map<string, Map<string, Map<string, Map<string, Subscription>>>>()\nconst countSubscriptions = new Map<string, Map<string, Map<string, Map<string, CountSubscription>>>>()\nconst changeStreams = new Map<string, Map<string, ChangeStream>>()\nconst dispatchTimers = new Map<string, ReturnType<typeof setTimeout>>()\nconst upgradeMeta = new WeakMap<IncomingMessage, SocketMeta>()\n\nlet maxPayloadBytes = DEFAULT_MAX_PAYLOAD_BYTES\nlet maxSubscriptionsPerSocket = DEFAULT_MAX_SUBSCRIPTIONS_PER_SOCKET\nlet dispatchDebounceMs = DEFAULT_DISPATCH_DEBOUNCE_MS\nlet allowInternalModels = false\n\nconst isValidQueryWindowCount = (value: unknown): value is number =>\n typeof value === \"number\"\n && Number.isInteger(value)\n && value >= 1\n && value <= RTS_QUERY_WINDOW_MAX_COUNT\n\nclass RtsSocket {\n public readonly id: string\n public readonly tenantId: string\n public readonly userId: string\n\n private readonly ws: WebSocket\n private readonly handlers = new Map<string, Set<(payload: unknown) => void>>()\n private readonly messageHandlers = new Map<string, Set<(payload: unknown) => void>>()\n\n public constructor({\n id,\n ws,\n meta,\n }: {\n id: string\n ws: WebSocket\n meta: SocketMeta\n }) {\n this.id = id\n this.ws = ws\n this.tenantId = meta.tenantId\n this.userId = meta.userId\n }\n\n public on(event: string, handler: (payload: unknown) => void): () => void {\n const set = this.handlers.get(event) ?? new Set()\n set.add(handler)\n this.handlers.set(event, set)\n return () => this.off(event, handler)\n }\n\n public off(event: string, handler: (payload: unknown) => void): void {\n const set = this.handlers.get(event)\n if (!set) return\n set.delete(handler)\n if (!set.size) this.handlers.delete(event)\n }\n\n public emit(event: string, payload?: unknown): void {\n sendWs(this.ws, { type: \"event\", event, payload })\n }\n\n public onRtsMessage(channel: string, handler: (payload: unknown) => void): () => void {\n const set = this.messageHandlers.get(channel) ?? new Set()\n set.add(handler)\n this.messageHandlers.set(channel, set)\n return () => this.offRtsMessage(channel, handler)\n }\n\n public offRtsMessage(channel: string, handler: (payload: unknown) => void): void {\n const set = this.messageHandlers.get(channel)\n if (!set) return\n set.delete(handler)\n if (!set.size) this.messageHandlers.delete(channel)\n }\n\n public emitRtsMessage(channel: string, payload?: unknown): void {\n sendWs(this.ws, { type: \"rts-message\", channel, payload })\n }\n\n public close(): void {\n try {\n this.ws.close()\n } catch {\n // ignore\n }\n }\n\n public dispatch(event: string, payload: unknown): void {\n const set = this.handlers.get(event)\n if (!set) return\n for (const handler of set) {\n handler(payload)\n }\n }\n\n public dispatchRtsMessage(channel: string, payload: unknown): void {\n const set = this.messageHandlers.get(channel)\n if (!set) return\n for (const handler of set) {\n handler(payload)\n }\n }\n}\n\nconst rawToText = (raw: RawData): string => {\n if (typeof raw === \"string\") return raw\n if (raw instanceof ArrayBuffer) return Buffer.from(raw).toString()\n if (Array.isArray(raw)) return Buffer.concat(raw).toString()\n return raw.toString()\n}\n\nconst safeJsonParse = (raw: RawData): unknown => JSON.parse(rawToText(raw))\n\nconst sendWs = (ws: WebSocket, message: ServerMessage): void => {\n if (ws.readyState !== 1) return\n const validate = socketValidators.get(ws)\n if (!validate) return\n void validate().then((valid) => {\n if (valid && ws.readyState === 1) ws.send(JSON.stringify(message))\n }).catch(() => ws.close(1011, \"Session validation failed\"))\n}\n\nconst ensureSocketErrorHandler = (socket: Socket, context?: () => Record<string, unknown>): void => {\n if (socket.listenerCount(\"error\") > 0) return\n\n socket.on(\"error\", (err: unknown) => {\n const message = err instanceof Error ? err.message : String(err)\n const name = err instanceof Error ? err.name : typeof err\n const stack = err instanceof Error ? err.stack : undefined\n const code = err && typeof err === \"object\" && \"code\" in err ? (err as any).code : undefined\n\n if (code === \"ECONNRESET\" || (code == null && message.includes(\"ECONNRESET\"))) return\n\n console.warn(\"[rb/rts] socket error\", {\n name,\n code,\n message,\n stack,\n remoteAddress: socket.remoteAddress,\n remotePort: socket.remotePort,\n localAddress: socket.localAddress,\n localPort: socket.localPort,\n ...context?.(),\n })\n })\n}\n\nconst redactErrorMessage = (err: unknown): string => {\n const raw = err instanceof Error ? err.message : \"Unknown error\"\n const trimmedModelList = raw.replace(/\\.\\s+Available models:[\\s\\S]*$/, \"\")\n const maxLen = 256\n if (trimmedModelList.length <= maxLen) return trimmedModelList\n return trimmedModelList.slice(0, maxLen)\n}\n\nconst unauthorized = (socket: Socket, message = \"Unauthorized\"): void => {\n ensureSocketErrorHandler(socket)\n try {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\")\n socket.write(`Error: ${message}\\r\\n`)\n socket.end()\n } catch {\n socket.destroy()\n }\n}\n\nconst badRequest = (socket: Socket, message = \"Bad Request\"): void => {\n ensureSocketErrorHandler(socket)\n try {\n socket.write(\"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\")\n socket.write(`Error: ${message}\\r\\n`)\n socket.end()\n } catch {\n socket.destroy()\n }\n}\n\nconst runSessionMiddleware = async (sessionMiddleware: RequestHandler, req: UpgradeRequest): Promise<void> => {\n type MiddlewareReq = Parameters<RequestHandler>[0]\n type MiddlewareRes = Parameters<RequestHandler>[1]\n type MiddlewareNext = Parameters<RequestHandler>[2]\n\n await new Promise<void>((resolve, reject) => {\n const next: MiddlewareNext = (err) => {\n if (err) reject(err)\n else resolve()\n }\n\n sessionMiddleware(req as unknown as MiddlewareReq, {} as unknown as MiddlewareRes, next)\n })\n}\n\nconst parseUpgradeMeta = async ({\n req,\n url,\n sessionMiddleware,\n postSyncSessionMiddleware,\n}: {\n req: IncomingMessage\n url: URL\n sessionMiddleware: RequestHandler\n postSyncSessionMiddleware?: RequestHandler\n}): Promise<SocketMeta> => {\n const upgradeReq = req as UpgradeRequest\n try {\n await runSessionMiddleware(sessionMiddleware, upgradeReq)\n } catch {\n throw new Error(\"Failed to load session for RTS\")\n }\n\n await syncAuthenticatedSessionFromRequest(upgradeReq as never)\n\n if (postSyncSessionMiddleware) {\n try {\n await runSessionMiddleware(postSyncSessionMiddleware, upgradeReq)\n } catch {\n throw new Error(\"RTS session authorization failed\")\n }\n }\n\n const sessionUser = upgradeReq.session?.user\n const sessionUserId = sessionUser?.id?.trim()\n if (!sessionUserId) {\n throw new Error(\"Not signed in (missing session.user.id)\")\n }\n\n const tenantId = sessionUser?.currentTenantId?.trim()\n if (!tenantId) {\n throw new Error(\"Missing current tenant in session\")\n }\n\n const ability = buildAbilityFromSession({ tenantId, session: upgradeReq.session })\n const authVersion = sessionUser?.authVersion ?? 0\n const rules = JSON.stringify(ability.rules)\n if (upgradeReq.session?.save) {\n await new Promise<void>((resolve, reject) => {\n upgradeReq.session!.save!((err) => err ? reject(err) : resolve())\n })\n }\n let validation: Promise<boolean> | undefined\n const validate = (): Promise<boolean> => {\n if (validation) return validation\n validation = (async () => {\n if (upgradeReq.session?.reload) {\n await new Promise<void>((resolve, reject) => {\n upgradeReq.session!.reload!((err) => err ? reject(err) : resolve())\n })\n }\n const expires = upgradeReq.session?.cookie?.expires\n if (expires && new Date(expires).getTime() <= Date.now()) return false\n await revalidateAuthenticatedSession(upgradeReq)\n if (!upgradeReq.session?.user?.id) return false\n if (postSyncSessionMiddleware) await runSessionMiddleware(postSyncSessionMiddleware, upgradeReq)\n const currentUser = upgradeReq.session?.user\n return currentUser?.id === sessionUserId\n && currentUser.currentTenantId === tenantId\n && (currentUser.authVersion ?? 0) === authVersion\n && JSON.stringify(buildAbilityFromSession({ tenantId, session: upgradeReq.session }).rules) === rules\n })().catch(() => false).finally(() => { validation = undefined })\n return validation\n }\n return { tenantId, userId: sessionUserId, ability, validate }\n}\n\nconst getTenantModel = async (tenantId: string, modelName: string): Promise<Model<any>> => {\n const ctx: LoadModelCtx = {\n req: {\n session: {\n user: {\n currentTenantId: tenantId,\n },\n },\n },\n }\n\n return models.getUnsafe(modelName, ctx)\n}\n\nconst makeDispatchKey = (tenantId: string, modelName: string): string => `${tenantId}:${modelName}`\n\nconst clearDispatchTimer = (tenantId: string, modelName: string): void => {\n const key = makeDispatchKey(tenantId, modelName)\n const timer = dispatchTimers.get(key)\n if (!timer) return\n clearTimeout(timer)\n dispatchTimers.delete(key)\n}\n\nconst scheduleDispatchSubscriptionsForModel = (tenantId: string, modelName: string): void => {\n const key = makeDispatchKey(tenantId, modelName)\n if (dispatchTimers.has(key)) return\n\n const delay = Math.max(0, Math.min(1000, Math.floor(dispatchDebounceMs)))\n dispatchTimers.set(key, setTimeout(() => {\n dispatchTimers.delete(key)\n void Promise.all([\n dispatchSubscriptionsForModel(tenantId, modelName),\n dispatchCountSubscriptionsForModel(tenantId, modelName),\n ]).catch(() => {})\n }, delay))\n}\n\nconst runAndSendQuery = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query,\n options,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n query: JsonObject\n options: QueryOptions\n}): Promise<void> => {\n const result = await runRtsQuery({\n tenantId,\n ability,\n modelName,\n query,\n options,\n allowInternalModels,\n })\n const payload: ServerMessage = {\n type: \"query-payload\",\n modelName,\n queryKey,\n data: result.data,\n ...(result.pageInfo ? { pageInfo: result.pageInfo } : {}),\n ...(typeof result.totalCount === \"number\" ? { totalCount: result.totalCount } : {}),\n }\n\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n}\n\nconst getHeadWindowOptions = (options: QueryOptions, requestedCount: number): QueryOptions => {\n if (!options.pagination) return options\n\n const pagination = { ...options.pagination, limit: requestedCount }\n delete pagination.cursor\n delete pagination.direction\n\n return {\n ...options,\n pagination,\n }\n}\n\nconst runAndSendSubscriptionQuery = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n subscription,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n subscription: Subscription\n}): Promise<void> => {\n if (!subscription.options.pagination) {\n await runAndSendQuery({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query: subscription.query,\n options: subscription.options,\n })\n return\n }\n\n const groups = new Map<number, Array<{ socketId: string; window: QueryWindowPayload }>>()\n for (const socketId of targetSocketIds) {\n const state = subscription.windows.get(socketId)\n if (!state) continue\n\n state.version += 1\n const targets = groups.get(state.requestedCount) ?? []\n targets.push({\n socketId,\n window: {\n requestedCount: state.requestedCount,\n version: state.version,\n },\n })\n groups.set(state.requestedCount, targets)\n }\n\n await Promise.all(Array.from(groups.entries()).map(async ([requestedCount, targets]) => {\n try {\n const result = await runRtsQuery({\n tenantId,\n ability,\n modelName,\n query: subscription.query,\n options: getHeadWindowOptions(subscription.options, requestedCount),\n allowInternalModels,\n paginationMaxLimit: RTS_QUERY_WINDOW_MAX_COUNT,\n includePaginationCursors: false,\n })\n\n for (const target of targets) {\n const current = subscription.windows.get(target.socketId)\n if (\n !current\n || current.requestedCount !== target.window.requestedCount\n || current.version !== target.window.version\n ) {\n continue\n }\n\n const ws = sockets.get(target.socketId)\n if (!ws) continue\n sendWs(ws, {\n type: \"query-payload\",\n modelName,\n queryKey,\n data: result.data,\n ...(result.pageInfo ? { pageInfo: result.pageInfo } : {}),\n ...(typeof result.totalCount === \"number\" ? { totalCount: result.totalCount } : {}),\n window: target.window,\n })\n }\n } catch (err) {\n const error = redactErrorMessage(err)\n for (const target of targets) {\n const current = subscription.windows.get(target.socketId)\n if (\n !current\n || current.requestedCount !== target.window.requestedCount\n || current.version !== target.window.version\n ) {\n continue\n }\n\n const ws = sockets.get(target.socketId)\n if (!ws) continue\n sendWs(ws, {\n type: \"query-payload\",\n modelName,\n queryKey,\n error,\n window: target.window,\n })\n }\n }\n }))\n}\n\nconst runAndSendCount = async ({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query,\n}: {\n tenantId: string\n targetSocketIds: string[]\n ability: AppAbility\n modelName: string\n queryKey: string\n query: JsonObject\n}): Promise<void> => {\n const count = await runRtsCount({\n tenantId,\n ability,\n modelName,\n query,\n allowInternalModels,\n })\n const payload: ServerMessage = {\n type: \"count-payload\",\n modelName,\n queryKey,\n count,\n }\n\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n}\n\nconst subscriptionDependsOnModel = (\n changedModelName: string,\n ownerModelName: string,\n subscription: Subscription,\n): boolean => {\n if (ownerModelName === changedModelName) return true\n return subscription.dependencyModelNames.includes(changedModelName)\n}\n\nconst hasAnySubscriptionsDependingOnModel = (\n tenantId: string,\n modelName: string,\n): boolean => {\n const tenantSubs = subscriptions.get(tenantId)\n if (!tenantSubs) return false\n\n for (const userSubs of tenantSubs.values()) {\n for (const [ownerModelName, modelSubs] of userSubs.entries()) {\n for (const subscription of modelSubs.values()) {\n if (subscriptionDependsOnModel(modelName, ownerModelName, subscription)) {\n return true\n }\n }\n }\n }\n\n return false\n}\n\nconst hasAnyCountSubscriptionsForModel = (\n tenantId: string,\n modelName: string,\n): boolean => {\n const tenantSubs = countSubscriptions.get(tenantId)\n if (!tenantSubs) return false\n\n for (const userSubs of tenantSubs.values()) {\n const modelSubs = userSubs.get(modelName)\n if (modelSubs?.size) {\n return true\n }\n }\n\n return false\n}\n\nconst getValidatedSocketIds = async (socketIds: Set<string>): Promise<string[]> => {\n const ids = Array.from(socketIds)\n const valid = await Promise.all(ids.map((id) => {\n const ws = sockets.get(id)\n return ws ? socketValidators.get(ws)?.() : false\n }))\n return ids.filter((_, index) => valid[index])\n}\n\nconst dispatchSubscriptionsForModel = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantSubs = subscriptions.get(tenantId)\n if (!tenantSubs || !tenantSubs.size) return\n\n for (const userSubs of tenantSubs.values()) {\n for (const [ownerModelName, modelSubs] of userSubs.entries()) {\n for (const [queryKey, sub] of modelSubs.entries()) {\n if (!subscriptionDependsOnModel(modelName, ownerModelName, sub)) continue\n\n const targetSocketIds = await getValidatedSocketIds(sub.socketIds)\n if (!targetSocketIds.length) continue\n\n const socketId = targetSocketIds[0]\n const meta = socketMeta.get(socketId)\n const ability = meta?.ability\n if (!ability) continue\n\n try {\n await runAndSendSubscriptionQuery({\n tenantId,\n targetSocketIds,\n ability,\n modelName: ownerModelName,\n queryKey,\n subscription: sub,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n const payload: ServerMessage = { type: \"query-payload\", modelName: ownerModelName, queryKey, error }\n for (const socketId of targetSocketIds) {\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n }\n }\n }\n }\n}\n\nconst dispatchCountSubscriptionsForModel = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantSubs = countSubscriptions.get(tenantId)\n if (!tenantSubs || !tenantSubs.size) return\n\n for (const userSubs of tenantSubs.values()) {\n const modelSubs = userSubs.get(modelName)\n if (!modelSubs) continue\n\n for (const [queryKey, sub] of modelSubs.entries()) {\n const targetSocketIds = await getValidatedSocketIds(sub.socketIds)\n if (!targetSocketIds.length) continue\n\n const socketId = targetSocketIds[0]\n const meta = socketMeta.get(socketId)\n const ability = meta?.ability\n if (!ability) continue\n\n try {\n await runAndSendCount({\n tenantId,\n targetSocketIds,\n ability,\n modelName,\n queryKey,\n query: sub.query,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n const payload: ServerMessage = { type: \"count-payload\", modelName, queryKey, error }\n for (const targetSocketId of targetSocketIds) {\n const ws = sockets.get(targetSocketId)\n if (!ws) continue\n sendWs(ws, payload)\n }\n }\n }\n }\n}\n\nconst ensureChangeStream = async (tenantId: string, modelName: string): Promise<void> => {\n const tenantStreams = changeStreams.get(tenantId) ?? new Map()\n changeStreams.set(tenantId, tenantStreams)\n if (tenantStreams.has(modelName)) return\n\n const model = await getTenantModel(tenantId, modelName)\n\n const stream = model.watch([], {\n fullDocument: \"updateLookup\",\n })\n\n stream.on(\"change\", () => {\n scheduleDispatchSubscriptionsForModel(tenantId, modelName)\n })\n\n stream.on(\"close\", () => {\n clearDispatchTimer(tenantId, modelName)\n const map = changeStreams.get(tenantId)\n map?.delete(modelName)\n if (map && map.size === 0) changeStreams.delete(tenantId)\n })\n\n stream.on(\"error\", () => {\n try {\n clearDispatchTimer(tenantId, modelName)\n stream.close()\n } catch {\n // ignore\n }\n })\n\n tenantStreams.set(modelName, stream)\n}\n\nconst closeUnusedChangeStream = (tenantId: string, modelName: string): void => {\n if (hasAnySubscriptionsDependingOnModel(tenantId, modelName) || hasAnyCountSubscriptionsForModel(tenantId, modelName)) {\n return\n }\n\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(modelName)\n if (!stream) return\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, modelName)\n tenantStreams?.delete(modelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n}\n\nconst addSocketSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n query,\n options,\n dependencyModelNames,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n query: JsonObject\n options: QueryOptions\n dependencyModelNames: string[]\n}): void => {\n const tenantSubs = subscriptions.get(tenantId) ?? new Map<string, Map<string, Map<string, Subscription>>>()\n subscriptions.set(tenantId, tenantSubs)\n\n const userSubs = tenantSubs.get(userId) ?? new Map<string, Map<string, Subscription>>()\n tenantSubs.set(userId, userSubs)\n\n const modelSubs = userSubs.get(modelName) ?? new Map<string, Subscription>()\n userSubs.set(modelName, modelSubs)\n\n const existing = modelSubs.get(queryKey)\n if (existing) {\n existing.socketIds.add(socketId)\n existing.dependencyModelNames = Array.from(new Set([...existing.dependencyModelNames, ...dependencyModelNames]))\n if (options.pagination) {\n existing.windows.set(socketId, {\n requestedCount: options.pagination.limit,\n version: 0,\n })\n } else {\n existing.windows.delete(socketId)\n }\n } else {\n modelSubs.set(queryKey, {\n query,\n options,\n dependencyModelNames: Array.from(new Set(dependencyModelNames)),\n socketIds: new Set([socketId]),\n windows: options.pagination\n ? new Map([[socketId, { requestedCount: options.pagination.limit, version: 0 }]])\n : new Map(),\n })\n }\n\n const byModel = socketSubscriptions.get(socketId) ?? new Map()\n socketSubscriptions.set(socketId, byModel)\n\n const querySet = byModel.get(modelName) ?? new Set()\n byModel.set(modelName, querySet)\n querySet.add(queryKey)\n}\n\nconst addSocketCountSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n query,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n query: JsonObject\n}): void => {\n const tenantSubs = countSubscriptions.get(tenantId) ?? new Map<string, Map<string, Map<string, CountSubscription>>>()\n countSubscriptions.set(tenantId, tenantSubs)\n\n const userSubs = tenantSubs.get(userId) ?? new Map<string, Map<string, CountSubscription>>()\n tenantSubs.set(userId, userSubs)\n\n const modelSubs = userSubs.get(modelName) ?? new Map<string, CountSubscription>()\n userSubs.set(modelName, modelSubs)\n\n const existing = modelSubs.get(queryKey)\n if (existing) {\n existing.socketIds.add(socketId)\n } else {\n modelSubs.set(queryKey, {\n query,\n socketIds: new Set([socketId]),\n })\n }\n\n const byModel = socketCountSubscriptions.get(socketId) ?? new Map()\n socketCountSubscriptions.set(socketId, byModel)\n\n const querySet = byModel.get(modelName) ?? new Set()\n byModel.set(modelName, querySet)\n querySet.add(queryKey)\n}\n\nconst removeSocketSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n}): void => {\n const tenantSubs = subscriptions.get(tenantId)\n const userSubs = tenantSubs?.get(userId)\n const modelSubs = userSubs?.get(modelName)\n const sub = modelSubs?.get(queryKey)\n const affectedModelNames = new Set<string>([modelName, ...(sub?.dependencyModelNames ?? [])])\n if (sub) {\n sub.socketIds.delete(socketId)\n sub.windows.delete(socketId)\n if (!sub.socketIds.size) {\n modelSubs?.delete(queryKey)\n }\n }\n\n const byModel = socketSubscriptions.get(socketId)\n const set = byModel?.get(modelName)\n if (set) {\n set.delete(queryKey)\n if (!set.size) {\n byModel?.delete(modelName)\n }\n }\n\n if (modelSubs && modelSubs.size === 0) {\n userSubs?.delete(modelName)\n }\n\n if (userSubs && userSubs.size === 0) {\n tenantSubs?.delete(userId)\n }\n\n for (const affectedModelName of affectedModelNames) {\n if (\n hasAnySubscriptionsDependingOnModel(tenantId, affectedModelName)\n || hasAnyCountSubscriptionsForModel(tenantId, affectedModelName)\n ) {\n continue\n }\n\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(affectedModelName)\n if (stream) {\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, affectedModelName)\n tenantStreams?.delete(affectedModelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n }\n }\n\n if (tenantSubs && tenantSubs.size === 0) subscriptions.delete(tenantId)\n if (byModel && byModel.size === 0) socketSubscriptions.delete(socketId)\n}\n\nconst removeSocketCountSubscription = ({\n socketId,\n tenantId,\n userId,\n modelName,\n queryKey,\n}: {\n socketId: string\n tenantId: string\n userId: string\n modelName: string\n queryKey: string\n}): void => {\n const tenantSubs = countSubscriptions.get(tenantId)\n const userSubs = tenantSubs?.get(userId)\n const modelSubs = userSubs?.get(modelName)\n const sub = modelSubs?.get(queryKey)\n if (sub) {\n sub.socketIds.delete(socketId)\n if (!sub.socketIds.size) {\n modelSubs?.delete(queryKey)\n }\n }\n\n const byModel = socketCountSubscriptions.get(socketId)\n const set = byModel?.get(modelName)\n if (set) {\n set.delete(queryKey)\n if (!set.size) {\n byModel?.delete(modelName)\n }\n }\n\n if (modelSubs && modelSubs.size === 0) {\n userSubs?.delete(modelName)\n }\n\n if (userSubs && userSubs.size === 0) {\n tenantSubs?.delete(userId)\n }\n\n if (!hasAnySubscriptionsDependingOnModel(tenantId, modelName) && !hasAnyCountSubscriptionsForModel(tenantId, modelName)) {\n const tenantStreams = changeStreams.get(tenantId)\n const stream = tenantStreams?.get(modelName)\n if (stream) {\n try {\n stream.close()\n } catch {\n // ignore\n }\n clearDispatchTimer(tenantId, modelName)\n tenantStreams?.delete(modelName)\n if (tenantStreams && tenantStreams.size === 0) changeStreams.delete(tenantId)\n }\n }\n\n if (tenantSubs && tenantSubs.size === 0) countSubscriptions.delete(tenantId)\n if (byModel && byModel.size === 0) socketCountSubscriptions.delete(socketId)\n}\n\nconst getSocketSubscriptionCount = (socketId: string): number => {\n let count = 0\n const querySubscriptionsByModel = socketSubscriptions.get(socketId)\n if (querySubscriptionsByModel) {\n for (const set of querySubscriptionsByModel.values()) count += set.size\n }\n\n const countSubscriptionsByModel = socketCountSubscriptions.get(socketId)\n if (countSubscriptionsByModel) {\n for (const set of countSubscriptionsByModel.values()) count += set.size\n }\n\n return count\n}\n\nconst cleanupSocket = (socketId: string): void => {\n const meta = socketMeta.get(socketId)\n if (meta) {\n const byModel = socketSubscriptions.get(socketId)\n if (byModel) {\n for (const [modelName, keys] of byModel.entries()) {\n for (const queryKey of keys.values()) {\n removeSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName,\n queryKey,\n })\n }\n }\n }\n\n const countByModel = socketCountSubscriptions.get(socketId)\n if (countByModel) {\n for (const [modelName, keys] of countByModel.entries()) {\n for (const queryKey of keys.values()) {\n removeSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName,\n queryKey,\n })\n }\n }\n }\n }\n\n socketSubscriptions.delete(socketId)\n socketCountSubscriptions.delete(socketId)\n\n const cleanupFns = socketCleanup.get(socketId) ?? []\n socketCleanup.delete(socketId)\n for (const fn of cleanupFns) {\n try {\n fn()\n } catch {\n // ignore\n }\n }\n\n sockets.delete(socketId)\n socketMeta.delete(socketId)\n socketWrappers.delete(socketId)\n}\n\nconst handleClientMessage = async ({\n socketId,\n meta,\n message,\n}: {\n socketId: string\n meta: SocketMeta\n message: ClientMessage\n}): Promise<void> => {\n const ws = sockets.get(socketId)\n if (!ws) return\n if (!await socketValidators.get(ws)?.()) return\n\n if (message.type === \"event\") {\n const wrapper = socketWrappers.get(socketId)\n wrapper?.dispatch(message.event, message.payload)\n return\n }\n\n if (message.type === \"rts-message\") {\n const wrapper = socketWrappers.get(socketId)\n wrapper?.dispatchRtsMessage(message.channel, message.payload)\n return\n }\n\n const isCountMessage =\n message.type === \"run-count\"\n || message.type === \"register-count\"\n || message.type === \"remove-count\"\n const sendAccessError = (error: string) => {\n if (isCountMessage) {\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName ?? \"\", queryKey: message.queryKey ?? \"\", error })\n return\n }\n\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName ?? \"\", queryKey: message.queryKey ?? \"\", error })\n }\n\n if (!message.modelName || typeof message.modelName !== \"string\") return\n if (!allowInternalModels && INTERNAL_MODEL_NAMES.has(message.modelName)) {\n sendAccessError(\"Model not allowed\")\n return\n }\n if (!message.queryKey || typeof message.queryKey !== \"string\") return\n if (message.queryKey.length > QUERY_KEY_MAX_LEN) return\n\n if (message.type === \"remove-query\") {\n removeSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n })\n return\n }\n\n if (message.type === \"remove-count\") {\n removeSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n })\n return\n }\n\n const ability = meta.ability\n\n if (!ability.can(\"read\", message.modelName as AclSubjectType)) {\n sendAccessError(\"forbidden\")\n return\n }\n\n if (message.type === \"set-query-window\") {\n if (!isValidQueryWindowCount(message.requestedCount)) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Invalid requestedCount\",\n })\n return\n }\n\n const subscription = subscriptions\n .get(meta.tenantId)\n ?.get(meta.userId)\n ?.get(message.modelName)\n ?.get(message.queryKey)\n const window = subscription?.windows.get(socketId)\n if (!subscription || !subscription.options.pagination || !window) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Paginated query subscription not found\",\n })\n return\n }\n\n window.requestedCount = message.requestedCount\n await runAndSendSubscriptionQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n subscription,\n })\n return\n }\n\n if (!message.query || typeof message.query !== \"object\") return\n\n if (message.type === \"register-query\" || message.type === \"run-query\") {\n const options = normalizeRtsQueryOptions(message.options)\n if (message.type === \"register-query\") {\n if (options.pagination && !isValidQueryWindowCount(options.pagination.limit)) {\n sendWs(ws, {\n type: \"query-payload\",\n modelName: message.modelName,\n queryKey: message.queryKey,\n error: \"Invalid requestedCount\",\n })\n return\n }\n\n const existing = socketSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false\n if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error: \"Too many subscriptions\" })\n return\n }\n\n let dependencyModelNames: string[] = []\n if (options.populate !== undefined) {\n try {\n dependencyModelNames = await resolveRtsQueryDependencyModelNames({\n tenantId: meta.tenantId,\n ability,\n modelName: message.modelName,\n options,\n allowInternalModels,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n }\n\n if (!sockets.has(socketId)) return\n\n addSocketSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n options,\n dependencyModelNames,\n })\n\n try {\n const modelNamesToWatch = new Set<string>([message.modelName, ...dependencyModelNames])\n for (const modelName of modelNamesToWatch) {\n await ensureChangeStream(meta.tenantId, modelName)\n }\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n\n if (!sockets.has(socketId)) {\n for (const modelName of new Set<string>([message.modelName, ...dependencyModelNames])) {\n closeUnusedChangeStream(meta.tenantId, modelName)\n }\n return\n }\n\n if (message.runInitialQuery === false) {\n return\n }\n\n const subscription = subscriptions\n .get(meta.tenantId)\n ?.get(meta.userId)\n ?.get(message.modelName)\n ?.get(message.queryKey)\n if (!subscription) return\n\n try {\n await runAndSendSubscriptionQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n subscription,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n return\n }\n\n try {\n await runAndSendQuery({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n options,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"query-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n return\n }\n\n if (message.type === \"register-count\" || message.type === \"run-count\") {\n if (message.type === \"register-count\") {\n const existing = socketCountSubscriptions.get(socketId)?.get(message.modelName)?.has(message.queryKey) ?? false\n if (!existing && getSocketSubscriptionCount(socketId) >= maxSubscriptionsPerSocket) {\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error: \"Too many subscriptions\" })\n return\n }\n\n addSocketCountSubscription({\n socketId,\n tenantId: meta.tenantId,\n userId: meta.userId,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n })\n\n try {\n await ensureChangeStream(meta.tenantId, message.modelName)\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n return\n }\n\n if (!sockets.has(socketId)) {\n closeUnusedChangeStream(meta.tenantId, message.modelName)\n return\n }\n\n if (message.runInitialQuery === false) {\n return\n }\n }\n\n try {\n await runAndSendCount({\n tenantId: meta.tenantId,\n targetSocketIds: [socketId],\n ability,\n modelName: message.modelName,\n queryKey: message.queryKey,\n query: message.query,\n })\n } catch (err) {\n const error = redactErrorMessage(err)\n sendWs(ws, { type: \"count-payload\", modelName: message.modelName, queryKey: message.queryKey, error })\n }\n }\n}\n\nexport const initRts = ({\n server,\n path = \"/rts\",\n sessionMiddleware,\n postSyncSessionMiddleware,\n maxPayloadBytes: maxPayloadBytesArg,\n maxSubscriptionsPerSocket: maxSubscriptionsPerSocketArg,\n dispatchDebounceMs: dispatchDebounceMsArg,\n allowInternalModels: allowInternalModelsArg,\n allowedOrigins = (process.env.RB_RTS_ALLOWED_ORIGINS ?? \"\").split(\",\").map((value) => value.trim()).filter(Boolean),\n}: {\n server: HttpServer\n path?: string\n sessionMiddleware: RequestHandler\n postSyncSessionMiddleware?: RequestHandler\n maxPayloadBytes?: number\n maxSubscriptionsPerSocket?: number\n dispatchDebounceMs?: number\n allowInternalModels?: boolean\n allowedOrigins?: string[]\n}): void => {\n if (initializedServers.has(server)) return\n initializedServers.add(server)\n\n if (typeof maxPayloadBytesArg === \"number\" && Number.isFinite(maxPayloadBytesArg) && maxPayloadBytesArg > 0) {\n maxPayloadBytes = Math.floor(maxPayloadBytesArg)\n }\n\n if (\n typeof maxSubscriptionsPerSocketArg === \"number\"\n && Number.isFinite(maxSubscriptionsPerSocketArg)\n && maxSubscriptionsPerSocketArg > 0\n ) {\n maxSubscriptionsPerSocket = Math.floor(maxSubscriptionsPerSocketArg)\n }\n\n if (typeof dispatchDebounceMsArg === \"number\" && Number.isFinite(dispatchDebounceMsArg) && dispatchDebounceMsArg >= 0) {\n dispatchDebounceMs = Math.floor(dispatchDebounceMsArg)\n }\n\n allowInternalModels = Boolean(allowInternalModelsArg)\n\n const wss = new WebSocketServer({ noServer: true, maxPayload: maxPayloadBytes })\n\n server.on(\"upgrade\", (req: IncomingMessage, socket: Socket, head: Buffer) => {\n ensureSocketErrorHandler(socket, () => ({\n upgradeHost: req.headers.host ?? \"\",\n upgradeUrl: req.url ?? \"\",\n userAgent: typeof req.headers[\"user-agent\"] === \"string\" ? req.headers[\"user-agent\"] : \"\",\n }))\n upgradeMeta.delete(req)\n\n let url: URL\n try {\n url = new URL(req.url ?? \"\", `http://${req.headers.host ?? \"localhost\"}`)\n } catch {\n badRequest(socket, \"Invalid URL\")\n return\n }\n\n if (url.pathname !== path) return\n if (!isRtsOriginAllowed(req, allowedOrigins)) {\n socket.end(\"HTTP/1.1 403 Forbidden\\r\\nConnection: close\\r\\n\\r\\n\")\n return\n }\n\n void (async() => {\n try {\n const meta = await parseUpgradeMeta({\n req,\n url,\n sessionMiddleware,\n postSyncSessionMiddleware,\n })\n upgradeMeta.set(req, meta)\n\n wss.handleUpgrade(req, socket, head, (ws: WebSocket) => {\n wss.emit(\"connection\", ws, req)\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : \"RTS upgrade failed\"\n const upgradeReq = req as UpgradeRequest\n const sessionUser = upgradeReq.session?.user\n const sessionUserId = typeof sessionUser?.id === \"string\" ? sessionUser.id.trim() : \"\"\n const sessionTenantId = typeof sessionUser?.currentTenantId === \"string\" ? sessionUser.currentTenantId.trim() : \"\"\n const authenticatedUserIdHeader = req.headers[\"rb-authenticated-user-id\"]\n const authenticatedTenantIdHeader = req.headers[\"rb-authenticated-tenant-id\"]\n console.warn(\"[rb/rts] upgrade rejected\", {\n reason: message,\n host: req.headers.host ?? \"\",\n url: req.url ?? \"\",\n hasSessionUserId: Boolean(sessionUserId),\n hasCurrentTenantId: Boolean(sessionTenantId),\n hasAuthenticatedUserIdHeader: Boolean(Array.isArray(authenticatedUserIdHeader) ? authenticatedUserIdHeader[0] : authenticatedUserIdHeader),\n hasAuthenticatedTenantIdHeader: Boolean(Array.isArray(authenticatedTenantIdHeader) ? authenticatedTenantIdHeader[0] : authenticatedTenantIdHeader),\n userAgent: typeof req.headers[\"user-agent\"] === \"string\" ? req.headers[\"user-agent\"] : \"\",\n })\n if (message === \"Missing current tenant in session\") {\n badRequest(socket, message)\n return\n }\n unauthorized(socket, message)\n return\n }\n })().catch(() => {\n badRequest(socket, \"RTS upgrade failed\")\n })\n })\n\n wss.on(\"connection\", (ws: WebSocket, req: IncomingMessage) => {\n const meta = upgradeMeta.get(req)\n upgradeMeta.delete(req)\n if (!meta) {\n try {\n ws.close()\n } catch {\n // ignore\n }\n return\n }\n\n const socketId = randomUUID()\n sockets.set(socketId, ws)\n socketMeta.set(socketId, meta)\n const validate = async (): Promise<boolean> => {\n if (ws.readyState !== 1) return false\n const valid = await meta.validate()\n if (!valid) ws.close(1008, \"Session expired or permissions changed\")\n return valid\n }\n socketValidators.set(ws, validate)\n\n const wrapper = new RtsSocket({ id: socketId, ws, meta })\n socketWrappers.set(socketId, wrapper)\n\n const validationTimer = setInterval(() => { void validate() }, 30_000)\n validationTimer.unref()\n const cleanupFns: Array<() => void> = [() => clearInterval(validationTimer)]\n for (const handler of customHandlers) {\n try {\n const cleanup = handler(wrapper)\n if (typeof cleanup === \"function\") cleanupFns.push(cleanup)\n } catch {\n // ignore\n }\n }\n if (cleanupFns.length) socketCleanup.set(socketId, cleanupFns)\n\n let messageQueue = Promise.resolve()\n\n ws.on(\"message\", (raw: RawData) => {\n let parsed: unknown\n try {\n parsed = safeJsonParse(raw)\n } catch {\n return\n }\n\n if (!parsed || typeof parsed !== \"object\") return\n const message = parsed as { type?: unknown }\n if (\n message.type !== \"event\"\n && message.type !== \"rts-message\"\n && message.type !== \"run-query\"\n && message.type !== \"register-query\"\n && message.type !== \"set-query-window\"\n && message.type !== \"remove-query\"\n && message.type !== \"run-count\"\n && message.type !== \"register-count\"\n && message.type !== \"remove-count\"\n ) return\n messageQueue = messageQueue\n .then(() => handleClientMessage({ socketId, meta, message: message as ClientMessage }))\n .catch(() => undefined)\n })\n\n ws.on(\"close\", () => {\n cleanupSocket(socketId)\n })\n\n ws.on(\"error\", () => {\n cleanupSocket(socketId)\n })\n })\n}\n\nexport const registerRtsHandler = (handler: HandlerFn): void => {\n customHandlers.push(handler)\n}\n\nexport const publishRtsMessage = ({ tenantId, userId, channel, payload }: PublishRtsMessageInput): void => {\n const normalizedTenantId = tenantId.trim()\n const normalizedUserId = userId?.trim()\n const normalizedChannel = channel.trim()\n if (!normalizedTenantId || !normalizedChannel) return\n\n for (const [socketId, meta] of socketMeta.entries()) {\n if (meta.tenantId !== normalizedTenantId) continue\n if (normalizedUserId && meta.userId !== normalizedUserId) continue\n const ws = sockets.get(socketId)\n if (!ws) continue\n sendWs(ws, { type: \"rts-message\", channel: normalizedChannel, payload })\n }\n}\n\nexport const notifyRtsModelChanged = (tenantId: string, modelName: string): void => {\n scheduleDispatchSubscriptionsForModel(tenantId, modelName)\n}\n\nexport * from \"./routes\"\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"origin.d.ts","sourceRoot":"","sources":["../../src/rts/origin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAKhD,eAAO,MAAM,kBAAkB,GAAI,KAAK,eAAe,EAAE,iBAAgB,MAAM,EAAO,KAAG,OAkBxF,CAAA"}
|
package/dist/sharp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sharp.d.ts","sourceRoot":"","sources":["../src/sharp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC/B,mBAAmB,OAAO,CAAA"}
|
package/dist/sharp.js
ADDED
|
@@ -5,6 +5,7 @@ type SessionUserLike = {
|
|
|
5
5
|
signedInTenants?: unknown;
|
|
6
6
|
tenantRoles?: unknown;
|
|
7
7
|
isEntryGateAuthorized?: unknown;
|
|
8
|
+
authVersion?: unknown;
|
|
8
9
|
};
|
|
9
10
|
type RequestLike = {
|
|
10
11
|
headers?: Record<string, string | string[] | undefined>;
|
|
@@ -12,6 +13,7 @@ type RequestLike = {
|
|
|
12
13
|
user?: SessionUserLike;
|
|
13
14
|
};
|
|
14
15
|
};
|
|
16
|
+
export declare const revalidateAuthenticatedSession: (req: RequestLike) => Promise<void>;
|
|
15
17
|
export declare const syncAuthenticatedSessionFromRequest: (req: RequestLike) => Promise<void>;
|
|
16
18
|
export declare const syncAuthenticatedSessionMiddleware: RequestHandler;
|
|
17
19
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncAuthenticatedSession.d.ts","sourceRoot":"","sources":["../src/syncAuthenticatedSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAQ7C,KAAK,eAAe,GAAG;IACrB,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qBAAqB,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"syncAuthenticatedSession.d.ts","sourceRoot":"","sources":["../src/syncAuthenticatedSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAQ7C,KAAK,eAAe,GAAG;IACrB,EAAE,CAAC,EAAE,OAAO,CAAA;IACZ,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;IACvD,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,eAAe,CAAA;KACvB,CAAA;CACF,CAAA;AA6ED,eAAO,MAAM,8BAA8B,GAAU,KAAK,WAAW,KAAG,OAAO,CAAC,IAAI,CAYnF,CAAA;AAED,eAAO,MAAM,mCAAmC,GAAU,KAAK,WAAW,KAAG,OAAO,CAAC,IAAI,CAexF,CAAA;AAED,eAAO,MAAM,kCAAkC,EAAE,cAIhD,CAAA"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../../../src/uploads/api/files/handlers/getFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"getFile.d.ts","sourceRoot":"","sources":["../../../../../src/uploads/api/files/handlers/getFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAMzC,OAAO,EAML,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAA;AAuElC,eAAO,MAAM,OAAO,EAAE,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,CAwHzF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileContentHeaders.d.ts","sourceRoot":"","sources":["../../src/uploads/fileContentHeaders.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAW/F,CAAA"}
|
package/dist/uploads/worker.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { s as getBucketName } from "../shared-B1VLaHsk.js";
|
|
2
2
|
import { o as registerUploadPostProcessor, s as registerUploadPostProcessorTask } from "../postProcessors-iffHvje4.js";
|
|
3
|
-
import { n as registerConvertHeifToWebpTask } from "../convertHeifToWebp-
|
|
3
|
+
import { n as registerConvertHeifToWebpTask } from "../convertHeifToWebp-CIP6qLY7.js";
|
|
4
4
|
import { GridFSBucket, ObjectId } from "mongodb";
|
|
5
5
|
import { getTenantFilesystemDb } from "@rpcbase/db";
|
|
6
6
|
import sharp from "sharp";
|
package/dist/uploads.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as getUploadProcessors, c as registerUploadProcessor, d as unregisterUploadProcessor, f as uploadPostProcessorTaskName, i as getUploadPostProcessors, l as runUploadPostProcessors, n as clearUploadProcessors, o as registerUploadPostProcessor, r as enqueueUploadPostProcessors, s as registerUploadPostProcessorTask, t as clearUploadPostProcessors, u as unregisterUploadPostProcessor } from "./postProcessors-iffHvje4.js";
|
|
2
2
|
//#region src/uploads/routes.ts
|
|
3
3
|
var routes = Object.entries({ .../* #__PURE__ */ Object.assign({
|
|
4
|
-
"./api/file-uploads/handler.ts": () => import("./handler-
|
|
5
|
-
"./api/files/handler.ts": () => import("./handler-
|
|
4
|
+
"./api/file-uploads/handler.ts": () => import("./handler-BkGfOJ1l.js"),
|
|
5
|
+
"./api/files/handler.ts": () => import("./handler-Dy_L6_-U.js")
|
|
6
6
|
}) }).reduce((acc, [path, mod]) => {
|
|
7
7
|
acc[path.replace("./api/", "@rpcbase/server/uploads/api/")] = mod;
|
|
8
8
|
return acc;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.637.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
15
|
},
|
|
16
|
+
"./sharp": {
|
|
17
|
+
"types": "./dist/sharp.d.ts",
|
|
18
|
+
"import": "./dist/sharp.js",
|
|
19
|
+
"default": "./dist/sharp.js"
|
|
20
|
+
},
|
|
16
21
|
"./email-validation": {
|
|
17
22
|
"types": "./dist/email-validation/index.d.ts",
|
|
18
23
|
"import": "./dist/email-validation/index.js",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handler-C34TFH28.js","names":[],"sources":["../src/uploads/api/files/handlers/deleteFile.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","import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\n\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 escapeHeaderFilename = (filename: string): string => filename.replace(/[\\\\\"]/g, \"_\")\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 const filenameSafe = escapeHeaderFilename(filename)\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}\"` : `W/\"${etagValue}\"`\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-Type\", mimeType)\n ctx.res.setHeader(\"Content-Length\", String((selectedFile as any)?.length ?? 0))\n ctx.res.setHeader(\"Content-Disposition\", `inline; filename=\"${filenameSafe}\"`)\n ctx.res.setHeader(\"Cache-Control\", cacheControl)\n ctx.res.setHeader(\"ETag\", etag)\n ctx.res.setHeader(\"X-Content-Type-Options\", \"nosniff\")\n if (mimeType === \"image/svg+xml\") {\n ctx.res.setHeader(\n \"Content-Security-Policy\",\n \"default-src 'none'; style-src 'unsafe-inline'; sandbox; base-uri 'none'; form-action 'none'\",\n )\n }\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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"}
|