@rpcbase/server 0.550.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":"uploads-BAxHzidK.js","sources":["../src/uploads/api/file-uploads/processors/convertHeifToWebp.ts","../src/uploads/api/file-uploads/processors/sanitizeSvg.ts","../src/uploads/api/file-uploads/postProcessors.ts","../src/uploads/api/file-uploads/shared.ts","../src/uploads/api/file-uploads/imageVariantsPostProcessor.ts","../src/uploads/routes.ts"],"sourcesContent":["import { queue, type Job } from \"@rpcbase/worker\"\nimport sharp from \"sharp\"\n\nimport type { UploadFileProcessor, UploadFileProcessorContext } from \"./index\"\n\n\nconst MAX_HEIF_BYTES = 25 * 1024 * 1024\nconst MAX_HEIF_INPUT_PIXELS = 64 * 1024 * 1024\nconst WEBP_QUALITY = 82\nconst CONVERSION_TIMEOUT_MS = 60_000\nconst POLL_INTERVAL_MS = 250\nconst HEIF_DECODE_UNSUPPORTED = \"heif_decode_unsupported\"\n\nconst heifMimeTypes = new Set([\n \"image/heic\",\n \"image/heif\",\n \"image/heic-sequence\",\n \"image/heif-sequence\",\n])\n\nconst heifExtensions = /\\.(?:heic|heif|heics|heifs)$/i\nconst hevcBrands = new Set([\"heic\", \"heix\", \"hevc\", \"hevx\", \"heim\", \"heis\", \"hevm\", \"hevs\"])\n\nexport const convertHeifToWebpTaskName = \"rb-upload-convert-heif-to-webp\"\n\nexport type ConvertHeifToWebpTaskPayload = {\n filename: string\n mimeType: string\n inputBase64: string\n}\n\nexport type ConvertHeifToWebpTaskResult = {\n dataBase64: string\n filename: string\n mimeType: \"image/webp\"\n metadata: {\n width?: number\n height?: number\n sourceFilename: string\n sourceMimeType: string\n }\n}\n\ndeclare module \"@rpcbase/worker\" {\n interface WorkerTasksMap {\n \"rb-upload-convert-heif-to-webp\": ConvertHeifToWebpTaskPayload\n }\n}\n\nconst delay = async (ms: number): Promise<void> => {\n await new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nconst normalizeMimeType = (value: string): string => value.trim().toLowerCase()\n\nconst getFtypBrands = (sniff: Buffer): string[] => {\n if (sniff.length < 12) return []\n\n const ftypOffset = sniff.indexOf(Buffer.from(\"ftyp\"))\n if (ftypOffset < 4 || ftypOffset > 32) return []\n\n const brands: string[] = []\n for (let offset = ftypOffset + 4; offset + 4 <= Math.min(sniff.length, ftypOffset + 80); offset += 4) {\n const brand = sniff.subarray(offset, offset + 4).toString(\"ascii\")\n if (/^[a-zA-Z0-9 ]{4}$/.test(brand)) {\n brands.push(brand.trim())\n }\n }\n\n return brands.filter(Boolean)\n}\n\nexport const hasHeifDeclaration = ({ filename, clientMimeType }: Pick<UploadFileProcessorContext, \"filename\" | \"clientMimeType\">): boolean =>\n heifMimeTypes.has(normalizeMimeType(clientMimeType)) || heifExtensions.test(filename)\n\nexport const looksLikeHevcHeif = (sniff: Buffer): boolean => getFtypBrands(sniff).some((brand) => hevcBrands.has(brand))\n\nexport const isHeifUpload = ({ filename, clientMimeType, sniff }: UploadFileProcessorContext): boolean =>\n hasHeifDeclaration({ filename, clientMimeType }) || looksLikeHevcHeif(sniff)\n\nexport const toWebpFilename = (filename: string): string => {\n const trimmed = filename.trim()\n if (!trimmed) return \"image.webp\"\n if (heifExtensions.test(trimmed)) return trimmed.replace(heifExtensions, \".webp\")\n return `${trimmed}.webp`\n}\n\nconst isHeifDecodeUnsupportedError = (error: unknown): boolean => {\n const message = error instanceof Error ? error.message : String(error ?? \"unknown\")\n const normalized = message.toLowerCase()\n return (\n message.startsWith(HEIF_DECODE_UNSUPPORTED) ||\n normalized.includes(\"support for this compression format has not been built in\") ||\n normalized.includes(\"heif: error while loading plugin\") ||\n normalized.includes(\"unsupported feature: unsupported codec\") ||\n normalized.includes(\"no decoding plugin installed\")\n )\n}\n\nexport const getSharpHeifSupportDiagnostic = (): string => {\n const suffixes = sharp.format.heif.input.fileSuffix ?? []\n const advertisedSuffixes = suffixes.length ? suffixes.join(\", \") : \"none\"\n const sharpVersion = sharp.versions.sharp ?? \"unknown\"\n const vipsVersion = sharp.versions.vips ?? \"unknown\"\n const heifVersion = sharp.versions.heif ?? \"not reported\"\n\n return `Sharp ${sharpVersion} / libvips ${vipsVersion} / libheif ${heifVersion} advertises HEIF input suffixes: ${advertisedSuffixes}. iPhone HEIC/HEVC requires a libvips build with libheif, libde265 and x265/HEVC support. Install a compatible global libvips and reinstall sharp so it links against it.`\n}\n\nconst createHeifDecodeUnsupportedError = (): Error => new Error(`${HEIF_DECODE_UNSUPPORTED}: ${getSharpHeifSupportDiagnostic()}`)\n\nconst normalizeConversionError = (error: unknown): Error => {\n const message = error instanceof Error ? error.message : String(error ?? \"unknown\")\n if (message === \"heif_too_large\") {\n return new Error(message)\n }\n if (message.startsWith(HEIF_DECODE_UNSUPPORTED)) {\n return new Error(message)\n }\n if (isHeifDecodeUnsupportedError(error)) {\n return createHeifDecodeUnsupportedError()\n }\n return new Error(\"heif_conversion_failed\")\n}\n\nexport const convertHeifToWebp = async (\n input: Buffer,\n payload: Pick<ConvertHeifToWebpTaskPayload, \"filename\" | \"mimeType\">,\n): Promise<ConvertHeifToWebpTaskResult> => {\n try {\n const output = await sharp(input, { limitInputPixels: MAX_HEIF_INPUT_PIXELS })\n .rotate()\n .webp({ quality: WEBP_QUALITY, effort: 4 })\n .toBuffer({ resolveWithObject: true })\n\n return {\n dataBase64: output.data.toString(\"base64\"),\n filename: toWebpFilename(payload.filename),\n mimeType: \"image/webp\",\n metadata: {\n sourceFilename: payload.filename,\n sourceMimeType: payload.mimeType,\n ...(typeof output.info.width === \"number\" ? { width: output.info.width } : {}),\n ...(typeof output.info.height === \"number\" ? { height: output.info.height } : {}),\n },\n }\n } catch (error) {\n throw normalizeConversionError(error)\n }\n}\n\nconst convertHeifToWebpTask = async (payload: ConvertHeifToWebpTaskPayload, job: Job): Promise<ConvertHeifToWebpTaskResult> => {\n const input = Buffer.from(payload.inputBase64, \"base64\")\n await job.log(`convert ${payload.filename} (${input.length} bytes) to webp`)\n return convertHeifToWebp(input, payload)\n}\n\nqueue.registerTask(convertHeifToWebpTaskName, convertHeifToWebpTask)\n\nconst waitForConversionResult = async (job: Job): Promise<ConvertHeifToWebpTaskResult> => {\n const startedAt = Date.now()\n\n while (Date.now() - startedAt < CONVERSION_TIMEOUT_MS) {\n const currentJob = job.id ? await queue.getJob(String(job.id)) : job\n if (!currentJob) {\n throw new Error(\"heif_conversion_failed\")\n }\n\n const state = await currentJob.getState()\n if (state === \"completed\") {\n return currentJob.returnvalue as ConvertHeifToWebpTaskResult\n }\n if (state === \"failed\") {\n throw new Error(currentJob.failedReason || \"heif_conversion_failed\")\n }\n await delay(POLL_INTERVAL_MS)\n }\n\n throw new Error(\"heif_conversion_timeout\")\n}\n\nconst runConversionTask = async (\n input: Buffer,\n payload: Pick<ConvertHeifToWebpTaskPayload, \"filename\" | \"mimeType\">,\n): Promise<ConvertHeifToWebpTaskResult> => {\n const job = await queue.add(\n convertHeifToWebpTaskName,\n {\n ...payload,\n inputBase64: input.toString(\"base64\"),\n },\n {\n attempts: 1,\n removeOnComplete: 128,\n removeOnFail: 128,\n },\n )\n\n return waitForConversionResult(job)\n}\n\nexport const convertHeifToWebpProcessor: UploadFileProcessor = {\n id: \"convert-heif-to-webp\",\n maxBytes: MAX_HEIF_BYTES,\n match: isHeifUpload,\n process: async (data, ctx) => {\n if (data.length > MAX_HEIF_BYTES) {\n throw new Error(\"heif_too_large\")\n }\n\n const result = await runConversionTask(data, {\n filename: ctx.filename,\n mimeType: ctx.clientMimeType,\n })\n\n return {\n data: Buffer.from(result.dataBase64, \"base64\"),\n filename: result.filename,\n mimeType: result.mimeType,\n metadata: result.metadata,\n }\n },\n}\n","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 { queue } from \"@rpcbase/worker\"\n\n\nexport type UploadPostProcessorContext = {\n tenantId: string\n uploadId: string\n fileId: string\n filename: string\n mimeType: string\n clientMimeType: string\n totalSize: number\n isPublic?: boolean\n userId?: string\n ownerKeyHash?: string\n inlineProcessors: string[]\n metadata: Record<string, unknown>\n}\n\nexport type UploadPostProcessor = {\n id: string\n version?: number\n match?: (ctx: UploadPostProcessorContext) => boolean\n process: (ctx: UploadPostProcessorContext) => Promise<unknown> | unknown\n}\n\nconst processorsById: Record<string, UploadPostProcessor> = Object.create(null)\nexport const uploadPostProcessorTaskName = \"rb-upload-post-processors\"\n\nconst normalizeProcessorId = (value: unknown): string => (typeof value === \"string\" ? value.trim() : \"\")\n\nconst normalizeProcessorVersion = (value: unknown): number | undefined => {\n if (typeof value !== \"number\") return undefined\n if (!Number.isInteger(value) || value < 1) return undefined\n return value\n}\n\nexport const registerUploadPostProcessor = (processor: UploadPostProcessor): void => {\n const normalizedId = normalizeProcessorId(processor.id)\n if (!normalizedId) {\n throw new Error(\"Upload post processor id is required.\")\n }\n\n const normalizedVersion = normalizeProcessorVersion(processor.version)\n\n processorsById[normalizedId] = {\n ...processor,\n id: normalizedId,\n ...(normalizedVersion ? { version: normalizedVersion } : {}),\n }\n}\n\nexport const registerUploadProcessor = registerUploadPostProcessor\n\nexport const unregisterUploadPostProcessor = (id: string): void => {\n const normalizedId = normalizeProcessorId(id)\n if (!normalizedId) return\n delete processorsById[normalizedId]\n}\n\nexport const unregisterUploadProcessor = unregisterUploadPostProcessor\n\nexport const clearUploadPostProcessors = (): void => {\n for (const id of Object.keys(processorsById)) {\n delete processorsById[id]\n }\n}\n\nexport const clearUploadProcessors = clearUploadPostProcessors\n\nexport const getUploadPostProcessors = (): UploadPostProcessor[] => Object.values(processorsById)\n\nexport const getUploadProcessors = getUploadPostProcessors\n\nexport const runUploadPostProcessors = async (ctx: UploadPostProcessorContext): Promise<void> => {\n const processors = getUploadPostProcessors()\n if (!processors.length) return\n\n for (const processor of processors) {\n if (processor.match) {\n try {\n if (!processor.match(ctx)) continue\n } catch (error) {\n console.error(\"Upload post processor failed\", {\n processorId: processor.id,\n processorVersion: processor.version,\n tenantId: ctx.tenantId,\n uploadId: ctx.uploadId,\n fileId: ctx.fileId,\n stage: \"match\",\n error,\n })\n continue\n }\n }\n\n try {\n await processor.process(ctx)\n } catch (error) {\n console.error(\"Upload post processor failed\", {\n processorId: processor.id,\n processorVersion: processor.version,\n tenantId: ctx.tenantId,\n uploadId: ctx.uploadId,\n fileId: ctx.fileId,\n stage: \"process\",\n error,\n })\n }\n }\n}\n\nqueue.registerTask(uploadPostProcessorTaskName, async (payload) => {\n await runUploadPostProcessors(payload as UploadPostProcessorContext)\n})\n\nexport const enqueueUploadPostProcessors = async (ctx: UploadPostProcessorContext): Promise<void> => {\n if (getUploadPostProcessors().length === 0) return\n\n await queue.add(uploadPostProcessorTaskName, ctx, {\n attempts: 3,\n backoff: { type: \"exponential\", delay: 5_000 },\n removeOnComplete: true,\n removeOnFail: false,\n })\n}\n","import { createHash, timingSafeEqual } from \"node:crypto\"\n\nimport { Ctx } from \"@rpcbase/api\"\nimport {\n type IRBUploadChunk,\n type IRBUploadSession,\n type LoadModelCtx,\n} from \"@rpcbase/db\"\nimport { buildAbilityFromSession, getAccessibleByQuery, type AppAbility } from \"@rpcbase/db/acl\"\nimport type { Model } from \"mongoose\"\n\n\nexport type SessionUser = {\n id?: string\n currentTenantId?: string\n}\n\nexport type UploadSessionDoc = IRBUploadSession\nexport type UploadChunkDoc = Omit<IRBUploadChunk, \"data\"> & { data: Buffer }\n\nconst DEFAULT_CHUNK_SIZE_BYTES = 5 * 1024 * 1024\nconst MAX_CHUNK_SIZE_BYTES = 15 * 1024 * 1024\n\nconst DEFAULT_MAX_CLIENT_BYTES_PER_SECOND = 10 * 1024 * 1024\n\nconst DEFAULT_SESSION_TTL_S = 60 * 60 * 24\n\nconst ensuredIndexDbNames = new Set<string>()\n\nconst parseOptionalPositiveInt = (rawValue: unknown): number | null => {\n if (typeof rawValue !== \"string\") return null\n const normalized = rawValue.trim()\n if (!normalized) return null\n const parsed = Number(normalized)\n if (!Number.isFinite(parsed) || parsed <= 0) return null\n return Math.floor(parsed)\n}\n\nexport const getChunkSizeBytes = (): number => {\n const configured = parseOptionalPositiveInt(process.env.RB_UPLOAD_CHUNK_SIZE_BYTES)\n const resolved = configured ?? DEFAULT_CHUNK_SIZE_BYTES\n return Math.min(MAX_CHUNK_SIZE_BYTES, resolved)\n}\n\nexport const getMaxClientUploadBytesPerSecond = (): number | null => {\n const configured = parseOptionalPositiveInt(process.env.RB_UPLOAD_MAX_CLIENT_BYTES_PER_SECOND)\n return configured ?? DEFAULT_MAX_CLIENT_BYTES_PER_SECOND\n}\n\nexport const getSessionTtlMs = (): number => {\n const ttlSeconds = parseOptionalPositiveInt(process.env.RB_UPLOAD_SESSION_TTL_S) ?? DEFAULT_SESSION_TTL_S\n return ttlSeconds * 1000\n}\n\nexport const getRawBodyLimitBytes = (chunkSizeBytes: number): number => chunkSizeBytes + 1024 * 1024\n\nexport const getBucketName = (): string => (process.env.RB_FILESYSTEM_BUCKET_NAME ?? \"\").trim() || \"fs\"\n\nexport const getUserId = (ctx: Ctx<SessionUser>): string | null => {\n const raw = ctx.req.session?.user?.id\n if (typeof raw !== \"string\") return null\n const normalized = raw.trim()\n return normalized ? normalized : null\n}\n\nexport const getTenantId = (ctx: Ctx<SessionUser>): string | null => {\n const rawSession = ctx.req.session?.user?.currentTenantId\n const sessionTenantId = typeof rawSession === \"string\" ? rawSession.trim() : \"\"\n return sessionTenantId || null\n}\n\nexport const computeSha256Hex = (data: Buffer): string => createHash(\"sha256\").update(data).digest(\"hex\")\n\nexport const normalizeSha256Hex = (value: string): string => value.trim().toLowerCase()\n\nexport const getModelCtx = (_ctx: Ctx<SessionUser>, tenantId: string, ability?: AppAbility): LoadModelCtx => ({\n req: {\n session: {\n user: {\n currentTenantId: tenantId,\n },\n },\n },\n ability,\n})\n\nexport const toBufferPayload = (payload: unknown): Buffer | null => {\n if (Buffer.isBuffer(payload)) return payload\n if (payload instanceof Uint8Array) return Buffer.from(payload)\n return null\n}\n\nexport const ensureUploadIndexes = async (\n UploadSession: Model<UploadSessionDoc>,\n UploadChunk: Model<UploadChunkDoc>,\n): Promise<void> => {\n const dbName = String((UploadSession as unknown as { db?: { name?: unknown } })?.db?.name ?? \"\")\n if (dbName && ensuredIndexDbNames.has(dbName)) return\n\n await Promise.all([\n UploadSession.createIndexes(),\n UploadChunk.createIndexes(),\n ])\n\n if (dbName) ensuredIndexDbNames.add(dbName)\n}\n\nconst normalizeUploadKey = (raw: unknown): string | null => {\n if (typeof raw !== \"string\") return null\n const normalized = raw.trim()\n return normalized ? normalized : null\n}\n\nexport const getUploadKeyHash = (ctx: Ctx<SessionUser>): string | null => {\n const uploadKey = normalizeUploadKey(ctx.req.get(\"X-Upload-Key\"))\n if (!uploadKey) return null\n return computeSha256Hex(Buffer.from(uploadKey))\n}\n\nexport const buildUploadsAbility = (ctx: Ctx<SessionUser>, tenantId: string): AppAbility => {\n const uploadKeyHash = getUploadKeyHash(ctx)\n const claims = uploadKeyHash ? { uploadKeyHash } : undefined\n return buildAbilityFromSession({ tenantId, session: ctx.req.session, claims })\n}\n\nexport const getUploadSessionAccessQuery = (\n ability: AppAbility,\n action: \"read\" | \"update\" | \"delete\",\n): Record<string, unknown> => getAccessibleByQuery(ability, action, \"RBUploadSession\")\n\nconst timingSafeEqualHex = (left: string, right: string): boolean => {\n if (left.length !== right.length) return false\n try {\n return timingSafeEqual(Buffer.from(left, \"hex\"), Buffer.from(right, \"hex\"))\n } catch {\n return false\n }\n}\n\nexport const getOwnershipSelector = (\n ctx: Ctx<SessionUser>,\n session: Pick<UploadSessionDoc, \"userId\" | \"ownerKeyHash\">,\n): { userId?: string; ownerKeyHash?: string } | null => {\n if (session.userId) {\n const userId = getUserId(ctx)\n if (!userId || userId !== session.userId) return null\n return { userId: session.userId }\n }\n\n if (session.ownerKeyHash) {\n const uploadKeyHash = getUploadKeyHash(ctx)\n if (!uploadKeyHash) return null\n if (!timingSafeEqualHex(session.ownerKeyHash, uploadKeyHash)) return null\n return { ownerKeyHash: session.ownerKeyHash }\n }\n\n return null\n}\n","import { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\nimport sharp from \"sharp\"\n\nimport { registerUploadPostProcessor } from \"./postProcessors\"\nimport { getBucketName } from \"./shared\"\n\n\nconst IMAGE_VARIANTS_PROCESSOR_ID = \"rb-image-variants\"\nconst IMAGE_VARIANTS_VERSION = 1\nconst IMAGE_VARIANT_WIDTHS = [320, 640, 960, 1600] as const\nconst IMAGE_VARIANT_QUALITY = 82\nconst IMAGE_VARIANT_MIME_TYPE = \"image/webp\"\nconst IMAGE_VARIANT_FORMAT = \"webp\"\nconst IMAGE_VARIANT_MAX_INPUT_BYTES = 32 * 1024 * 1024\nconst IMAGE_VARIANT_MAX_INPUT_PIXELS = 128 * 1024 * 1024\n\nconst supportedImageMimeTypes = new Set([\n \"image/avif\",\n \"image/heic\",\n \"image/heif\",\n \"image/jpeg\",\n \"image/png\",\n \"image/webp\",\n])\n\ntype ImageVariantRecord = {\n fileId: string\n width: number\n height: number\n mimeType: typeof IMAGE_VARIANT_MIME_TYPE\n size: number\n}\n\nconst normalizeMimeType = (value: string): string => value.trim().toLowerCase()\n\nconst toObjectId = (value: string): ObjectId | null => {\n try {\n return new ObjectId(value)\n } catch {\n return null\n }\n}\n\nconst readGridFsFile = async (bucket: GridFSBucket, fileId: ObjectId): Promise<Buffer> => new Promise((resolve, reject) => {\n const chunks: Buffer[] = []\n const stream = bucket.openDownloadStream(fileId)\n\n stream.on(\"data\", (chunk) => {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))\n })\n stream.once(\"error\", reject)\n stream.once(\"end\", () => resolve(Buffer.concat(chunks)))\n})\n\nconst writeGridFsFile = async (\n bucket: GridFSBucket,\n filename: string,\n data: Buffer,\n metadata: Record<string, unknown>,\n): Promise<string> => new Promise((resolve, reject) => {\n const stream = bucket.openUploadStream(filename, {\n metadata,\n })\n\n stream.once(\"error\", reject)\n stream.once(\"finish\", () => resolve(String((stream as unknown as { id?: unknown }).id ?? \"\")))\n stream.end(data)\n})\n\nregisterUploadPostProcessor({\n id: IMAGE_VARIANTS_PROCESSOR_ID,\n version: IMAGE_VARIANTS_VERSION,\n match: ({ mimeType, metadata }) => {\n if (typeof metadata.variantOf === \"string\") return false\n return supportedImageMimeTypes.has(normalizeMimeType(mimeType))\n },\n process: async ({ tenantId, fileId, filename, isPublic, userId, ownerKeyHash, totalSize }) => {\n const originalObjectId = toObjectId(fileId)\n if (!originalObjectId) return\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) return\n\n const bucketName = getBucketName()\n const filesCollection = nativeDb.collection(`${bucketName}.files`)\n const existingFile = await filesCollection.findOne({ _id: originalObjectId })\n if (!existingFile) return\n\n const existingImageMetadata = existingFile && typeof existingFile.metadata === \"object\" && existingFile.metadata\n ? (existingFile.metadata as Record<string, unknown>).image\n : null\n\n if (\n existingImageMetadata &&\n typeof existingImageMetadata === \"object\" &&\n (existingImageMetadata as Record<string, unknown>).variantsStatus === \"done\" &&\n (existingImageMetadata as Record<string, unknown>).variantsVersion === IMAGE_VARIANTS_VERSION\n ) {\n return\n }\n\n const markVariantsSkipped = async (reason: string): Promise<void> => {\n await filesCollection.updateOne(\n { _id: originalObjectId },\n {\n $set: {\n \"metadata.image.variantsStatus\": \"skipped\",\n \"metadata.image.variantsVersion\": IMAGE_VARIANTS_VERSION,\n \"metadata.image.variantsSkippedReason\": reason,\n },\n $unset: {\n \"metadata.image.variants\": \"\",\n },\n },\n )\n }\n\n const existingFileLength = typeof existingFile.length === \"number\" ? existingFile.length : null\n const sourceBytes = existingFileLength ?? totalSize\n if (sourceBytes > IMAGE_VARIANT_MAX_INPUT_BYTES) {\n await markVariantsSkipped(\"source_too_large\")\n return\n }\n\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n const source = await readGridFsFile(bucket, originalObjectId)\n const metadata = await sharp(source, { limitInputPixels: IMAGE_VARIANT_MAX_INPUT_PIXELS }).metadata()\n\n if (!metadata.width || !metadata.height) {\n await markVariantsSkipped(\"missing_dimensions\")\n return\n }\n\n const targetWidths = IMAGE_VARIANT_WIDTHS.filter((width) => width < metadata.width)\n const variants: Record<string, ImageVariantRecord> = {}\n\n for (const width of targetWidths) {\n const output = await sharp(source, { limitInputPixels: IMAGE_VARIANT_MAX_INPUT_PIXELS })\n .rotate()\n .resize({ width, withoutEnlargement: true })\n .webp({ quality: IMAGE_VARIANT_QUALITY, effort: 4 })\n .toBuffer({ resolveWithObject: true })\n\n const variantFileId = await writeGridFsFile(\n bucket,\n `${filename}.${width}.${IMAGE_VARIANT_FORMAT}`,\n output.data,\n {\n mimeType: IMAGE_VARIANT_MIME_TYPE,\n totalSize: output.data.length,\n variantOf: fileId,\n variantWidth: width,\n variantFormat: IMAGE_VARIANT_FORMAT,\n variantsVersion: IMAGE_VARIANTS_VERSION,\n ...(typeof isPublic === \"boolean\" ? { isPublic } : {}),\n ...(userId ? { userId } : {}),\n ...(ownerKeyHash ? { ownerKeyHash } : {}),\n },\n )\n\n if (!variantFileId) continue\n\n variants[String(width)] = {\n fileId: variantFileId,\n width: output.info.width,\n height: output.info.height,\n mimeType: IMAGE_VARIANT_MIME_TYPE,\n size: output.data.length,\n }\n }\n\n await filesCollection.updateOne(\n { _id: originalObjectId },\n {\n $set: {\n \"metadata.image\": {\n width: metadata.width,\n height: metadata.height,\n format: metadata.format,\n variantsStatus: Object.keys(variants).length ? \"done\" : \"skipped\",\n variantsVersion: IMAGE_VARIANTS_VERSION,\n variants,\n },\n },\n },\n )\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/uploads/api/\")] = mod\n return acc\n}, {})\n\n"],"names":["MAX_HEIF_BYTES","MAX_HEIF_INPUT_PIXELS","WEBP_QUALITY","CONVERSION_TIMEOUT_MS","POLL_INTERVAL_MS","HEIF_DECODE_UNSUPPORTED","heifMimeTypes","Set","heifExtensions","hevcBrands","convertHeifToWebpTaskName","delay","ms","Promise","resolve","setTimeout","normalizeMimeType","value","trim","toLowerCase","getFtypBrands","sniff","length","ftypOffset","indexOf","Buffer","from","brands","offset","Math","min","brand","subarray","toString","test","push","filter","Boolean","hasHeifDeclaration","filename","clientMimeType","has","looksLikeHevcHeif","some","isHeifUpload","toWebpFilename","trimmed","replace","isHeifDecodeUnsupportedError","error","message","Error","String","normalized","startsWith","includes","getSharpHeifSupportDiagnostic","suffixes","sharp","format","heif","input","fileSuffix","advertisedSuffixes","join","sharpVersion","versions","vipsVersion","vips","heifVersion","createHeifDecodeUnsupportedError","normalizeConversionError","convertHeifToWebp","payload","output","limitInputPixels","rotate","webp","quality","effort","toBuffer","resolveWithObject","dataBase64","data","mimeType","metadata","sourceFilename","sourceMimeType","info","width","height","convertHeifToWebpTask","job","inputBase64","log","queue","registerTask","waitForConversionResult","startedAt","Date","now","currentJob","id","getJob","state","getState","returnvalue","failedReason","runConversionTask","add","attempts","removeOnComplete","removeOnFail","convertHeifToWebpProcessor","maxBytes","match","process","ctx","result","MAX_SVG_BYTES","window","JSDOM","DOMPurify","createDOMPurify","normalizeForSniff","raw","trimStart","looksLikeSvgText","text","looksLikeSvg","sanitizeSvg","svg","sanitize","USE_PROFILES","svgFilters","sanitizeSvgProcessor","svgText","sanitized","sanitizedBuffer","processorsById","Object","create","uploadPostProcessorTaskName","normalizeProcessorId","normalizeProcessorVersion","undefined","Number","isInteger","registerUploadPostProcessor","processor","normalizedId","normalizedVersion","version","registerUploadProcessor","unregisterUploadPostProcessor","unregisterUploadProcessor","clearUploadPostProcessors","keys","clearUploadProcessors","getUploadPostProcessors","values","getUploadProcessors","runUploadPostProcessors","processors","console","processorId","processorVersion","tenantId","uploadId","fileId","stage","enqueueUploadPostProcessors","backoff","type","DEFAULT_CHUNK_SIZE_BYTES","MAX_CHUNK_SIZE_BYTES","DEFAULT_MAX_CLIENT_BYTES_PER_SECOND","DEFAULT_SESSION_TTL_S","ensuredIndexDbNames","parseOptionalPositiveInt","rawValue","parsed","isFinite","floor","getChunkSizeBytes","configured","env","RB_UPLOAD_CHUNK_SIZE_BYTES","resolved","getMaxClientUploadBytesPerSecond","RB_UPLOAD_MAX_CLIENT_BYTES_PER_SECOND","getSessionTtlMs","ttlSeconds","RB_UPLOAD_SESSION_TTL_S","getRawBodyLimitBytes","chunkSizeBytes","getBucketName","RB_FILESYSTEM_BUCKET_NAME","getUserId","req","session","user","getTenantId","rawSession","currentTenantId","sessionTenantId","computeSha256Hex","createHash","update","digest","normalizeSha256Hex","getModelCtx","_ctx","ability","toBufferPayload","isBuffer","Uint8Array","ensureUploadIndexes","UploadSession","UploadChunk","dbName","db","name","all","createIndexes","normalizeUploadKey","getUploadKeyHash","uploadKey","get","buildUploadsAbility","uploadKeyHash","claims","buildAbilityFromSession","getUploadSessionAccessQuery","action","getAccessibleByQuery","IMAGE_VARIANTS_PROCESSOR_ID","IMAGE_VARIANTS_VERSION","IMAGE_VARIANT_WIDTHS","IMAGE_VARIANT_QUALITY","IMAGE_VARIANT_MIME_TYPE","IMAGE_VARIANT_FORMAT","IMAGE_VARIANT_MAX_INPUT_BYTES","IMAGE_VARIANT_MAX_INPUT_PIXELS","supportedImageMimeTypes","toObjectId","ObjectId","readGridFsFile","bucket","reject","chunks","stream","openDownloadStream","on","chunk","once","concat","writeGridFsFile","openUploadStream","end","variantOf","isPublic","userId","ownerKeyHash","totalSize","originalObjectId","fsDb","getTenantFilesystemDb","nativeDb","bucketName","filesCollection","collection","existingFile","findOne","_id","existingImageMetadata","image","variantsStatus","variantsVersion","markVariantsSkipped","reason","updateOne","$set","$unset","existingFileLength","sourceBytes","GridFSBucket","source","targetWidths","variants","resize","withoutEnlargement","variantFileId","variantWidth","variantFormat","size","routes","entries","import","reduce","acc","path","mod"],"mappings":"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"}