@rpcbase/server 0.537.0 → 0.539.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/email-DK8uUU4X.js +8045 -0
- package/dist/email-DK8uUU4X.js.map +1 -0
- package/dist/handler--FFBJMl6.js +153 -0
- package/dist/handler--FFBJMl6.js.map +1 -0
- package/dist/handler-0rPClEv4.js +663 -0
- package/dist/handler-0rPClEv4.js.map +1 -0
- package/dist/handler-COnCnprN.js +203 -0
- package/dist/handler-COnCnprN.js.map +1 -0
- package/dist/handler-ClQF4MOn.js +931 -0
- package/dist/handler-ClQF4MOn.js.map +1 -0
- package/dist/index.js +4988 -4830
- package/dist/index.js.map +1 -1
- package/dist/notifications.js +199 -134
- package/dist/notifications.js.map +1 -1
- package/dist/queryExecutor-Bol_iR8f.js +453 -0
- package/dist/queryExecutor-Bol_iR8f.js.map +1 -0
- package/dist/render_resend_false-MiC__Smr.js +6 -0
- package/dist/render_resend_false-MiC__Smr.js.map +1 -0
- package/dist/rts/index.d.ts +0 -1
- package/dist/rts/index.d.ts.map +1 -1
- package/dist/rts/index.js +1003 -842
- package/dist/rts/index.js.map +1 -1
- package/dist/schemas-Cjdjgehl.js +4225 -0
- package/dist/schemas-Cjdjgehl.js.map +1 -0
- package/dist/shared-nE84Or5W.js +111 -0
- package/dist/shared-nE84Or5W.js.map +1 -0
- package/dist/ssrMiddleware.d.ts +1 -1
- package/dist/uploads/api/file-uploads/handlers/completeUpload.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/postProcessors.d.ts +2 -0
- package/dist/uploads/api/file-uploads/postProcessors.d.ts.map +1 -1
- package/dist/uploads.js +103 -71
- package/dist/uploads.js.map +1 -1
- package/package.json +11 -10
- package/dist/email-H8nTAGxe.js +0 -12449
- package/dist/email-H8nTAGxe.js.map +0 -1
- package/dist/handler-BBzEodA0.js +0 -182
- package/dist/handler-BBzEodA0.js.map +0 -1
- package/dist/handler-BLwgdQv-.js +0 -544
- package/dist/handler-BLwgdQv-.js.map +0 -1
- package/dist/handler-BU_tEK6x.js +0 -749
- package/dist/handler-BU_tEK6x.js.map +0 -1
- package/dist/handler-CZD5p1Jv.js +0 -28
- package/dist/handler-CZD5p1Jv.js.map +0 -1
- package/dist/handler-Cq6MsoD4.js +0 -124
- package/dist/handler-Cq6MsoD4.js.map +0 -1
- package/dist/queryExecutor-JadZcQSQ.js +0 -318
- package/dist/queryExecutor-JadZcQSQ.js.map +0 -1
- package/dist/render_resend-DQANggpW.js +0 -7
- package/dist/render_resend-DQANggpW.js.map +0 -1
- package/dist/rts/api/cleanup/handler.d.ts +0 -9
- package/dist/rts/api/cleanup/handler.d.ts.map +0 -1
- package/dist/rts/api/cleanup/index.d.ts +0 -11
- package/dist/rts/api/cleanup/index.d.ts.map +0 -1
- package/dist/schemas-BR3K5Luo.js +0 -3824
- package/dist/schemas-BR3K5Luo.js.map +0 -1
- package/dist/shared-DhZ_rDdo.js +0 -87
- package/dist/shared-DhZ_rDdo.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-ClQF4MOn.js","sources":["../src/uploads/api/file-uploads/processors/sanitizeSvg.ts","../src/uploads/api/file-uploads/processors/index.ts","../src/uploads/api/file-uploads/handlers/completeUpload.ts","../src/uploads/api/file-uploads/handlers/getStatus.ts","../src/uploads/api/file-uploads/index.ts","../src/uploads/api/file-uploads/handlers/initUpload.ts","../src/uploads/api/file-uploads/handlers/uploadChunk.ts","../src/uploads/api/file-uploads/middleware/rawBodyParser.ts","../src/uploads/api/file-uploads/handler.ts"],"sourcesContent":["import { JSDOM } from \"jsdom\"\nimport createDOMPurify from \"dompurify\"\n\nimport type { UploadFileProcessor } from \"./index\"\n\n\nconst MAX_SVG_BYTES = 128 * 1024\n\nconst window = new JSDOM(\"\").window\nconst DOMPurify = createDOMPurify(window)\n\nconst normalizeForSniff = (raw: string): string => raw.replace(/^\\uFEFF/, \"\").trimStart()\n\nconst looksLikeSvgText = (text: string): boolean => {\n const normalized = normalizeForSniff(text)\n if (!normalized.startsWith(\"<\")) return false\n return /<svg(?:\\s|>)/i.test(normalized)\n}\n\nexport const looksLikeSvg = (sniff: Buffer): boolean => looksLikeSvgText(sniff.toString(\"utf8\"))\n\nexport const sanitizeSvg = (svg: string): string =>\n DOMPurify.sanitize(svg, {\n USE_PROFILES: { svg: true, svgFilters: true },\n })\n\nexport const sanitizeSvgProcessor: UploadFileProcessor = {\n id: \"sanitize-svg\",\n maxBytes: MAX_SVG_BYTES,\n match: ({ sniff }) => looksLikeSvg(sniff),\n process: (data): { data: Buffer; mimeType: string } => {\n if (data.length > MAX_SVG_BYTES) {\n throw new Error(\"svg_too_large\")\n }\n\n const svgText = data.toString(\"utf8\")\n if (!looksLikeSvgText(svgText)) {\n throw new Error(\"svg_invalid\")\n }\n\n const sanitized = sanitizeSvg(svgText)\n if (!sanitized.trim() || !looksLikeSvgText(sanitized)) {\n throw new Error(\"svg_sanitize_failed\")\n }\n\n const sanitizedBuffer = Buffer.from(sanitized, \"utf8\")\n if (sanitizedBuffer.length > MAX_SVG_BYTES) {\n throw new Error(\"svg_too_large\")\n }\n\n return { data: sanitizedBuffer, mimeType: \"image/svg+xml\" }\n },\n}\n\n","import { sanitizeSvgProcessor } from \"./sanitizeSvg\"\n\n\nexport type UploadFileProcessorContext = {\n filename: string\n clientMimeType: string\n totalSize: number\n sniff: Buffer\n}\n\nexport type UploadFileProcessorResult = {\n data: Buffer\n mimeType?: string\n}\n\nexport type UploadFileProcessor = {\n id: string\n maxBytes: number\n match: (ctx: UploadFileProcessorContext) => boolean\n process: (data: Buffer, ctx: UploadFileProcessorContext) => Promise<UploadFileProcessorResult> | UploadFileProcessorResult\n}\n\nexport const uploadProcessors = Object.freeze([sanitizeSvgProcessor] satisfies UploadFileProcessor[])\n\nexport const getMaxUploadProcessorBytes = (): number =>\n uploadProcessors.reduce((max, processor) => Math.max(max, processor.maxBytes), 0)\n\nexport const selectUploadProcessors = (ctx: UploadFileProcessorContext): UploadFileProcessor[] =>\n uploadProcessors.filter((processor) => processor.match(ctx))\n\nexport const applyUploadProcessors = async (\n data: Buffer,\n ctx: Omit<UploadFileProcessorContext, \"sniff\" | \"totalSize\">,\n): Promise<{ data: Buffer; mimeType: string; applied: string[] }> => {\n let currentData = data\n let currentMimeType = ctx.clientMimeType\n const applied: string[] = []\n\n for (const processor of uploadProcessors) {\n const processorCtx: UploadFileProcessorContext = {\n filename: ctx.filename,\n clientMimeType: currentMimeType,\n totalSize: currentData.length,\n sniff: currentData,\n }\n\n if (!processor.match(processorCtx)) continue\n\n if (currentData.length > processor.maxBytes) {\n throw new Error(\"processor_input_too_large\")\n }\n\n const result = await processor.process(currentData, processorCtx)\n currentData = result.data\n if (typeof result.mimeType === \"string\" && result.mimeType.trim()) {\n currentMimeType = result.mimeType.trim()\n }\n applied.push(processor.id)\n }\n\n return {\n data: currentData,\n mimeType: currentMimeType,\n applied,\n }\n}\n","import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb, models } from \"@rpcbase/db\"\nimport { GridFSBucket } from \"mongodb\"\nimport type { Model } from \"mongoose\"\n\nimport * as Uploads from \"../index\"\nimport { enqueueUploadPostProcessors } from \"../postProcessors\"\nimport { applyUploadProcessors, getMaxUploadProcessorBytes, selectUploadProcessors } from \"../processors\"\nimport {\n type SessionUser,\n type UploadChunkDoc,\n type UploadSessionDoc,\n buildUploadsAbility,\n ensureUploadIndexes,\n getBucketName,\n getModelCtx,\n getUploadSessionAccessQuery,\n getTenantId,\n} from \"../shared\"\n\n\nconst waitForStreamFinished = async (stream: NodeJS.WritableStream): Promise<void> => new Promise((resolve, reject) => {\n stream.once(\"finish\", resolve)\n stream.once(\"error\", reject)\n})\n\nconst writeToStream = async (stream: NodeJS.WritableStream, chunk: Buffer): Promise<void> => {\n const ok = stream.write(chunk)\n if (ok) return\n await new Promise<void>((resolve, reject) => {\n const onDrain = () => {\n cleanup()\n resolve()\n }\n\n const onError = (error: unknown) => {\n cleanup()\n reject(error)\n }\n\n const cleanup = () => {\n stream.off(\"drain\", onDrain)\n stream.off(\"error\", onError)\n }\n\n stream.on(\"drain\", onDrain)\n stream.on(\"error\", onError)\n })\n}\n\nconst abortUploadStream = async (stream: unknown): Promise<void> => {\n if (!stream) return\n if (typeof (stream as { abort?: unknown }).abort === \"function\") {\n try {\n await (stream as { abort: () => Promise<void> | void }).abort()\n return\n } catch {\n //\n }\n }\n try {\n ;(stream as { destroy?: () => void }).destroy?.()\n } catch {\n //\n }\n}\n\nexport const completeUpload: ApiHandler<Record<string, never>, Uploads.CompleteResponsePayload, SessionUser> = async (\n _payload,\n ctx,\n): Promise<Uploads.CompleteResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const uploadId = String(ctx.req.params?.uploadId ?? \"\").trim()\n if (!uploadId) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_upload_id\" }\n }\n\n const ability = buildUploadsAbility(ctx, tenantId)\n const modelCtx = getModelCtx(ctx, tenantId, ability)\n\n const [UploadSession, UploadChunk] = await Promise.all([\n models.get(\"RBUploadSession\", modelCtx) as Promise<Model<UploadSessionDoc>>,\n models.get(\"RBUploadChunk\", modelCtx) as Promise<Model<UploadChunkDoc>>,\n ])\n\n if (!ability.can(\"update\", \"RBUploadSession\")) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n const existing = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"read\")] }).lean()\n if (!existing) {\n ctx.res.status(404)\n return { ok: false, error: \"not_found\" }\n }\n\n if (existing.status === \"done\" && existing.fileId) {\n return { ok: true, fileId: existing.fileId }\n }\n\n const locked = await UploadSession.findOneAndUpdate(\n { $and: [{ _id: uploadId }, { status: \"uploading\" }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"assembling\" }, $unset: { error: \"\" } },\n { returnDocument: \"after\" },\n ).lean()\n\n if (!locked) {\n ctx.res.status(409)\n return { ok: false, error: \"not_uploading\" }\n }\n\n await ensureUploadIndexes(UploadSession, UploadChunk)\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) {\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"error\", error: \"filesystem_db_unavailable\" } },\n )\n ctx.res.status(500)\n return { ok: false, error: \"assembly_failed\" }\n }\n const bucketName = getBucketName()\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n\n const lockedUserId = typeof locked.userId === \"string\" ? locked.userId : undefined\n const maxProcessorBytes = getMaxUploadProcessorBytes()\n const shouldBufferForProcessing = locked.totalSize <= maxProcessorBytes\n const declaredMimeType = locked.mimeType.trim().toLowerCase()\n const declaredSvg = declaredMimeType === \"image/svg+xml\" || locked.filename.trim().toLowerCase().endsWith(\".svg\")\n\n let uploadStream: NodeJS.WritableStream | null = null\n let finalMimeType = locked.mimeType\n let inlineProcessors: string[] = []\n let finalMetadata: Record<string, unknown> = {\n uploadId,\n tenantId,\n mimeType: locked.mimeType,\n totalSize: locked.totalSize,\n ...(typeof locked.isPublic === \"boolean\" ? { isPublic: locked.isPublic } : {}),\n ...(typeof locked.ownerKeyHash === \"string\" ? { ownerKeyHash: locked.ownerKeyHash } : {}),\n ...(lockedUserId ? { userId: lockedUserId } : {}),\n }\n\n try {\n if (!shouldBufferForProcessing && declaredSvg) {\n throw new Error(\"svg_too_large\")\n }\n\n const cursor = UploadChunk.find({ uploadId }).sort({ index: 1 }).cursor() as unknown as AsyncIterable<UploadChunkDoc> & {\n close: () => Promise<void>\n }\n\n let expectedIndex = 0\n const chunks: Buffer[] = []\n let bufferedBytes = 0\n\n const pendingChunks: Buffer[] = []\n const sniffParts: Buffer[] = []\n let sniffBytes = 0\n\n try {\n for await (const chunkDoc of cursor) {\n if (chunkDoc.index !== expectedIndex) {\n throw new Error(\"missing_chunks\")\n }\n\n const chunk = chunkDoc.data\n\n if (shouldBufferForProcessing) {\n chunks.push(chunk)\n bufferedBytes += chunk.length\n } else if (!uploadStream) {\n pendingChunks.push(chunk)\n\n if (sniffBytes < maxProcessorBytes) {\n const slice = chunk.subarray(0, Math.min(chunk.length, maxProcessorBytes - sniffBytes))\n if (slice.length) {\n sniffParts.push(slice)\n sniffBytes += slice.length\n }\n }\n\n if (sniffBytes >= maxProcessorBytes) {\n const sniff = Buffer.concat(sniffParts, sniffBytes)\n const processors = selectUploadProcessors({\n filename: locked.filename,\n clientMimeType: locked.mimeType,\n totalSize: locked.totalSize,\n sniff,\n })\n\n if (processors.length) {\n throw new Error(\"svg_too_large\")\n }\n\n finalMetadata = {\n uploadId,\n tenantId,\n mimeType: locked.mimeType,\n totalSize: locked.totalSize,\n ...(typeof locked.isPublic === \"boolean\" ? { isPublic: locked.isPublic } : {}),\n ...(typeof locked.ownerKeyHash === \"string\" ? { ownerKeyHash: locked.ownerKeyHash } : {}),\n ...(lockedUserId ? { userId: lockedUserId } : {}),\n }\n uploadStream = bucket.openUploadStream(locked.filename, {\n metadata: finalMetadata,\n })\n\n for (const pending of pendingChunks) {\n await writeToStream(uploadStream, pending)\n }\n pendingChunks.length = 0\n }\n } else {\n await writeToStream(uploadStream, chunk)\n }\n\n expectedIndex += 1\n }\n } finally {\n try {\n await cursor.close()\n } catch {\n //\n }\n }\n\n if (expectedIndex !== locked.chunksTotal) {\n throw new Error(\"missing_chunks\")\n }\n\n if (shouldBufferForProcessing) {\n const assembled = Buffer.concat(chunks, bufferedBytes)\n const { data: processed, mimeType: processedMimeType, applied } = await applyUploadProcessors(assembled, {\n filename: locked.filename,\n clientMimeType: locked.mimeType,\n })\n\n finalMimeType = processedMimeType\n inlineProcessors = applied\n finalMetadata = {\n uploadId,\n tenantId,\n mimeType: processedMimeType,\n totalSize: locked.totalSize,\n ...(applied.length ? { processors: applied, processedSize: processed.length } : {}),\n ...(typeof locked.isPublic === \"boolean\" ? { isPublic: locked.isPublic } : {}),\n ...(typeof locked.ownerKeyHash === \"string\" ? { ownerKeyHash: locked.ownerKeyHash } : {}),\n ...(lockedUserId ? { userId: lockedUserId } : {}),\n }\n uploadStream = bucket.openUploadStream(locked.filename, {\n metadata: finalMetadata,\n })\n\n const finished = waitForStreamFinished(uploadStream)\n uploadStream.end(processed)\n await finished\n } else {\n if (!uploadStream) {\n const sniff = Buffer.concat(sniffParts, sniffBytes)\n const processors = selectUploadProcessors({\n filename: locked.filename,\n clientMimeType: locked.mimeType,\n totalSize: locked.totalSize,\n sniff,\n })\n\n if (processors.length) {\n throw new Error(\"svg_too_large\")\n }\n\n finalMetadata = {\n uploadId,\n tenantId,\n mimeType: locked.mimeType,\n totalSize: locked.totalSize,\n ...(typeof locked.isPublic === \"boolean\" ? { isPublic: locked.isPublic } : {}),\n ...(typeof locked.ownerKeyHash === \"string\" ? { ownerKeyHash: locked.ownerKeyHash } : {}),\n ...(lockedUserId ? { userId: lockedUserId } : {}),\n }\n uploadStream = bucket.openUploadStream(locked.filename, {\n metadata: finalMetadata,\n })\n\n for (const pending of pendingChunks) {\n await writeToStream(uploadStream, pending)\n }\n pendingChunks.length = 0\n }\n\n const finished = waitForStreamFinished(uploadStream)\n uploadStream.end()\n await finished\n }\n\n const fileId = String((uploadStream as unknown as { id?: unknown }).id ?? \"\")\n if (!fileId) {\n throw new Error(\"missing_file_id\")\n }\n\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"done\", fileId }, $unset: { error: \"\" } },\n )\n\n await enqueueUploadPostProcessors({\n tenantId,\n uploadId,\n fileId,\n filename: locked.filename,\n mimeType: finalMimeType,\n clientMimeType: locked.mimeType,\n totalSize: locked.totalSize,\n ...(typeof locked.isPublic === \"boolean\" ? { isPublic: locked.isPublic } : {}),\n ...(typeof locked.ownerKeyHash === \"string\" ? { ownerKeyHash: locked.ownerKeyHash } : {}),\n ...(lockedUserId ? { userId: lockedUserId } : {}),\n inlineProcessors,\n metadata: finalMetadata,\n }).catch((error) => {\n console.error(\"Upload post processor enqueue failed\", {\n tenantId,\n uploadId,\n fileId,\n error,\n })\n })\n\n try {\n await UploadChunk.deleteMany({ uploadId })\n } catch {\n //\n }\n\n return { ok: true, fileId }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n await abortUploadStream(uploadStream)\n\n if (message === \"missing_chunks\") {\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"uploading\" } },\n )\n ctx.res.status(409)\n return { ok: false, error: \"missing_chunks\" }\n }\n\n if (message === \"svg_too_large\") {\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"error\", error: message } },\n )\n ctx.res.status(413)\n return { ok: false, error: message }\n }\n\n if (message === \"svg_invalid\" || message === \"svg_sanitize_failed\") {\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"error\", error: message } },\n )\n ctx.res.status(400)\n return { ok: false, error: message }\n }\n\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"error\", error: message } },\n )\n\n ctx.res.status(500)\n return { ok: false, error: \"assembly_failed\" }\n }\n}\n","import { ApiHandler } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport type { Model } from \"mongoose\"\n\nimport * as Uploads from \"../index\"\nimport {\n type SessionUser,\n type UploadChunkDoc,\n type UploadSessionDoc,\n buildUploadsAbility,\n getModelCtx,\n getUploadSessionAccessQuery,\n getTenantId,\n} from \"../shared\"\n\n\nexport const getStatus: ApiHandler<Record<string, never>, Uploads.StatusResponsePayload, SessionUser> = async (\n _payload,\n ctx,\n): Promise<Uploads.StatusResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const uploadId = String(ctx.req.params?.uploadId ?? \"\").trim()\n if (!uploadId) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_upload_id\" }\n }\n\n const ability = buildUploadsAbility(ctx, tenantId)\n const modelCtx = getModelCtx(ctx, tenantId, ability)\n\n const [UploadSession, UploadChunk] = await Promise.all([\n models.get(\"RBUploadSession\", modelCtx) as Promise<Model<UploadSessionDoc>>,\n models.get(\"RBUploadChunk\", modelCtx) as Promise<Model<UploadChunkDoc>>,\n ])\n\n if (!ability.can(\"read\", \"RBUploadSession\")) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n const session = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"read\")] }).lean()\n if (!session) {\n ctx.res.status(404)\n return { ok: false, error: \"not_found\" }\n }\n\n const receivedDocs = await UploadChunk.find(\n { uploadId },\n { index: 1, _id: 0 },\n ).sort({ index: 1 }).lean()\n\n const received = (receivedDocs as unknown as Array<{ index?: unknown }>)\n .map((doc) => (typeof doc.index === \"number\" ? doc.index : -1))\n .filter((n) => Number.isInteger(n) && n >= 0)\n\n return {\n ok: true,\n status: session.status,\n chunkSize: session.chunkSize,\n chunksTotal: session.chunksTotal,\n received,\n ...(session.fileId ? { fileId: session.fileId } : {}),\n }\n}\n","import { z } from \"zod\"\n\n\nexport const InitRoute = \"/api/rb/file-uploads\"\nexport const ChunkRoute = \"/api/rb/file-uploads/:uploadId/chunks/:index\"\nexport const StatusRoute = \"/api/rb/file-uploads/:uploadId/status\"\nexport const CompleteRoute = \"/api/rb/file-uploads/:uploadId/complete\"\n\nexport const initRequestSchema = z.object({\n filename: z.string().min(1),\n mimeType: z.string().min(1),\n isPublic: z.boolean().optional(),\n totalSize: z.number().int().min(1),\n})\n\nexport type InitRequestPayload = z.infer<typeof initRequestSchema>\n\nexport const initResponseSchema = z.object({\n ok: z.boolean(),\n error: z.string().optional(),\n uploadId: z.string().optional(),\n uploadKey: z.string().optional(),\n chunkSize: z.number().int().optional(),\n chunksTotal: z.number().int().optional(),\n})\n\nexport type InitResponsePayload = z.infer<typeof initResponseSchema>\n\nexport const statusResponseSchema = z.object({\n ok: z.boolean(),\n error: z.string().optional(),\n status: z.enum([\"uploading\", \"assembling\", \"done\", \"error\"]).optional(),\n chunkSize: z.number().int().optional(),\n chunksTotal: z.number().int().optional(),\n received: z.array(z.number().int().min(0)).optional(),\n fileId: z.string().optional(),\n})\n\nexport type StatusResponsePayload = z.infer<typeof statusResponseSchema>\n\nexport const completeResponseSchema = z.object({\n ok: z.boolean(),\n error: z.string().optional(),\n fileId: z.string().optional(),\n})\n\nexport type CompleteResponsePayload = z.infer<typeof completeResponseSchema>\n","import { randomBytes } from \"node:crypto\"\n\nimport { ApiHandler } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport { ObjectId } from \"mongodb\"\nimport type { Model } from \"mongoose\"\n\nimport * as Uploads from \"../index\"\nimport {\n type SessionUser,\n type UploadChunkDoc,\n type UploadSessionDoc,\n buildUploadsAbility,\n computeSha256Hex,\n ensureUploadIndexes,\n getChunkSizeBytes,\n getModelCtx,\n getSessionTtlMs,\n getTenantId,\n getUserId,\n} from \"../shared\"\n\n\nexport const initUpload: ApiHandler<Uploads.InitRequestPayload, Uploads.InitResponsePayload, SessionUser> = async (\n payload,\n ctx,\n): Promise<Uploads.InitResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const userId = getUserId(ctx)\n\n const parsed = Uploads.initRequestSchema.safeParse(payload ?? {})\n if (!parsed.success) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_payload\" }\n }\n\n const chunkSize = getChunkSizeBytes()\n const { filename, mimeType, totalSize, isPublic } = parsed.data\n const chunksTotal = Math.ceil(totalSize / chunkSize)\n\n const ability = buildUploadsAbility(ctx, tenantId)\n const modelCtx = getModelCtx(ctx, tenantId, ability)\n\n const [UploadSession, UploadChunk] = await Promise.all([\n models.get(\"RBUploadSession\", modelCtx) as Promise<Model<UploadSessionDoc>>,\n models.get(\"RBUploadChunk\", modelCtx) as Promise<Model<UploadChunkDoc>>,\n ])\n\n await ensureUploadIndexes(UploadSession, UploadChunk)\n\n const uploadId = new ObjectId().toString()\n const now = Date.now()\n const expiresAt = new Date(now + getSessionTtlMs())\n\n const uploadKey = userId ? null : randomBytes(32).toString(\"base64url\")\n const ownerKeyHash = uploadKey ? computeSha256Hex(Buffer.from(uploadKey)) : undefined\n\n await UploadSession.create({\n _id: uploadId,\n ...(userId ? { userId } : {}),\n ...(ownerKeyHash ? { ownerKeyHash } : {}),\n filename,\n mimeType,\n ...(typeof isPublic === \"boolean\" ? { isPublic } : {}),\n totalSize,\n chunkSize,\n chunksTotal,\n status: \"uploading\",\n createdAt: new Date(now),\n expiresAt,\n })\n\n return {\n ok: true,\n uploadId,\n chunkSize,\n chunksTotal,\n ...(uploadKey ? { uploadKey } : {}),\n }\n}\n","import { ApiHandler } from \"@rpcbase/api\"\nimport { models } from \"@rpcbase/db\"\nimport type { Model } from \"mongoose\"\n\nimport {\n type SessionUser,\n type UploadChunkDoc,\n type UploadSessionDoc,\n buildUploadsAbility,\n computeSha256Hex,\n ensureUploadIndexes,\n getModelCtx,\n getUploadSessionAccessQuery,\n getTenantId,\n normalizeSha256Hex,\n toBufferPayload,\n} from \"../shared\"\n\n\ntype ChunkResponsePayload = {\n ok: boolean\n error?: string\n}\n\nexport const uploadChunk: ApiHandler<Buffer, ChunkResponsePayload, SessionUser> = async (\n payload,\n ctx,\n): Promise<ChunkResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const uploadId = String(ctx.req.params?.uploadId ?? \"\").trim()\n const indexRaw = String(ctx.req.params?.index ?? \"\").trim()\n const index = Number(indexRaw)\n\n if (!uploadId || !Number.isInteger(index) || index < 0) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_chunk_ref\" }\n }\n\n const ability = buildUploadsAbility(ctx, tenantId)\n const modelCtx = getModelCtx(ctx, tenantId, ability)\n\n const [UploadSession, UploadChunk] = await Promise.all([\n models.get(\"RBUploadSession\", modelCtx) as Promise<Model<UploadSessionDoc>>,\n models.get(\"RBUploadChunk\", modelCtx) as Promise<Model<UploadChunkDoc>>,\n ])\n\n if (!ability.can(\"update\", \"RBUploadSession\")) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n const session = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] }).lean()\n if (!session) {\n ctx.res.status(404)\n return { ok: false, error: \"not_found\" }\n }\n\n if (session.status !== \"uploading\") {\n ctx.res.status(409)\n return { ok: false, error: \"not_uploading\" }\n }\n\n if (index >= session.chunksTotal) {\n ctx.res.status(400)\n return { ok: false, error: \"index_out_of_range\" }\n }\n\n const data = toBufferPayload(payload)\n if (!data) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_body\" }\n }\n\n const expectedSize = index === session.chunksTotal - 1\n ? session.totalSize - session.chunkSize * (session.chunksTotal - 1)\n : session.chunkSize\n\n if (data.length > expectedSize) {\n ctx.res.status(413)\n return { ok: false, error: \"chunk_too_large\" }\n }\n\n if (data.length !== expectedSize) {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_chunk_size\" }\n }\n\n const checksumHeader = ctx.req.get(\"X-Chunk-SHA256\")\n const sha256 = checksumHeader ? computeSha256Hex(data) : undefined\n\n if (checksumHeader) {\n const expectedSha256 = normalizeSha256Hex(checksumHeader)\n if (sha256 !== expectedSha256) {\n ctx.res.status(400)\n return { ok: false, error: \"checksum_mismatch\" }\n }\n }\n\n await ensureUploadIndexes(UploadSession, UploadChunk)\n\n await UploadChunk.updateOne(\n { uploadId, index },\n {\n $set: {\n uploadId,\n index,\n data,\n size: data.length,\n sha256,\n expiresAt: session.expiresAt,\n },\n $setOnInsert: {\n createdAt: new Date(),\n },\n },\n { upsert: true },\n )\n\n ctx.res.status(204)\n return { ok: true }\n}\n","export const rawBodyParser = ({\n limitBytes,\n maxClientBytesPerSecond,\n}: {\n limitBytes: number\n maxClientBytesPerSecond?: number | null\n}) => {\n return (req: any, res: any, next: any) => {\n const contentType = typeof req?.headers?.[\"content-type\"] === \"string\"\n ? String(req.headers[\"content-type\"])\n : \"\"\n\n if (!contentType.includes(\"application/octet-stream\")) {\n next()\n return\n }\n\n let total = 0\n const chunks: Buffer[] = []\n let done = false\n let paused = false\n let throttleTimeout: ReturnType<typeof setTimeout> | null = null\n\n const rateBytesPerSecond = typeof maxClientBytesPerSecond === \"number\" && maxClientBytesPerSecond > 0\n ? maxClientBytesPerSecond\n : null\n\n const cleanup = () => {\n req.off(\"data\", onData)\n req.off(\"end\", onEnd)\n req.off(\"error\", onError)\n req.off(\"aborted\", onAborted)\n if (throttleTimeout) {\n clearTimeout(throttleTimeout)\n throttleTimeout = null\n }\n }\n\n const finish = (error?: unknown) => {\n if (done) return\n done = true\n\n cleanup()\n\n if (error) {\n next(error)\n return\n }\n\n req.body = Buffer.concat(chunks, total)\n next()\n }\n\n const onData = (chunk: any) => {\n if (done) return\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n total += buffer.length\n\n if (total > limitBytes) {\n done = true\n cleanup()\n req.destroy()\n res.status(413).json({ ok: false, error: \"chunk_too_large\" })\n return\n }\n\n chunks.push(buffer)\n\n if (!rateBytesPerSecond) return\n\n const now = Date.now()\n const clientKey = getClientKey(req)\n const state = getClientRateState(clientKey, rateBytesPerSecond, now)\n const waitMs = consumeRateBudget(state, buffer.length, rateBytesPerSecond, now)\n\n if (waitMs > 0 && !paused) {\n paused = true\n req.pause()\n throttleTimeout = setTimeout(() => {\n throttleTimeout = null\n paused = false\n if (done) return\n try {\n req.resume()\n } catch {\n //\n }\n }, waitMs)\n }\n }\n\n const onEnd = () => finish()\n const onError = (err: unknown) => finish(err)\n const onAborted = () => finish(new Error(\"request_aborted\"))\n\n req.on(\"data\", onData)\n req.on(\"end\", onEnd)\n req.on(\"error\", onError)\n req.on(\"aborted\", onAborted)\n }\n}\n\ntype ClientRateState = {\n tokens: number\n lastRefillMs: number\n lastSeenMs: number\n}\n\nconst MAX_BURST_SECONDS = 1\nconst STALE_CLIENT_MS = 15 * 60 * 1000\n\nconst clientRateStates = new Map<string, ClientRateState>()\nlet lastCleanupMs = 0\n\nconst getClientKey = (req: any): string => {\n const rawClientIp = typeof req?.clientIp === \"string\" ? req.clientIp : \"\"\n if (rawClientIp.trim()) return rawClientIp.trim()\n const rawIp = typeof req?.ip === \"string\" ? req.ip : \"\"\n return rawIp.trim() || \"unknown\"\n}\n\nconst maybeCleanupStates = (now: number) => {\n if (now - lastCleanupMs < 60_000) return\n lastCleanupMs = now\n\n if (clientRateStates.size < 2000) return\n\n for (const [key, state] of clientRateStates) {\n if (now - state.lastSeenMs > STALE_CLIENT_MS) {\n clientRateStates.delete(key)\n }\n }\n}\n\nconst getClientRateState = (key: string, rateBytesPerSecond: number, now: number): ClientRateState => {\n maybeCleanupStates(now)\n\n const capacity = rateBytesPerSecond * MAX_BURST_SECONDS\n const existing = clientRateStates.get(key)\n if (existing) {\n existing.lastSeenMs = now\n existing.tokens = Math.min(capacity, existing.tokens)\n return existing\n }\n\n const next: ClientRateState = {\n tokens: capacity,\n lastRefillMs: now,\n lastSeenMs: now,\n }\n clientRateStates.set(key, next)\n return next\n}\n\nconst consumeRateBudget = (\n state: ClientRateState,\n bytes: number,\n rateBytesPerSecond: number,\n now: number,\n): number => {\n const capacity = rateBytesPerSecond * MAX_BURST_SECONDS\n const elapsedMs = Math.max(0, now - state.lastRefillMs)\n\n if (elapsedMs > 0) {\n state.tokens = Math.min(capacity, state.tokens + (elapsedMs * rateBytesPerSecond) / 1000)\n state.lastRefillMs = now\n }\n\n state.tokens -= bytes\n\n if (state.tokens >= 0) return 0\n return Math.ceil((-state.tokens / rateBytesPerSecond) * 1000)\n}\n","import { Api } from \"@rpcbase/api\"\n\nimport { completeUpload } from \"./handlers/completeUpload\"\nimport { getStatus } from \"./handlers/getStatus\"\nimport { initUpload } from \"./handlers/initUpload\"\nimport { uploadChunk } from \"./handlers/uploadChunk\"\nimport { rawBodyParser } from \"./middleware/rawBodyParser\"\nimport { getChunkSizeBytes, getMaxClientUploadBytesPerSecond, getRawBodyLimitBytes, type SessionUser } from \"./shared\"\n\nimport * as Uploads from \"./index\"\n\n\nexport default (api: Api<SessionUser>) => {\n const chunkSizeBytes = getChunkSizeBytes()\n api.use(\n Uploads.InitRoute,\n rawBodyParser({\n limitBytes: getRawBodyLimitBytes(chunkSizeBytes),\n maxClientBytesPerSecond: getMaxClientUploadBytesPerSecond(),\n }),\n )\n\n api.post(Uploads.InitRoute, initUpload)\n api.put(Uploads.ChunkRoute, uploadChunk)\n api.get(Uploads.StatusRoute, getStatus)\n api.post(Uploads.CompleteRoute, completeUpload)\n}\n"],"names":["MAX_SVG_BYTES","window","JSDOM","DOMPurify","createDOMPurify","normalizeForSniff","raw","replace","trimStart","looksLikeSvgText","text","normalized","startsWith","test","looksLikeSvg","sniff","toString","sanitizeSvg","svg","sanitize","USE_PROFILES","svgFilters","sanitizeSvgProcessor","id","maxBytes","match","process","data","length","Error","svgText","sanitized","trim","sanitizedBuffer","Buffer","from","mimeType","uploadProcessors","Object","freeze","getMaxUploadProcessorBytes","reduce","max","processor","Math","selectUploadProcessors","ctx","filter","applyUploadProcessors","currentData","currentMimeType","clientMimeType","applied","processorCtx","filename","totalSize","result","push","waitForStreamFinished","stream","Promise","resolve","reject","once","writeToStream","chunk","ok","write","onDrain","cleanup","onError","error","off","on","abortUploadStream","abort","destroy","completeUpload","_payload","tenantId","getTenantId","res","status","uploadId","String","req","params","ability","buildUploadsAbility","modelCtx","getModelCtx","UploadSession","UploadChunk","all","models","get","can","existing","findOne","$and","_id","getUploadSessionAccessQuery","lean","fileId","locked","findOneAndUpdate","$set","$unset","returnDocument","ensureUploadIndexes","fsDb","getTenantFilesystemDb","nativeDb","db","updateOne","bucketName","getBucketName","bucket","GridFSBucket","lockedUserId","userId","undefined","maxProcessorBytes","shouldBufferForProcessing","declaredMimeType","toLowerCase","declaredSvg","endsWith","uploadStream","finalMimeType","inlineProcessors","finalMetadata","isPublic","ownerKeyHash","cursor","find","sort","index","expectedIndex","chunks","bufferedBytes","pendingChunks","sniffParts","sniffBytes","chunkDoc","slice","subarray","min","concat","processors","openUploadStream","metadata","pending","close","chunksTotal","assembled","processed","processedMimeType","processedSize","finished","end","enqueueUploadPostProcessors","catch","console","deleteMany","message","getStatus","session","receivedDocs","received","map","doc","n","Number","isInteger","chunkSize","InitRoute","ChunkRoute","StatusRoute","CompleteRoute","initRequestSchema","z","string","boolean","optional","number","int","uploadKey","initUpload","payload","getUserId","parsed","Uploads","safeParse","success","getChunkSizeBytes","ceil","ObjectId","now","Date","expiresAt","getSessionTtlMs","randomBytes","computeSha256Hex","create","createdAt","uploadChunk","indexRaw","toBufferPayload","expectedSize","checksumHeader","sha256","expectedSha256","normalizeSha256Hex","size","$setOnInsert","upsert","rawBodyParser","limitBytes","maxClientBytesPerSecond","next","contentType","headers","includes","total","done","paused","throttleTimeout","rateBytesPerSecond","onData","onEnd","onAborted","clearTimeout","finish","body","buffer","isBuffer","json","clientKey","getClientKey","state","getClientRateState","waitMs","consumeRateBudget","pause","setTimeout","resume","err","MAX_BURST_SECONDS","STALE_CLIENT_MS","clientRateStates","Map","lastCleanupMs","rawClientIp","clientIp","rawIp","ip","maybeCleanupStates","key","lastSeenMs","delete","capacity","tokens","lastRefillMs","set","bytes","elapsedMs","api","chunkSizeBytes","use","getRawBodyLimitBytes","getMaxClientUploadBytesPerSecond","post","put"],"mappings":"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"}
|