@rpcbase/server 0.524.0 → 0.526.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-Dzauaq11.js +12449 -0
- package/dist/email-Dzauaq11.js.map +1 -0
- package/dist/handler-BLwgdQv-.js +544 -0
- package/dist/handler-BLwgdQv-.js.map +1 -0
- package/dist/handler-Cq-OJ0Rf.js +182 -0
- package/dist/handler-Cq-OJ0Rf.js.map +1 -0
- package/dist/handler-Cq6MsoD4.js +124 -0
- package/dist/handler-Cq6MsoD4.js.map +1 -0
- package/dist/handler-Cx_ZP_NB.js +749 -0
- package/dist/handler-Cx_ZP_NB.js.map +1 -0
- package/dist/index.js +4783 -4935
- package/dist/index.js.map +1 -1
- package/dist/notifications.js +134 -199
- package/dist/notifications.js.map +1 -1
- package/dist/queryExecutor-DYVlCvns.js +295 -0
- package/dist/queryExecutor-DYVlCvns.js.map +1 -0
- package/dist/render_resend-CQb8_8G7.js +7 -0
- package/dist/render_resend-CQb8_8G7.js.map +1 -0
- package/dist/rts/index.js +581 -725
- package/dist/rts/index.js.map +1 -1
- package/dist/schemas-BR3K5Luo.js +3824 -0
- package/dist/schemas-BR3K5Luo.js.map +1 -0
- package/dist/shared-BfMSZm2P.js +87 -0
- package/dist/shared-BfMSZm2P.js.map +1 -0
- package/dist/ssrMiddleware.d.ts +1 -1
- package/dist/uploads.js +71 -84
- package/dist/uploads.js.map +1 -1
- package/package.json +9 -9
- package/dist/email-DK8uUU4X.js +0 -8045
- package/dist/email-DK8uUU4X.js.map +0 -1
- package/dist/handler-0rPClEv4.js +0 -663
- package/dist/handler-0rPClEv4.js.map +0 -1
- package/dist/handler-3uwH4f67.js +0 -924
- package/dist/handler-3uwH4f67.js.map +0 -1
- package/dist/handler-BsauvgjA.js +0 -153
- package/dist/handler-BsauvgjA.js.map +0 -1
- package/dist/handler-DnSJAQ_B.js +0 -203
- package/dist/handler-DnSJAQ_B.js.map +0 -1
- package/dist/queryExecutor-Bg1GGL3j.js +0 -407
- package/dist/queryExecutor-Bg1GGL3j.js.map +0 -1
- package/dist/render_resend_false-MiC__Smr.js +0 -6
- package/dist/render_resend_false-MiC__Smr.js.map +0 -1
- package/dist/schemas-Cjdjgehl.js +0 -4225
- package/dist/schemas-Cjdjgehl.js.map +0 -1
- package/dist/shared-BqZiSOmf.js +0 -111
- package/dist/shared-BqZiSOmf.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-Cx_ZP_NB.js","names":["JSDOM","createDOMPurify","UploadFileProcessor","MAX_SVG_BYTES","window","DOMPurify","normalizeForSniff","raw","replace","trimStart","looksLikeSvgText","text","normalized","startsWith","test","looksLikeSvg","sniff","Buffer","toString","sanitizeSvg","svg","sanitize","USE_PROFILES","svgFilters","sanitizeSvgProcessor","id","maxBytes","match","process","data","mimeType","length","Error","svgText","sanitized","trim","sanitizedBuffer","from","sanitizeSvgProcessor","UploadFileProcessorContext","filename","clientMimeType","totalSize","sniff","Buffer","UploadFileProcessorResult","data","mimeType","UploadFileProcessor","id","maxBytes","match","ctx","process","Promise","uploadProcessors","Object","freeze","getMaxUploadProcessorBytes","reduce","max","processor","Math","selectUploadProcessors","filter","applyUploadProcessors","Omit","applied","currentData","currentMimeType","processorCtx","length","Error","result","trim","push","ApiHandler","getTenantFilesystemDb","models","GridFSBucket","Model","Uploads","runUploadPostProcessors","applyUploadProcessors","getMaxUploadProcessorBytes","selectUploadProcessors","SessionUser","UploadChunkDoc","UploadSessionDoc","buildUploadsAbility","ensureUploadIndexes","getBucketName","getModelCtx","getUploadSessionAccessQuery","getTenantId","waitForStreamFinished","stream","NodeJS","WritableStream","Promise","resolve","reject","once","writeToStream","chunk","Buffer","ok","write","onDrain","cleanup","onError","error","off","on","abortUploadStream","abort","destroy","completeUpload","Record","CompleteResponsePayload","_payload","ctx","tenantId","res","status","uploadId","String","req","params","trim","ability","modelCtx","UploadSession","UploadChunk","all","get","can","existing","findOne","$and","_id","lean","fileId","locked","findOneAndUpdate","$set","$unset","returnDocument","fsDb","nativeDb","db","updateOne","bucketName","bucket","lockedUserId","userId","undefined","maxProcessorBytes","shouldBufferForProcessing","totalSize","declaredMimeType","mimeType","toLowerCase","declaredSvg","filename","endsWith","uploadStream","finalMimeType","inlineProcessors","finalMetadata","isPublic","ownerKeyHash","Error","cursor","find","sort","index","AsyncIterable","close","expectedIndex","chunks","bufferedBytes","pendingChunks","sniffParts","sniffBytes","chunkDoc","data","push","length","slice","subarray","Math","min","sniff","concat","processors","clientMimeType","openUploadStream","metadata","pending","chunksTotal","assembled","processed","processedMimeType","applied","processedSize","finished","end","id","deleteMany","message","ApiHandler","models","Model","Uploads","SessionUser","UploadChunkDoc","UploadSessionDoc","buildUploadsAbility","getModelCtx","getUploadSessionAccessQuery","getTenantId","getStatus","Record","StatusResponsePayload","_payload","ctx","Promise","tenantId","res","status","ok","error","uploadId","String","req","params","trim","ability","modelCtx","UploadSession","UploadChunk","all","get","can","session","findOne","$and","_id","lean","receivedDocs","find","index","sort","received","Array","map","doc","filter","n","Number","isInteger","chunkSize","chunksTotal","fileId","z","InitRoute","ChunkRoute","StatusRoute","CompleteRoute","initRequestSchema","object","filename","string","min","mimeType","isPublic","boolean","optional","totalSize","number","int","InitRequestPayload","infer","initResponseSchema","ok","error","uploadId","uploadKey","chunkSize","chunksTotal","InitResponsePayload","statusResponseSchema","status","enum","received","array","fileId","StatusResponsePayload","completeResponseSchema","CompleteResponsePayload","randomBytes","ApiHandler","models","ObjectId","Model","Uploads","SessionUser","UploadChunkDoc","UploadSessionDoc","buildUploadsAbility","computeSha256Hex","ensureUploadIndexes","getChunkSizeBytes","getModelCtx","getSessionTtlMs","getTenantId","getUserId","initUpload","InitRequestPayload","InitResponsePayload","payload","ctx","Promise","tenantId","res","status","ok","error","userId","parsed","initRequestSchema","safeParse","success","chunkSize","filename","mimeType","totalSize","isPublic","data","chunksTotal","Math","ceil","ability","modelCtx","UploadSession","UploadChunk","all","get","uploadId","toString","now","Date","expiresAt","uploadKey","ownerKeyHash","Buffer","from","undefined","create","_id","createdAt","ApiHandler","models","Model","SessionUser","UploadChunkDoc","UploadSessionDoc","buildUploadsAbility","computeSha256Hex","ensureUploadIndexes","getModelCtx","getUploadSessionAccessQuery","getTenantId","normalizeSha256Hex","toBufferPayload","ChunkResponsePayload","ok","error","uploadChunk","Buffer","payload","ctx","Promise","tenantId","res","status","uploadId","String","req","params","trim","indexRaw","index","Number","isInteger","ability","modelCtx","UploadSession","UploadChunk","all","get","can","session","findOne","$and","_id","lean","chunksTotal","data","expectedSize","totalSize","chunkSize","length","checksumHeader","sha256","undefined","expectedSha256","updateOne","$set","size","expiresAt","$setOnInsert","createdAt","Date","upsert","rawBodyParser","limitBytes","maxClientBytesPerSecond","req","res","next","contentType","headers","String","includes","total","chunks","Buffer","done","paused","throttleTimeout","ReturnType","setTimeout","rateBytesPerSecond","cleanup","off","onData","onEnd","onError","onAborted","clearTimeout","finish","error","body","concat","chunk","buffer","isBuffer","from","length","destroy","status","json","ok","push","now","Date","clientKey","getClientKey","state","getClientRateState","waitMs","consumeRateBudget","pause","resume","err","Error","on","ClientRateState","tokens","lastRefillMs","lastSeenMs","MAX_BURST_SECONDS","STALE_CLIENT_MS","clientRateStates","Map","lastCleanupMs","rawClientIp","clientIp","trim","rawIp","ip","maybeCleanupStates","size","key","delete","capacity","existing","get","Math","min","set","bytes","elapsedMs","max","ceil","Api","completeUpload","getStatus","initUpload","uploadChunk","rawBodyParser","getChunkSizeBytes","getMaxClientUploadBytesPerSecond","getRawBodyLimitBytes","SessionUser","Uploads","api","chunkSizeBytes","use","InitRoute","limitBytes","maxClientBytesPerSecond","post","put","ChunkRoute","get","StatusRoute","CompleteRoute"],"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 { runUploadPostProcessors } 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 runUploadPostProcessors({\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 })\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"],"mappings":";;;;;;;;;AAMA,IAAMG,gBAAgB,MAAM;AAE5B,IAAMC,SAAS,IAAIJ,MAAM,GAAG,CAACI;AAC7B,IAAMC,YAAYJ,gBAAgBG,OAAO;AAEzC,IAAME,qBAAqBC,QAAwBA,IAAIC,QAAQ,WAAW,GAAG,CAACC,WAAW;AAEzF,IAAMC,oBAAoBC,SAA0B;CAClD,MAAMC,aAAaN,kBAAkBK,KAAK;AAC1C,KAAI,CAACC,WAAWC,WAAW,IAAI,CAAE,QAAO;AACxC,QAAO,gBAAgBC,KAAKF,WAAW;;AAGzC,IAAaG,gBAAgBC,UAA2BN,iBAAiBM,MAAME,SAAS,OAAO,CAAC;AAEhG,IAAaC,eAAeC,QAC1Bf,UAAUgB,SAASD,KAAK,EACtBE,cAAc;CAAEF,KAAK;CAAMG,YAAY;CAAK,EAC7C,CAAC;;;ACFJ,IAAagC,mBAAmBC,OAAOC,OAAO,CDIW;CACvDhC,IAAI;CACJC,UAAUvB;CACVwB,QAAQ,EAAEX,YAAYD,aAAaC,MAAM;CACzCY,UAAUC,SAA6C;AACrD,MAAIA,KAAKE,SAAS5B,cAChB,OAAM,IAAI6B,MAAM,gBAAgB;EAGlC,MAAMC,UAAUJ,KAAKX,SAAS,OAAO;AACrC,MAAI,CAACR,iBAAiBuB,QAAQ,CAC5B,OAAM,IAAID,MAAM,cAAc;EAGhC,MAAME,YAAYf,YAAYc,QAAQ;AACtC,MAAI,CAACC,UAAUC,MAAM,IAAI,CAACzB,iBAAiBwB,UAAU,CACnD,OAAM,IAAIF,MAAM,sBAAsB;EAGxC,MAAMI,kBAAkBnB,OAAOoB,KAAKH,WAAW,OAAO;AACtD,MAAIE,gBAAgBL,SAAS5B,cAC3B,OAAM,IAAI6B,MAAM,gBAAgB;AAGlC,SAAO;GAAEH,MAAMO;GAAiBN,UAAU;GAAiB;;CAE9D,CC9BmE,CAAiC;AAErG,IAAa4B,mCACXH,iBAAiBI,QAAQC,KAAKC,cAAcC,KAAKF,IAAIA,KAAKC,UAAUX,SAAS,EAAE,EAAE;AAEnF,IAAaa,0BAA0BX,QACrCG,iBAAiBS,QAAQH,cAAcA,UAAUV,MAAMC,IAAI,CAAC;AAE9D,IAAaa,wBAAwB,OACnCnB,MACAM,QACmE;CACnE,IAAIgB,cAActB;CAClB,IAAIuB,kBAAkBjB,IAAIX;CAC1B,MAAM0B,UAAoB,EAAE;AAE5B,MAAK,MAAMN,aAAaN,kBAAkB;EACxC,MAAMe,eAA2C;GAC/C9B,UAAUY,IAAIZ;GACdC,gBAAgB4B;GAChB3B,WAAW0B,YAAYG;GACvB5B,OAAOyB;GACR;AAED,MAAI,CAACP,UAAUV,MAAMmB,aAAa,CAAE;AAEpC,MAAIF,YAAYG,SAASV,UAAUX,SACjC,OAAM,IAAIsB,MAAM,4BAA4B;EAG9C,MAAMC,SAAS,MAAMZ,UAAUR,QAAQe,aAAaE,aAAa;AACjEF,gBAAcK,OAAO3B;AACrB,MAAI,OAAO2B,OAAO1B,aAAa,YAAY0B,OAAO1B,SAAS2B,MAAM,CAC/DL,mBAAkBI,OAAO1B,SAAS2B,MAAM;AAE1CP,UAAQQ,KAAKd,UAAUZ,GAAG;;AAG5B,QAAO;EACLH,MAAMsB;EACNrB,UAAUsB;EACVF;EACD;;;;AC3CH,IAAM4B,wBAAwB,OAAOC,WAAiD,IAAIG,SAASC,SAASC,WAAW;AACrHL,QAAOM,KAAK,UAAUF,QAAQ;AAC9BJ,QAAOM,KAAK,SAASD,OAAO;EAC5B;AAEF,IAAME,gBAAgB,OAAOP,QAA+BQ,UAAiC;AAE3F,KADWR,OAAOW,MAAMH,MAAM,CACtB;AACR,OAAM,IAAIL,SAAeC,SAASC,WAAW;EAC3C,MAAMO,gBAAgB;AACpBC,YAAS;AACTT,YAAS;;EAGX,MAAMU,WAAWC,UAAmB;AAClCF,YAAS;AACTR,UAAOU,MAAM;;EAGf,MAAMF,gBAAgB;AACpBb,UAAOgB,IAAI,SAASJ,QAAQ;AAC5BZ,UAAOgB,IAAI,SAASF,QAAQ;;AAG9Bd,SAAOiB,GAAG,SAASL,QAAQ;AAC3BZ,SAAOiB,GAAG,SAASH,QAAQ;GAC3B;;AAGJ,IAAMI,oBAAoB,OAAOlB,WAAmC;AAClE,KAAI,CAACA,OAAQ;AACb,KAAI,OAAQA,OAA+BmB,UAAU,WACnD,KAAI;AACF,QAAOnB,OAAiDmB,OAAO;AAC/D;SACM;AAIV,KAAI;AACAnB,SAAoCoB,WAAW;SAC3C;;AAKV,IAAaC,iBAAkG,OAC7GG,UACAC,QAC6C;CAC7C,MAAMC,WAAW5B,YAAY2B,IAAI;AACjC,KAAI,CAACC,UAAU;AACbD,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAkB;;CAG/C,MAAMc,WAAWC,OAAOL,IAAIM,IAAIC,QAAQH,YAAY,GAAG,CAACI,MAAM;AAC9D,KAAI,CAACJ,UAAU;AACbJ,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAqB;;CAGlD,MAAMmB,UAAUzC,oBAAoBgC,KAAKC,SAAS;CAClD,MAAMS,WAAWvC,YAAY6B,KAAKC,UAAUQ,QAAQ;CAEpD,MAAM,CAACE,eAAeC,eAAe,MAAMlC,QAAQmC,IAAI,CACrDxD,OAAOyD,IAAI,mBAAmBJ,SAAS,EACvCrD,OAAOyD,IAAI,iBAAiBJ,SAAS,CACtC,CAAC;AAEF,KAAI,CAACD,QAAQM,IAAI,UAAU,kBAAkB,EAAE;AAC7Cf,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAgB;;CAG7C,MAAM0B,WAAW,MAAML,cAAcM,QAAQ,EAAEC,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,OAAO,CAAA,EAAG,CAAC,CAACW,MAAM;AAChI,KAAI,CAACJ,UAAU;AACbhB,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAa;;AAG1C,KAAI0B,SAASb,WAAW,UAAUa,SAASK,OACzC,QAAO;EAAEpC,IAAI;EAAMoC,QAAQL,SAASK;EAAQ;CAG9C,MAAMC,SAAS,MAAMX,cAAcY,iBACjC,EAAEL,MAAM;EAAC,EAAEC,KAAKf,UAAU;EAAE,EAAED,QAAQ,aAAa;EAAE/B,4BAA4BqC,SAAS,SAAS;EAAA,EAAG,EACtG;EAAEe,MAAM,EAAErB,QAAQ,cAAc;EAAEsB,QAAQ,EAAEnC,OAAO,IAAG;EAAG,EACzD,EAAEoC,gBAAgB,SACpB,CAAC,CAACN,MAAM;AAER,KAAI,CAACE,QAAQ;AACXtB,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAiB;;AAG9C,OAAMrB,oBAAoB0C,eAAeC,YAAY;CAGrD,MAAMgB,YADO,MAAMxE,sBAAsB6C,SAAS,EAC5B4B;AACtB,KAAI,CAACD,UAAU;AACb,QAAMjB,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E,EAAEe,MAAM;GAAErB,QAAQ;GAASb,OAAO;GAA4B,EAChE,CAAC;AACDU,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAmB;;CAGhD,MAAM0C,SAAS,IAAI1E,aAAasE,UAAU,EAAEG,YADzB7D,eAAe,EACsB,CAAC;CAEzD,MAAM+D,eAAe,OAAOX,OAAOY,WAAW,WAAWZ,OAAOY,SAASC,KAAAA;CACzE,MAAMC,oBAAoBzE,4BAA4B;CACtD,MAAM0E,4BAA4Bf,OAAOgB,aAAaF;CAEtD,MAAMM,cADmBpB,OAAOkB,SAAShC,MAAM,CAACiC,aAAa,KACpB,mBAAmBnB,OAAOqB,SAASnC,MAAM,CAACiC,aAAa,CAACG,SAAS,OAAO;CAEjH,IAAIC,eAA6C;CACjD,IAAIC,gBAAgBxB,OAAOkB;CAC3B,IAAIO,mBAA6B,EAAE;CACnC,IAAIC,gBAAyC;EAC3C5C;EACAH;EACAuC,UAAUlB,OAAOkB;EACjBF,WAAWhB,OAAOgB;EAClB,GAAI,OAAOhB,OAAO2B,aAAa,YAAY,EAAEA,UAAU3B,OAAO2B,UAAU,GAAG,EAAE;EAC7E,GAAI,OAAO3B,OAAO4B,iBAAiB,WAAW,EAAEA,cAAc5B,OAAO4B,cAAc,GAAG,EAAE;EACxF,GAAIjB,eAAe,EAAEC,QAAQD,cAAc,GAAG,EAAE;EACjD;AAED,KAAI;AACF,MAAI,CAACI,6BAA6BK,YAChC,OAAM,IAAIS,MAAM,gBAAgB;EAGlC,MAAMC,SAASxC,YAAYyC,KAAK,EAAEjD,UAAU,CAAC,CAACkD,KAAK,EAAEC,OAAO,GAAG,CAAC,CAACH,QAAQ;EAIzE,IAAIM,gBAAgB;EACpB,MAAMC,SAAmB,EAAE;EAC3B,IAAIC,gBAAgB;EAEpB,MAAMC,gBAA0B,EAAE;EAClC,MAAMC,aAAuB,EAAE;EAC/B,IAAIC,aAAa;AAEjB,MAAI;AACF,cAAW,MAAMC,YAAYZ,QAAQ;AACnC,QAAIY,SAAST,UAAUG,cACrB,OAAM,IAAIP,MAAM,iBAAiB;IAGnC,MAAMpE,QAAQiF,SAASC;AAEvB,QAAI5B,2BAA2B;AAC7BsB,YAAOO,KAAKnF,MAAM;AAClB6E,sBAAiB7E,MAAMoF;eACd,CAACtB,cAAc;AACxBgB,mBAAcK,KAAKnF,MAAM;AAEzB,SAAIgF,aAAa3B,mBAAmB;MAClC,MAAMgC,QAAQrF,MAAMsF,SAAS,GAAGC,KAAKC,IAAIxF,MAAMoF,QAAQ/B,oBAAoB2B,WAAW,CAAC;AACvF,UAAIK,MAAMD,QAAQ;AAChBL,kBAAWI,KAAKE,MAAM;AACtBL,qBAAcK,MAAMD;;;AAIxB,SAAIJ,cAAc3B,mBAAmB;MACnC,MAAMoC,QAAQxF,OAAOyF,OAAOX,YAAYC,WAAW;AAQnD,UAPmBnG,uBAAuB;OACxC+E,UAAUrB,OAAOqB;OACjBgC,gBAAgBrD,OAAOkB;OACvBF,WAAWhB,OAAOgB;OAClBkC;OACD,CAAC,CAEaL,OACb,OAAM,IAAIhB,MAAM,gBAAgB;AAGlCH,sBAAgB;OACd5C;OACAH;OACAuC,UAAUlB,OAAOkB;OACjBF,WAAWhB,OAAOgB;OAClB,GAAI,OAAOhB,OAAO2B,aAAa,YAAY,EAAEA,UAAU3B,OAAO2B,UAAU,GAAG,EAAE;OAC7E,GAAI,OAAO3B,OAAO4B,iBAAiB,WAAW,EAAEA,cAAc5B,OAAO4B,cAAc,GAAG,EAAE;OACxF,GAAIjB,eAAe,EAAEC,QAAQD,cAAc,GAAG,EAAE;OACjD;AACDY,qBAAeb,OAAO4C,iBAAiBtD,OAAOqB,UAAU,EACtDkC,UAAU7B,eACX,CAAC;AAEF,WAAK,MAAM8B,WAAWjB,cACpB,OAAM/E,cAAc+D,cAAciC,QAAQ;AAE5CjB,oBAAcM,SAAS;;UAGzB,OAAMrF,cAAc+D,cAAc9D,MAAM;AAG1C2E,qBAAiB;;YAEX;AACR,OAAI;AACF,UAAMN,OAAOK,OAAO;WACd;;AAKV,MAAIC,kBAAkBpC,OAAOyD,YAC3B,OAAM,IAAI5B,MAAM,iBAAiB;AAGnC,MAAId,2BAA2B;GAE7B,MAAM,EAAE4B,MAAMgB,WAAWzC,UAAU0C,mBAAmBC,YAAY,MAAMzH,sBADtDsB,OAAOyF,OAAOd,QAAQC,cAAc,EACmD;IACvGjB,UAAUrB,OAAOqB;IACjBgC,gBAAgBrD,OAAOkB;IACxB,CAAC;AAEFM,mBAAgBoC;AAChBnC,sBAAmBoC;AACnBnC,mBAAgB;IACd5C;IACAH;IACAuC,UAAU0C;IACV5C,WAAWhB,OAAOgB;IAClB,GAAI6C,QAAQhB,SAAS;KAAEO,YAAYS;KAASC,eAAeH,UAAUd;KAAQ,GAAG,EAAE;IAClF,GAAI,OAAO7C,OAAO2B,aAAa,YAAY,EAAEA,UAAU3B,OAAO2B,UAAU,GAAG,EAAE;IAC7E,GAAI,OAAO3B,OAAO4B,iBAAiB,WAAW,EAAEA,cAAc5B,OAAO4B,cAAc,GAAG,EAAE;IACxF,GAAIjB,eAAe,EAAEC,QAAQD,cAAc,GAAG,EAAE;IACjD;AACDY,kBAAeb,OAAO4C,iBAAiBtD,OAAOqB,UAAU,EACtDkC,UAAU7B,eACX,CAAC;GAEF,MAAMqC,WAAW/G,sBAAsBuE,aAAa;AACpDA,gBAAayC,IAAIL,UAAU;AAC3B,SAAMI;SACD;AACL,OAAI,CAACxC,cAAc;IACjB,MAAM2B,QAAQxF,OAAOyF,OAAOX,YAAYC,WAAW;AAQnD,QAPmBnG,uBAAuB;KACxC+E,UAAUrB,OAAOqB;KACjBgC,gBAAgBrD,OAAOkB;KACvBF,WAAWhB,OAAOgB;KAClBkC;KACD,CAAC,CAEaL,OACb,OAAM,IAAIhB,MAAM,gBAAgB;AAGlCH,oBAAgB;KACd5C;KACAH;KACAuC,UAAUlB,OAAOkB;KACjBF,WAAWhB,OAAOgB;KAClB,GAAI,OAAOhB,OAAO2B,aAAa,YAAY,EAAEA,UAAU3B,OAAO2B,UAAU,GAAG,EAAE;KAC7E,GAAI,OAAO3B,OAAO4B,iBAAiB,WAAW,EAAEA,cAAc5B,OAAO4B,cAAc,GAAG,EAAE;KACxF,GAAIjB,eAAe,EAAEC,QAAQD,cAAc,GAAG,EAAE;KACjD;AACDY,mBAAeb,OAAO4C,iBAAiBtD,OAAOqB,UAAU,EACtDkC,UAAU7B,eACX,CAAC;AAEF,SAAK,MAAM8B,WAAWjB,cACpB,OAAM/E,cAAc+D,cAAciC,QAAQ;AAE5CjB,kBAAcM,SAAS;;GAGzB,MAAMkB,WAAW/G,sBAAsBuE,aAAa;AACpDA,gBAAayC,KAAK;AAClB,SAAMD;;EAGR,MAAMhE,SAAShB,OAAQwC,aAA6C0C,MAAM,GAAG;AAC7E,MAAI,CAAClE,OACH,OAAM,IAAI8B,MAAM,kBAAkB;AAGpC,QAAMxC,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E;GAAEe,MAAM;IAAErB,QAAQ;IAAQkB;IAAQ;GAAEI,QAAQ,EAAEnC,OAAO,IAAG;GAC1D,CAAC;AAED,QAAM7B,wBAAwB;GAC5BwC;GACAG;GACAiB;GACAsB,UAAUrB,OAAOqB;GACjBH,UAAUM;GACV6B,gBAAgBrD,OAAOkB;GACvBF,WAAWhB,OAAOgB;GAClB,GAAI,OAAOhB,OAAO2B,aAAa,YAAY,EAAEA,UAAU3B,OAAO2B,UAAU,GAAG,EAAE;GAC7E,GAAI,OAAO3B,OAAO4B,iBAAiB,WAAW,EAAEA,cAAc5B,OAAO4B,cAAc,GAAG,EAAE;GACxF,GAAIjB,eAAe,EAAEC,QAAQD,cAAc,GAAG,EAAE;GAChDc;GACA8B,UAAU7B;GACX,CAAC;AAEF,MAAI;AACF,SAAMpC,YAAY4E,WAAW,EAAEpF,UAAU,CAAC;UACpC;AAIR,SAAO;GAAEnB,IAAI;GAAMoC;GAAQ;UACpB/B,OAAO;EACd,MAAMmG,UAAUnG,iBAAiB6D,QAAQ7D,MAAMmG,UAAUpF,OAAOf,MAAM;AAEtE,QAAMG,kBAAkBoD,aAAa;AAErC,MAAI4C,YAAY,kBAAkB;AAChC,SAAM9E,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E,EAAEe,MAAM,EAAErB,QAAQ,aAAY,EAChC,CAAC;AACDH,OAAIE,IAAIC,OAAO,IAAI;AACnB,UAAO;IAAElB,IAAI;IAAOK,OAAO;IAAkB;;AAG/C,MAAImG,YAAY,iBAAiB;AAC/B,SAAM9E,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E,EAAEe,MAAM;IAAErB,QAAQ;IAASb,OAAOmG;IAAQ,EAC5C,CAAC;AACDzF,OAAIE,IAAIC,OAAO,IAAI;AACnB,UAAO;IAAElB,IAAI;IAAOK,OAAOmG;IAAS;;AAGtC,MAAIA,YAAY,iBAAiBA,YAAY,uBAAuB;AAClE,SAAM9E,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E,EAAEe,MAAM;IAAErB,QAAQ;IAASb,OAAOmG;IAAQ,EAC5C,CAAC;AACDzF,OAAIE,IAAIC,OAAO,IAAI;AACnB,UAAO;IAAElB,IAAI;IAAOK,OAAOmG;IAAS;;AAGtC,QAAM9E,cAAcmB,UAClB,EAAEZ,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEhC,4BAA4BqC,SAAS,SAAS,CAAA,EAAG,EAC7E,EAAEe,MAAM;GAAErB,QAAQ;GAASb,OAAOmG;GAAQ,EAC5C,CAAC;AAEDzF,MAAIE,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAElB,IAAI;GAAOK,OAAO;GAAmB;;;;;ACrWlD,IAAa+G,YAA2F,OACtGG,UACAC,QAC2C;CAC3C,MAAME,WAAWP,YAAYK,IAAI;AACjC,KAAI,CAACE,UAAU;AACbF,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAkB;;CAG/C,MAAMC,WAAWC,OAAOR,IAAIS,IAAIC,QAAQH,YAAY,GAAG,CAACI,MAAM;AAC9D,KAAI,CAACJ,UAAU;AACbP,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAqB;;CAGlD,MAAMM,UAAUpB,oBAAoBQ,KAAKE,SAAS;CAClD,MAAMW,WAAWpB,YAAYO,KAAKE,UAAUU,QAAQ;CAEpD,MAAM,CAACE,eAAeC,eAAe,MAAMd,QAAQe,IAAI,CACrD9B,OAAO+B,IAAI,mBAAmBJ,SAAS,EACvC3B,OAAO+B,IAAI,iBAAiBJ,SAAS,CACtC,CAAC;AAEF,KAAI,CAACD,QAAQM,IAAI,QAAQ,kBAAkB,EAAE;AAC3ClB,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAgB;;CAG7C,MAAMa,UAAU,MAAML,cAAcM,QAAQ,EAAEC,MAAM,CAAC,EAAEC,KAAKf,UAAU,EAAEb,4BAA4BkB,SAAS,OAAO,CAAA,EAAG,CAAC,CAACW,MAAM;AAC/H,KAAI,CAACJ,SAAS;AACZnB,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAa;;CAQ1C,MAAMsB,YALe,MAAMb,YAAYU,KACrC,EAAElB,UAAU,EACZ;EAAEmB,OAAO;EAAGJ,KAAK;EACnB,CAAC,CAACK,KAAK,EAAED,OAAO,GAAG,CAAC,CAACH,MAAM,EAGxBO,KAAKC,QAAS,OAAOA,IAAIL,UAAU,WAAWK,IAAIL,QAAQ,GAAI,CAC9DM,QAAQC,MAAMC,OAAOC,UAAUF,EAAE,IAAIA,KAAK,EAAE;AAE/C,QAAO;EACL5B,IAAI;EACJD,QAAQe,QAAQf;EAChBgC,WAAWjB,QAAQiB;EACnBC,aAAalB,QAAQkB;EACrBT;EACA,GAAIT,QAAQmB,SAAS,EAAEA,QAAQnB,QAAQmB,QAAQ,GAAG,EAAE;EACrD;;;;AChEH,IAAaE,YAAY;AACzB,IAAaC,aAAa;AAC1B,IAAaC,cAAc;AAC3B,IAAaC,gBAAgB;AAE7B,IAAaC,oBAAoBL,OAAS;CACxCO,UAAUP,QAAU,CAACS,IAAI,EAAE;CAC3BC,UAAUV,QAAU,CAACS,IAAI,EAAE;CAC3BE,UAAUX,SAAW,CAACa,UAAU;CAChCC,WAAWd,QAAU,CAACgB,KAAK,CAACP,IAAI,EAAC;CAClC,CAAC;AAIgCT,OAAS;CACzCoB,IAAIpB,SAAW;CACfqB,OAAOrB,QAAU,CAACa,UAAU;CAC5BS,UAAUtB,QAAU,CAACa,UAAU;CAC/BU,WAAWvB,QAAU,CAACa,UAAU;CAChCW,WAAWxB,QAAU,CAACgB,KAAK,CAACH,UAAU;CACtCY,aAAazB,QAAU,CAACgB,KAAK,CAACH,UAAS;CACxC,CAAC;AAIkCb,OAAS;CAC3CoB,IAAIpB,SAAW;CACfqB,OAAOrB,QAAU,CAACa,UAAU;CAC5Be,QAAQ5B,MAAO;EAAC;EAAa;EAAc;EAAQ;EAAQ,CAAC,CAACa,UAAU;CACvEW,WAAWxB,QAAU,CAACgB,KAAK,CAACH,UAAU;CACtCY,aAAazB,QAAU,CAACgB,KAAK,CAACH,UAAU;CACxCiB,UAAU9B,MAAQA,QAAU,CAACgB,KAAK,CAACP,IAAI,EAAE,CAAC,CAACI,UAAU;CACrDmB,QAAQhC,QAAU,CAACa,UAAS;CAC7B,CAAC;AAIoCb,OAAS;CAC7CoB,IAAIpB,SAAW;CACfqB,OAAOrB,QAAU,CAACa,UAAU;CAC5BmB,QAAQhC,QAAU,CAACa,UAAS;CAC7B,CAAC;;;ACrBF,IAAawC,aAA+F,OAC1GG,SACAC,QACyC;CACzC,MAAME,WAAWR,YAAYM,IAAI;AACjC,KAAI,CAACE,UAAU;AACbF,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAkB;;CAG/C,MAAMC,SAASZ,UAAUK,IAAI;CAE7B,MAAMQ,SAAAA,kBAAmCE,UAAUX,WAAW,EAAE,CAAC;AACjE,KAAI,CAACS,OAAOG,SAAS;AACnBX,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAEC,IAAI;GAAOC,OAAO;GAAmB;;CAGhD,MAAMM,YAAYrB,mBAAmB;CACrC,MAAM,EAAEsB,UAAUC,UAAUC,WAAWC,aAAaR,OAAOS;CAC3D,MAAMC,cAAcC,KAAKC,KAAKL,YAAYH,UAAU;CAGpD,MAAMU,WAAW9B,YAAYQ,KAAKE,UADlBd,oBAAoBY,KAAKE,SAAS,CACE;CAEpD,MAAM,CAACqB,eAAeC,eAAe,MAAMvB,QAAQwB,IAAI,CACrD5C,OAAO6C,IAAI,mBAAmBJ,SAAS,EACvCzC,OAAO6C,IAAI,iBAAiBJ,SAAS,CACtC,CAAC;AAEF,OAAMhC,oBAAoBiC,eAAeC,YAAY;CAErD,MAAMG,WAAW,IAAI7C,UAAU,CAAC8C,UAAU;CAC1C,MAAMC,MAAMC,KAAKD,KAAK;CACtB,MAAME,YAAY,IAAID,KAAKD,MAAMpC,iBAAiB,CAAC;CAEnD,MAAMuC,YAAYzB,SAAS,OAAO5B,YAAY,GAAG,CAACiD,SAAS,YAAY;CACvE,MAAMK,eAAeD,YAAY3C,iBAAiB6C,OAAOC,KAAKH,UAAU,CAAC,GAAGI,KAAAA;AAE5E,OAAMb,cAAcc,OAAO;EACzBC,KAAKX;EACL,GAAIpB,SAAS,EAAEA,QAAQ,GAAG,EAAE;EAC5B,GAAI0B,eAAe,EAAEA,cAAc,GAAG,EAAE;EACxCpB;EACAC;EACA,GAAI,OAAOE,aAAa,YAAY,EAAEA,UAAU,GAAG,EAAE;EACrDD;EACAH;EACAM;EACAd,QAAQ;EACRmC,WAAW,IAAIT,KAAKD,IAAI;EACxBE;EACD,CAAC;AAEF,QAAO;EACL1B,IAAI;EACJsB;EACAf;EACAM;EACA,GAAIc,YAAY,EAAEA,WAAW,GAAG,EAAE;EACnC;;;;AC3DH,IAAayB,cAAqE,OAChFE,SACAC,QACkC;CAClC,MAAME,WAAWX,YAAYS,IAAI;AACjC,KAAI,CAACE,UAAU;AACbF,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAkB;;CAG/C,MAAMS,WAAWC,OAAON,IAAIO,IAAIC,QAAQH,YAAY,GAAG,CAACI,MAAM;CAC9D,MAAMC,WAAWJ,OAAON,IAAIO,IAAIC,QAAQG,SAAS,GAAG,CAACF,MAAM;CAC3D,MAAME,QAAQC,OAAOF,SAAS;AAE9B,KAAI,CAACL,YAAY,CAACO,OAAOC,UAAUF,MAAM,IAAIA,QAAQ,GAAG;AACtDX,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAqB;;CAGlD,MAAMkB,UAAU5B,oBAAoBc,KAAKE,SAAS;CAClD,MAAMa,WAAW1B,YAAYW,KAAKE,UAAUY,QAAQ;CAEpD,MAAM,CAACE,eAAeC,eAAe,MAAMhB,QAAQiB,IAAI,CACrDrC,OAAOsC,IAAI,mBAAmBJ,SAAS,EACvClC,OAAOsC,IAAI,iBAAiBJ,SAAS,CACtC,CAAC;AAEF,KAAI,CAACD,QAAQM,IAAI,UAAU,kBAAkB,EAAE;AAC7CpB,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAgB;;CAG7C,MAAMyB,UAAU,MAAML,cAAcM,QAAQ,EAAEC,MAAM,CAAC,EAAEC,KAAKnB,UAAU,EAAEf,4BAA4BwB,SAAS,SAAS,CAAA,EAAG,CAAC,CAACW,MAAM;AACjI,KAAI,CAACJ,SAAS;AACZrB,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAa;;AAG1C,KAAIyB,QAAQjB,WAAW,aAAa;AAClCJ,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAiB;;AAG9C,KAAIe,SAASU,QAAQK,aAAa;AAChC1B,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAsB;;CAGnD,MAAM+B,OAAOlC,gBAAgBM,QAAQ;AACrC,KAAI,CAAC4B,MAAM;AACT3B,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAgB;;CAG7C,MAAMgC,eAAejB,UAAUU,QAAQK,cAAc,IACjDL,QAAQQ,YAAYR,QAAQS,aAAaT,QAAQK,cAAc,KAC/DL,QAAQS;AAEZ,KAAIH,KAAKI,SAASH,cAAc;AAC9B5B,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAmB;;AAGhD,KAAI+B,KAAKI,WAAWH,cAAc;AAChC5B,MAAIG,IAAIC,OAAO,IAAI;AACnB,SAAO;GAAET,IAAI;GAAOC,OAAO;GAAsB;;CAGnD,MAAMoC,iBAAiBhC,IAAIO,IAAIY,IAAI,iBAAiB;CACpD,MAAMc,SAASD,iBAAiB7C,iBAAiBwC,KAAK,GAAGO,KAAAA;AAEzD,KAAIF;MAEEC,WADmBzC,mBAAmBwC,eAAe,EAC1B;AAC7BhC,OAAIG,IAAIC,OAAO,IAAI;AACnB,UAAO;IAAET,IAAI;IAAOC,OAAO;IAAqB;;;AAIpD,OAAMR,oBAAoB4B,eAAeC,YAAY;AAErD,OAAMA,YAAYmB,UAChB;EAAE/B;EAAUM;EAAO,EACnB;EACE0B,MAAM;GACJhC;GACAM;GACAgB;GACAW,MAAMX,KAAKI;GACXE;GACAM,WAAWlB,QAAQkB;GACpB;EACDC,cAAc,EACZC,2BAAW,IAAIC,MAAK,EACtB;EACD,EACD,EAAEC,QAAQ,MACZ,CAAC;AAED3C,KAAIG,IAAIC,OAAO,IAAI;AACnB,QAAO,EAAET,IAAI,MAAM;;;;AC5HrB,IAAaiD,iBAAiB,EAC5BC,YACAC,8BAII;AACJ,SAAQC,KAAUC,KAAUC,SAAc;AAKxC,MAAI,EAJgB,OAAOF,KAAKI,UAAU,oBAAoB,WAC1DC,OAAOL,IAAII,QAAQ,gBAAgB,GACnC,IAEaE,SAAS,2BAA2B,EAAE;AACrDJ,SAAM;AACN;;EAGF,IAAIK,QAAQ;EACZ,MAAMC,SAAmB,EAAE;EAC3B,IAAIE,OAAO;EACX,IAAIC,SAAS;EACb,IAAIC,kBAAwD;EAE5D,MAAMG,qBAAqB,OAAOhB,4BAA4B,YAAYA,0BAA0B,IAChGA,0BACA;EAEJ,MAAMiB,gBAAgB;AACpBhB,OAAIiB,IAAI,QAAQC,OAAO;AACvBlB,OAAIiB,IAAI,OAAOE,MAAM;AACrBnB,OAAIiB,IAAI,SAASG,QAAQ;AACzBpB,OAAIiB,IAAI,WAAWI,UAAU;AAC7B,OAAIT,iBAAiB;AACnBU,iBAAaV,gBAAgB;AAC7BA,sBAAkB;;;EAItB,MAAMW,UAAUC,UAAoB;AAClC,OAAId,KAAM;AACVA,UAAO;AAEPM,YAAS;AAET,OAAIQ,OAAO;AACTtB,SAAKsB,MAAM;AACX;;AAGFxB,OAAIyB,OAAOhB,OAAOiB,OAAOlB,QAAQD,MAAM;AACvCL,SAAM;;EAGR,MAAMgB,UAAUS,UAAe;AAC7B,OAAIjB,KAAM;GACV,MAAMkB,SAASnB,OAAOoB,SAASF,MAAM,GAAGA,QAAQlB,OAAOqB,KAAKH,MAAM;AAClEpB,YAASqB,OAAOG;AAEhB,OAAIxB,QAAQT,YAAY;AACtBY,WAAO;AACPM,aAAS;AACThB,QAAIgC,SAAS;AACb/B,QAAIgC,OAAO,IAAI,CAACC,KAAK;KAAEC,IAAI;KAAOX,OAAO;KAAmB,CAAC;AAC7D;;AAGFhB,UAAO4B,KAAKR,OAAO;AAEnB,OAAI,CAACb,mBAAoB;GAEzB,MAAMsB,MAAMC,KAAKD,KAAK;GAGtB,MAAMM,SAASC,kBADDF,mBADIF,aAAaxC,IAAI,EACSe,oBAAoBsB,IAAI,EAC5BT,OAAOG,QAAQhB,oBAAoBsB,IAAI;AAE/E,OAAIM,SAAS,KAAK,CAAChC,QAAQ;AACzBA,aAAS;AACTX,QAAI6C,OAAO;AACXjC,sBAAkBE,iBAAiB;AACjCF,uBAAkB;AAClBD,cAAS;AACT,SAAID,KAAM;AACV,SAAI;AACFV,UAAI8C,QAAQ;aACN;OAGPH,OAAO;;;EAId,MAAMxB,cAAcI,QAAQ;EAC5B,MAAMH,WAAW2B,QAAiBxB,OAAOwB,IAAI;EAC7C,MAAM1B,kBAAkBE,uBAAO,IAAIyB,MAAM,kBAAkB,CAAC;AAE5DhD,MAAIiD,GAAG,QAAQ/B,OAAO;AACtBlB,MAAIiD,GAAG,OAAO9B,MAAM;AACpBnB,MAAIiD,GAAG,SAAS7B,QAAQ;AACxBpB,MAAIiD,GAAG,WAAW5B,UAAU;;;AAUhC,IAAMiC,oBAAoB;AAC1B,IAAMC,kBAAkB,MAAU;AAElC,IAAMC,mCAAmB,IAAIC,KAA8B;AAC3D,IAAIC,gBAAgB;AAEpB,IAAMlB,gBAAgBxC,QAAqB;CACzC,MAAM2D,cAAc,OAAO3D,KAAK4D,aAAa,WAAW5D,IAAI4D,WAAW;AACvE,KAAID,YAAYE,MAAM,CAAE,QAAOF,YAAYE,MAAM;AAEjD,SADc,OAAO7D,KAAK+D,OAAO,WAAW/D,IAAI+D,KAAK,IACxCF,MAAM,IAAI;;AAGzB,IAAMG,sBAAsB3B,QAAgB;AAC1C,KAAIA,MAAMqB,gBAAgB,IAAQ;AAClCA,iBAAgBrB;AAEhB,KAAImB,iBAAiBS,OAAO,IAAM;AAElC,MAAK,MAAM,CAACC,KAAKzB,UAAUe,iBACzB,KAAInB,MAAMI,MAAMY,aAAaE,gBAC3BC,kBAAiBW,OAAOD,IAAI;;AAKlC,IAAMxB,sBAAsBwB,KAAanD,oBAA4BsB,QAAiC;AACpG2B,oBAAmB3B,IAAI;CAEvB,MAAM+B,WAAWrD,qBAAqBuC;CACtC,MAAMe,WAAWb,iBAAiBc,IAAIJ,IAAI;AAC1C,KAAIG,UAAU;AACZA,WAAShB,aAAahB;AACtBgC,WAASlB,SAASoB,KAAKC,IAAIJ,UAAUC,SAASlB,OAAO;AACrD,SAAOkB;;CAGT,MAAMnE,OAAwB;EAC5BiD,QAAQiB;EACRhB,cAAcf;EACdgB,YAAYhB;EACb;AACDmB,kBAAiBiB,IAAIP,KAAKhE,KAAK;AAC/B,QAAOA;;AAGT,IAAM0C,qBACJH,OACAiC,OACA3D,oBACAsB,QACW;CACX,MAAM+B,WAAWrD,qBAAqBuC;CACtC,MAAMqB,YAAYJ,KAAKK,IAAI,GAAGvC,MAAMI,MAAMW,aAAa;AAEvD,KAAIuB,YAAY,GAAG;AACjBlC,QAAMU,SAASoB,KAAKC,IAAIJ,UAAU3B,MAAMU,SAAUwB,YAAY5D,qBAAsB,IAAK;AACzF0B,QAAMW,eAAef;;AAGvBI,OAAMU,UAAUuB;AAEhB,KAAIjC,MAAMU,UAAU,EAAG,QAAO;AAC9B,QAAOoB,KAAKM,KAAM,CAACpC,MAAMU,SAASpC,qBAAsB,IAAK;;;;AC/J/D,IAAA,mBAAgB0E,QAA0B;CACxC,MAAMC,iBAAiBN,mBAAmB;AAC1CK,KAAIE,IACFH,WACAL,cAAc;EACZU,YAAYP,qBAAqBI,eAAe;EAChDI,yBAAyBT,kCAAiC;EAC3D,CACH,CAAC;AAEDI,KAAIM,KAAKP,WAAmBP,WAAW;AACvCQ,KAAIO,IAAIR,YAAoBN,YAAY;AACxCO,KAAIS,IAAIV,aAAqBR,UAAU;AACvCS,KAAIM,KAAKP,eAAuBT,eAAe"}
|