@rpcbase/server 0.551.0 → 0.552.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.
@@ -1 +0,0 @@
1
- {"version":3,"file":"handler-Da2KGCRq.js","sources":["../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 { convertHeifToWebpProcessor } from \"./convertHeifToWebp\"\nimport { 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 filename?: string\n mimeType?: string\n metadata?: Record<string, unknown>\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, convertHeifToWebpProcessor] 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; filename: string; mimeType: string; applied: string[]; metadata: Record<string, unknown> }> => {\n let currentData = data\n let currentFilename = ctx.filename\n let currentMimeType = ctx.clientMimeType\n const applied: string[] = []\n const metadata: Record<string, unknown> = {}\n\n for (const processor of uploadProcessors) {\n const processorCtx: UploadFileProcessorContext = {\n filename: currentFilename,\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.filename === \"string\" && result.filename.trim()) {\n currentFilename = result.filename.trim()\n }\n if (typeof result.mimeType === \"string\" && result.mimeType.trim()) {\n currentMimeType = result.mimeType.trim()\n }\n if (result.metadata && typeof result.metadata === \"object\") {\n Object.assign(metadata, result.metadata)\n }\n applied.push(processor.id)\n }\n\n return {\n data: currentData,\n filename: currentFilename,\n mimeType: currentMimeType,\n applied,\n metadata,\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 finalFilename = locked.filename\n let finalMimeType = locked.mimeType\n let finalSize = locked.totalSize\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(processors.some((processor) => processor.id === \"sanitize-svg\") ? \"svg_too_large\" : \"processor_input_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 {\n data: processed,\n filename: processedFilename,\n mimeType: processedMimeType,\n applied,\n metadata: processedMetadata,\n } = await applyUploadProcessors(assembled, {\n filename: locked.filename,\n clientMimeType: locked.mimeType,\n })\n\n finalFilename = processedFilename\n finalMimeType = processedMimeType\n finalSize = processed.length\n inlineProcessors = applied\n finalMetadata = {\n uploadId,\n tenantId,\n mimeType: processedMimeType,\n totalSize: processed.length,\n ...(applied.length ? { processors: applied, sourceTotalSize: locked.totalSize } : {}),\n ...processedMetadata,\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(finalFilename, {\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(processors.some((processor) => processor.id === \"sanitize-svg\") ? \"svg_too_large\" : \"processor_input_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, filename: finalFilename, mimeType: finalMimeType, totalSize: finalSize }, $unset: { error: \"\" } },\n )\n\n await enqueueUploadPostProcessors({\n tenantId,\n uploadId,\n fileId,\n filename: finalFilename,\n mimeType: finalMimeType,\n clientMimeType: locked.mimeType,\n totalSize: finalSize,\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 === \"heif_too_large\" || message === \"processor_input_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.startsWith(\"heif_decode_unsupported\")) {\n await UploadSession.updateOne(\n { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, \"update\")] },\n { $set: { status: \"error\", error: message } },\n )\n ctx.res.status(415)\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":["uploadProcessors","Object","freeze","sanitizeSvgProcessor","convertHeifToWebpProcessor","getMaxUploadProcessorBytes","reduce","max","processor","Math","maxBytes","selectUploadProcessors","ctx","filter","match","applyUploadProcessors","data","currentData","currentFilename","filename","currentMimeType","clientMimeType","applied","metadata","processorCtx","totalSize","length","sniff","Error","result","process","trim","mimeType","assign","push","id","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","finalFilename","finalMimeType","finalSize","inlineProcessors","finalMetadata","isPublic","ownerKeyHash","cursor","find","sort","index","expectedIndex","chunks","bufferedBytes","pendingChunks","sniffParts","sniffBytes","chunkDoc","slice","subarray","min","Buffer","concat","processors","some","openUploadStream","pending","close","chunksTotal","assembled","processed","processedFilename","processedMimeType","processedMetadata","sourceTotalSize","finished","end","enqueueUploadPostProcessors","catch","console","deleteMany","message","startsWith","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","toString","now","Date","expiresAt","getSessionTtlMs","randomBytes","computeSha256Hex","from","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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"}