@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.
@@ -0,0 +1,107 @@
1
+ import { queue } from "@rpcbase/worker";
2
+ const processorsById = /* @__PURE__ */ Object.create(null);
3
+ const uploadPostProcessorTaskName = "rb-upload-post-processors";
4
+ const normalizeProcessorId = (value) => typeof value === "string" ? value.trim() : "";
5
+ const normalizeProcessorVersion = (value) => {
6
+ if (typeof value !== "number") return void 0;
7
+ if (!Number.isInteger(value) || value < 1) return void 0;
8
+ return value;
9
+ };
10
+ const registerUploadPostProcessor = (processor) => {
11
+ const normalizedId = normalizeProcessorId(processor.id);
12
+ if (!normalizedId) {
13
+ throw new Error("Upload post processor id is required.");
14
+ }
15
+ const normalizedVersion = normalizeProcessorVersion(processor.version);
16
+ processorsById[normalizedId] = {
17
+ ...processor,
18
+ id: normalizedId,
19
+ ...normalizedVersion ? {
20
+ version: normalizedVersion
21
+ } : {}
22
+ };
23
+ };
24
+ const registerUploadProcessor = registerUploadPostProcessor;
25
+ const unregisterUploadPostProcessor = (id) => {
26
+ const normalizedId = normalizeProcessorId(id);
27
+ if (!normalizedId) return;
28
+ delete processorsById[normalizedId];
29
+ };
30
+ const unregisterUploadProcessor = unregisterUploadPostProcessor;
31
+ const clearUploadPostProcessors = () => {
32
+ for (const id of Object.keys(processorsById)) {
33
+ delete processorsById[id];
34
+ }
35
+ };
36
+ const clearUploadProcessors = clearUploadPostProcessors;
37
+ const getUploadPostProcessors = () => Object.values(processorsById);
38
+ const getUploadProcessors = getUploadPostProcessors;
39
+ const runUploadPostProcessors = async (ctx) => {
40
+ const processors = getUploadPostProcessors();
41
+ if (!processors.length) return;
42
+ for (const processor of processors) {
43
+ if (processor.match) {
44
+ try {
45
+ if (!processor.match(ctx)) continue;
46
+ } catch (error) {
47
+ console.error("Upload post processor failed", {
48
+ processorId: processor.id,
49
+ processorVersion: processor.version,
50
+ tenantId: ctx.tenantId,
51
+ uploadId: ctx.uploadId,
52
+ fileId: ctx.fileId,
53
+ stage: "match",
54
+ error
55
+ });
56
+ continue;
57
+ }
58
+ }
59
+ try {
60
+ await processor.process(ctx);
61
+ } catch (error) {
62
+ console.error("Upload post processor failed", {
63
+ processorId: processor.id,
64
+ processorVersion: processor.version,
65
+ tenantId: ctx.tenantId,
66
+ uploadId: ctx.uploadId,
67
+ fileId: ctx.fileId,
68
+ stage: "process",
69
+ error
70
+ });
71
+ }
72
+ }
73
+ };
74
+ let isUploadPostProcessorTaskRegistered = false;
75
+ const registerUploadPostProcessorTask = () => {
76
+ if (isUploadPostProcessorTaskRegistered) return;
77
+ queue.registerTask(uploadPostProcessorTaskName, async (payload) => {
78
+ await runUploadPostProcessors(payload);
79
+ });
80
+ isUploadPostProcessorTaskRegistered = true;
81
+ };
82
+ const enqueueUploadPostProcessors = async (ctx) => {
83
+ await queue.add(uploadPostProcessorTaskName, ctx, {
84
+ attempts: 3,
85
+ backoff: {
86
+ type: "exponential",
87
+ delay: 5e3
88
+ },
89
+ removeOnComplete: true,
90
+ removeOnFail: false
91
+ });
92
+ };
93
+ export {
94
+ clearUploadProcessors as a,
95
+ getUploadProcessors as b,
96
+ clearUploadPostProcessors as c,
97
+ registerUploadPostProcessorTask as d,
98
+ enqueueUploadPostProcessors as e,
99
+ registerUploadProcessor as f,
100
+ getUploadPostProcessors as g,
101
+ runUploadPostProcessors as h,
102
+ unregisterUploadProcessor as i,
103
+ uploadPostProcessorTaskName as j,
104
+ registerUploadPostProcessor as r,
105
+ unregisterUploadPostProcessor as u
106
+ };
107
+ //# sourceMappingURL=postProcessors-D27fGZP0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postProcessors-D27fGZP0.js","sources":["../src/uploads/api/file-uploads/postProcessors.ts"],"sourcesContent":["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\nlet isUploadPostProcessorTaskRegistered = false\n\nexport const registerUploadPostProcessorTask = (): void => {\n if (isUploadPostProcessorTaskRegistered) return\n\n queue.registerTask(uploadPostProcessorTaskName, async (payload) => {\n await runUploadPostProcessors(payload as UploadPostProcessorContext)\n })\n isUploadPostProcessorTaskRegistered = true\n}\n\nexport const enqueueUploadPostProcessors = async (ctx: UploadPostProcessorContext): Promise<void> => {\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"],"names":["processorsById","Object","create","uploadPostProcessorTaskName","normalizeProcessorId","value","trim","normalizeProcessorVersion","undefined","Number","isInteger","registerUploadPostProcessor","processor","normalizedId","id","Error","normalizedVersion","version","registerUploadProcessor","unregisterUploadPostProcessor","unregisterUploadProcessor","clearUploadPostProcessors","keys","clearUploadProcessors","getUploadPostProcessors","values","getUploadProcessors","runUploadPostProcessors","ctx","processors","length","match","error","console","processorId","processorVersion","tenantId","uploadId","fileId","stage","process","isUploadPostProcessorTaskRegistered","registerUploadPostProcessorTask","queue","registerTask","payload","enqueueUploadPostProcessors","add","attempts","backoff","type","delay","removeOnComplete","removeOnFail"],"mappings":";AAyBA,MAAMA,iBAAsDC,uBAAOC,OAAO,IAAI;AACvE,MAAMC,8BAA8B;AAE3C,MAAMC,uBAAuBA,CAACC,UAA4B,OAAOA,UAAU,WAAWA,MAAMC,SAAS;AAErG,MAAMC,4BAA4BA,CAACF,UAAuC;AACxE,MAAI,OAAOA,UAAU,SAAU,QAAOG;AACtC,MAAI,CAACC,OAAOC,UAAUL,KAAK,KAAKA,QAAQ,EAAG,QAAOG;AAClD,SAAOH;AACT;AAEO,MAAMM,8BAA8BA,CAACC,cAAyC;AACnF,QAAMC,eAAeT,qBAAqBQ,UAAUE,EAAE;AACtD,MAAI,CAACD,cAAc;AACjB,UAAM,IAAIE,MAAM,uCAAuC;AAAA,EACzD;AAEA,QAAMC,oBAAoBT,0BAA0BK,UAAUK,OAAO;AAErEjB,iBAAea,YAAY,IAAI;AAAA,IAC7B,GAAGD;AAAAA,IACHE,IAAID;AAAAA,IACJ,GAAIG,oBAAoB;AAAA,MAAEC,SAASD;AAAAA,IAAAA,IAAsB,CAAA;AAAA,EAAC;AAE9D;AAEO,MAAME,0BAA0BP;AAEhC,MAAMQ,gCAAgCA,CAACL,OAAqB;AACjE,QAAMD,eAAeT,qBAAqBU,EAAE;AAC5C,MAAI,CAACD,aAAc;AACnB,SAAOb,eAAea,YAAY;AACpC;AAEO,MAAMO,4BAA4BD;AAElC,MAAME,4BAA4BA,MAAY;AACnD,aAAWP,MAAMb,OAAOqB,KAAKtB,cAAc,GAAG;AAC5C,WAAOA,eAAec,EAAE;AAAA,EAC1B;AACF;AAEO,MAAMS,wBAAwBF;AAE9B,MAAMG,0BAA0BA,MAA6BvB,OAAOwB,OAAOzB,cAAc;AAEzF,MAAM0B,sBAAsBF;AAE5B,MAAMG,0BAA0B,OAAOC,QAAmD;AAC/F,QAAMC,aAAaL,wBAAAA;AACnB,MAAI,CAACK,WAAWC,OAAQ;AAExB,aAAWlB,aAAaiB,YAAY;AAClC,QAAIjB,UAAUmB,OAAO;AACnB,UAAI;AACF,YAAI,CAACnB,UAAUmB,MAAMH,GAAG,EAAG;AAAA,MAC7B,SAASI,OAAO;AACdC,gBAAQD,MAAM,gCAAgC;AAAA,UAC5CE,aAAatB,UAAUE;AAAAA,UACvBqB,kBAAkBvB,UAAUK;AAAAA,UAC5BmB,UAAUR,IAAIQ;AAAAA,UACdC,UAAUT,IAAIS;AAAAA,UACdC,QAAQV,IAAIU;AAAAA,UACZC,OAAO;AAAA,UACPP;AAAAA,QAAAA,CACD;AACD;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AACF,YAAMpB,UAAU4B,QAAQZ,GAAG;AAAA,IAC7B,SAASI,OAAO;AACdC,cAAQD,MAAM,gCAAgC;AAAA,QAC5CE,aAAatB,UAAUE;AAAAA,QACvBqB,kBAAkBvB,UAAUK;AAAAA,QAC5BmB,UAAUR,IAAIQ;AAAAA,QACdC,UAAUT,IAAIS;AAAAA,QACdC,QAAQV,IAAIU;AAAAA,QACZC,OAAO;AAAA,QACPP;AAAAA,MAAAA,CACD;AAAA,IACH;AAAA,EACF;AACF;AAEA,IAAIS,sCAAsC;AAEnC,MAAMC,kCAAkCA,MAAY;AACzD,MAAID,oCAAqC;AAEzCE,QAAMC,aAAazC,6BAA6B,OAAO0C,YAAY;AACjE,UAAMlB,wBAAwBkB,OAAqC;AAAA,EACrE,CAAC;AACDJ,wCAAsC;AACxC;AAEO,MAAMK,8BAA8B,OAAOlB,QAAmD;AACnG,QAAMe,MAAMI,IAAI5C,6BAA6ByB,KAAK;AAAA,IAChDoB,UAAU;AAAA,IACVC,SAAS;AAAA,MAAEC,MAAM;AAAA,MAAeC,OAAO;AAAA,IAAA;AAAA,IACvCC,kBAAkB;AAAA,IAClBC,cAAc;AAAA,EAAA,CACf;AACH;"}
@@ -0,0 +1,104 @@
1
+ import { createHash } from "node:crypto";
2
+ import { buildAbilityFromSession, getAccessibleByQuery } from "@rpcbase/db/acl";
3
+ const DEFAULT_CHUNK_SIZE_BYTES = 5 * 1024 * 1024;
4
+ const MAX_CHUNK_SIZE_BYTES = 15 * 1024 * 1024;
5
+ const DEFAULT_MAX_CLIENT_BYTES_PER_SECOND = 10 * 1024 * 1024;
6
+ const DEFAULT_SESSION_TTL_S = 60 * 60 * 24;
7
+ const ensuredIndexDbNames = /* @__PURE__ */ new Set();
8
+ const parseOptionalPositiveInt = (rawValue) => {
9
+ if (typeof rawValue !== "string") return null;
10
+ const normalized = rawValue.trim();
11
+ if (!normalized) return null;
12
+ const parsed = Number(normalized);
13
+ if (!Number.isFinite(parsed) || parsed <= 0) return null;
14
+ return Math.floor(parsed);
15
+ };
16
+ const getChunkSizeBytes = () => {
17
+ const configured = parseOptionalPositiveInt(process.env.RB_UPLOAD_CHUNK_SIZE_BYTES);
18
+ const resolved = configured ?? DEFAULT_CHUNK_SIZE_BYTES;
19
+ return Math.min(MAX_CHUNK_SIZE_BYTES, resolved);
20
+ };
21
+ const getMaxClientUploadBytesPerSecond = () => {
22
+ const configured = parseOptionalPositiveInt(process.env.RB_UPLOAD_MAX_CLIENT_BYTES_PER_SECOND);
23
+ return configured ?? DEFAULT_MAX_CLIENT_BYTES_PER_SECOND;
24
+ };
25
+ const getSessionTtlMs = () => {
26
+ const ttlSeconds = parseOptionalPositiveInt(process.env.RB_UPLOAD_SESSION_TTL_S) ?? DEFAULT_SESSION_TTL_S;
27
+ return ttlSeconds * 1e3;
28
+ };
29
+ const getRawBodyLimitBytes = (chunkSizeBytes) => chunkSizeBytes + 1024 * 1024;
30
+ const getBucketName = () => (process.env.RB_FILESYSTEM_BUCKET_NAME ?? "").trim() || "fs";
31
+ const getUserId = (ctx) => {
32
+ const raw = ctx.req.session?.user?.id;
33
+ if (typeof raw !== "string") return null;
34
+ const normalized = raw.trim();
35
+ return normalized ? normalized : null;
36
+ };
37
+ const getTenantId = (ctx) => {
38
+ const rawSession = ctx.req.session?.user?.currentTenantId;
39
+ const sessionTenantId = typeof rawSession === "string" ? rawSession.trim() : "";
40
+ return sessionTenantId || null;
41
+ };
42
+ const computeSha256Hex = (data) => createHash("sha256").update(data).digest("hex");
43
+ const normalizeSha256Hex = (value) => value.trim().toLowerCase();
44
+ const getModelCtx = (_ctx, tenantId, ability) => ({
45
+ req: {
46
+ session: {
47
+ user: {
48
+ currentTenantId: tenantId
49
+ }
50
+ }
51
+ },
52
+ ability
53
+ });
54
+ const toBufferPayload = (payload) => {
55
+ if (Buffer.isBuffer(payload)) return payload;
56
+ if (payload instanceof Uint8Array) return Buffer.from(payload);
57
+ return null;
58
+ };
59
+ const ensureUploadIndexes = async (UploadSession, UploadChunk) => {
60
+ const dbName = String(UploadSession?.db?.name ?? "");
61
+ if (dbName && ensuredIndexDbNames.has(dbName)) return;
62
+ await Promise.all([UploadSession.createIndexes(), UploadChunk.createIndexes()]);
63
+ if (dbName) ensuredIndexDbNames.add(dbName);
64
+ };
65
+ const normalizeUploadKey = (raw) => {
66
+ if (typeof raw !== "string") return null;
67
+ const normalized = raw.trim();
68
+ return normalized ? normalized : null;
69
+ };
70
+ const getUploadKeyHash = (ctx) => {
71
+ const uploadKey = normalizeUploadKey(ctx.req.get("X-Upload-Key"));
72
+ if (!uploadKey) return null;
73
+ return computeSha256Hex(Buffer.from(uploadKey));
74
+ };
75
+ const buildUploadsAbility = (ctx, tenantId) => {
76
+ const uploadKeyHash = getUploadKeyHash(ctx);
77
+ const claims = uploadKeyHash ? {
78
+ uploadKeyHash
79
+ } : void 0;
80
+ return buildAbilityFromSession({
81
+ tenantId,
82
+ session: ctx.req.session,
83
+ claims
84
+ });
85
+ };
86
+ const getUploadSessionAccessQuery = (ability, action) => getAccessibleByQuery(ability, action, "RBUploadSession");
87
+ export {
88
+ getTenantId as a,
89
+ buildUploadsAbility as b,
90
+ getUploadSessionAccessQuery as c,
91
+ getModelCtx as d,
92
+ ensureUploadIndexes as e,
93
+ getUserId as f,
94
+ getBucketName as g,
95
+ getChunkSizeBytes as h,
96
+ getSessionTtlMs as i,
97
+ computeSha256Hex as j,
98
+ getMaxClientUploadBytesPerSecond as k,
99
+ getRawBodyLimitBytes as l,
100
+ getUploadKeyHash as m,
101
+ normalizeSha256Hex as n,
102
+ toBufferPayload as t
103
+ };
104
+ //# sourceMappingURL=shared-CJrm9Wjp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-CJrm9Wjp.js","sources":["../src/uploads/api/file-uploads/shared.ts"],"sourcesContent":["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"],"names":["DEFAULT_CHUNK_SIZE_BYTES","MAX_CHUNK_SIZE_BYTES","DEFAULT_MAX_CLIENT_BYTES_PER_SECOND","DEFAULT_SESSION_TTL_S","ensuredIndexDbNames","Set","parseOptionalPositiveInt","rawValue","normalized","trim","parsed","Number","isFinite","Math","floor","getChunkSizeBytes","configured","process","env","RB_UPLOAD_CHUNK_SIZE_BYTES","resolved","min","getMaxClientUploadBytesPerSecond","RB_UPLOAD_MAX_CLIENT_BYTES_PER_SECOND","getSessionTtlMs","ttlSeconds","RB_UPLOAD_SESSION_TTL_S","getRawBodyLimitBytes","chunkSizeBytes","getBucketName","RB_FILESYSTEM_BUCKET_NAME","getUserId","ctx","raw","req","session","user","id","getTenantId","rawSession","currentTenantId","sessionTenantId","computeSha256Hex","data","createHash","update","digest","normalizeSha256Hex","value","toLowerCase","getModelCtx","_ctx","tenantId","ability","toBufferPayload","payload","Buffer","isBuffer","Uint8Array","from","ensureUploadIndexes","UploadSession","UploadChunk","dbName","String","db","name","has","Promise","all","createIndexes","add","normalizeUploadKey","getUploadKeyHash","uploadKey","get","buildUploadsAbility","uploadKeyHash","claims","undefined","buildAbilityFromSession","getUploadSessionAccessQuery","action","getAccessibleByQuery"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export {};
1
+ export declare const registerImageVariantsPostProcessor: () => void;
2
2
  //# sourceMappingURL=imageVariantsPostProcessor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imageVariantsPostProcessor.d.ts","sourceRoot":"","sources":["../../../../src/uploads/api/file-uploads/imageVariantsPostProcessor.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"imageVariantsPostProcessor.d.ts","sourceRoot":"","sources":["../../../../src/uploads/api/file-uploads/imageVariantsPostProcessor.ts"],"names":[],"mappings":"AAiMA,eAAO,MAAM,kCAAkC,QAAO,IAKrD,CAAA"}
@@ -28,5 +28,6 @@ export declare const clearUploadProcessors: () => void;
28
28
  export declare const getUploadPostProcessors: () => UploadPostProcessor[];
29
29
  export declare const getUploadProcessors: () => UploadPostProcessor[];
30
30
  export declare const runUploadPostProcessors: (ctx: UploadPostProcessorContext) => Promise<void>;
31
+ export declare const registerUploadPostProcessorTask: () => void;
31
32
  export declare const enqueueUploadPostProcessors: (ctx: UploadPostProcessorContext) => Promise<void>;
32
33
  //# sourceMappingURL=postProcessors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"postProcessors.d.ts","sourceRoot":"","sources":["../../../../src/uploads/api/file-uploads/postProcessors.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,OAAO,CAAA;IACpD,OAAO,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CACzE,CAAA;AAGD,eAAO,MAAM,2BAA2B,8BAA8B,CAAA;AAUtE,eAAO,MAAM,2BAA2B,GAAI,WAAW,mBAAmB,KAAG,IAa5E,CAAA;AAED,eAAO,MAAM,uBAAuB,cAfmB,mBAAmB,KAAG,IAeX,CAAA;AAElE,eAAO,MAAM,6BAA6B,GAAI,IAAI,MAAM,KAAG,IAI1D,CAAA;AAED,eAAO,MAAM,yBAAyB,OANY,MAAM,KAAG,IAMW,CAAA;AAEtE,eAAO,MAAM,yBAAyB,QAAO,IAI5C,CAAA;AAED,eAAO,MAAM,qBAAqB,QANW,IAMiB,CAAA;AAE9D,eAAO,MAAM,uBAAuB,QAAO,mBAAmB,EAAmC,CAAA;AAEjG,eAAO,MAAM,mBAAmB,QAFW,mBAAmB,EAEJ,CAAA;AAE1D,eAAO,MAAM,uBAAuB,GAAU,KAAK,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAoC3F,CAAA;AAMD,eAAO,MAAM,2BAA2B,GAAU,KAAK,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAS/F,CAAA"}
1
+ {"version":3,"file":"postProcessors.d.ts","sourceRoot":"","sources":["../../../../src/uploads/api/file-uploads/postProcessors.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,OAAO,CAAA;IACpD,OAAO,EAAE,CAAC,GAAG,EAAE,0BAA0B,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;CACzE,CAAA;AAGD,eAAO,MAAM,2BAA2B,8BAA8B,CAAA;AAUtE,eAAO,MAAM,2BAA2B,GAAI,WAAW,mBAAmB,KAAG,IAa5E,CAAA;AAED,eAAO,MAAM,uBAAuB,cAfmB,mBAAmB,KAAG,IAeX,CAAA;AAElE,eAAO,MAAM,6BAA6B,GAAI,IAAI,MAAM,KAAG,IAI1D,CAAA;AAED,eAAO,MAAM,yBAAyB,OANY,MAAM,KAAG,IAMW,CAAA;AAEtE,eAAO,MAAM,yBAAyB,QAAO,IAI5C,CAAA;AAED,eAAO,MAAM,qBAAqB,QANW,IAMiB,CAAA;AAE9D,eAAO,MAAM,uBAAuB,QAAO,mBAAmB,EAAmC,CAAA;AAEjG,eAAO,MAAM,mBAAmB,QAFW,mBAAmB,EAEJ,CAAA;AAE1D,eAAO,MAAM,uBAAuB,GAAU,KAAK,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAoC3F,CAAA;AAID,eAAO,MAAM,+BAA+B,QAAO,IAOlD,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAU,KAAK,0BAA0B,KAAG,OAAO,CAAC,IAAI,CAO/F,CAAA"}
@@ -27,5 +27,6 @@ export declare const isHeifUpload: ({ filename, clientMimeType, sniff }: UploadF
27
27
  export declare const toWebpFilename: (filename: string) => string;
28
28
  export declare const getSharpHeifSupportDiagnostic: () => string;
29
29
  export declare const convertHeifToWebp: (input: Buffer, payload: Pick<ConvertHeifToWebpTaskPayload, "filename" | "mimeType">) => Promise<ConvertHeifToWebpTaskResult>;
30
+ export declare const registerConvertHeifToWebpTask: () => void;
30
31
  export declare const convertHeifToWebpProcessor: UploadFileProcessor;
31
32
  //# sourceMappingURL=convertHeifToWebp.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"convertHeifToWebp.d.ts","sourceRoot":"","sources":["../../../../../src/uploads/api/file-uploads/processors/convertHeifToWebp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAoB9E,eAAO,MAAM,yBAAyB,mCAAmC,CAAA;AAEzE,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,YAAY,CAAA;IACtB,QAAQ,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,cAAc,EAAE,MAAM,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;KACvB,CAAA;CACF,CAAA;AAED,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,cAAc;QACtB,gCAAgC,EAAE,4BAA4B,CAAA;KAC/D;CACF;AAyBD,eAAO,MAAM,kBAAkB,GAAI,8BAA8B,IAAI,CAAC,0BAA0B,EAAE,UAAU,GAAG,gBAAgB,CAAC,KAAG,OAC5C,CAAA;AAEvF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,OAAsE,CAAA;AAExH,eAAO,MAAM,YAAY,GAAI,qCAAqC,0BAA0B,KAAG,OACjB,CAAA;AAE9E,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAKjD,CAAA;AAcD,eAAO,MAAM,6BAA6B,QAAO,MAQhD,CAAA;AAkBD,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,SAAS,IAAI,CAAC,4BAA4B,EAAE,UAAU,GAAG,UAAU,CAAC,KACnE,OAAO,CAAC,2BAA2B,CAqBrC,CAAA;AAoDD,eAAO,MAAM,0BAA0B,EAAE,mBAqBxC,CAAA"}
1
+ {"version":3,"file":"convertHeifToWebp.d.ts","sourceRoot":"","sources":["../../../../../src/uploads/api/file-uploads/processors/convertHeifToWebp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAoB9E,eAAO,MAAM,yBAAyB,mCAAmC,CAAA;AAEzE,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,YAAY,CAAA;IACtB,QAAQ,EAAE;QACR,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,cAAc,EAAE,MAAM,CAAA;QACtB,cAAc,EAAE,MAAM,CAAA;KACvB,CAAA;CACF,CAAA;AAED,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,cAAc;QACtB,gCAAgC,EAAE,4BAA4B,CAAA;KAC/D;CACF;AAyBD,eAAO,MAAM,kBAAkB,GAAI,8BAA8B,IAAI,CAAC,0BAA0B,EAAE,UAAU,GAAG,gBAAgB,CAAC,KAAG,OAC5C,CAAA;AAEvF,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,KAAG,OAAsE,CAAA;AAExH,eAAO,MAAM,YAAY,GAAI,qCAAqC,0BAA0B,KAAG,OACjB,CAAA;AAE9E,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,KAAG,MAKjD,CAAA;AAcD,eAAO,MAAM,6BAA6B,QAAO,MAQhD,CAAA;AAkBD,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,SAAS,IAAI,CAAC,4BAA4B,EAAE,UAAU,GAAG,UAAU,CAAC,KACnE,OAAO,CAAC,2BAA2B,CAqBrC,CAAA;AAUD,eAAO,MAAM,6BAA6B,QAAO,IAKhD,CAAA;AA4CD,eAAO,MAAM,0BAA0B,EAAE,mBAqBxC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare const registerUploadWorkerTasks: () => void;
2
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/uploads/worker.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,yBAAyB,QAAO,IAI5C,CAAA"}
@@ -0,0 +1,176 @@
1
+ import { getTenantFilesystemDb } from "@rpcbase/db";
2
+ import { GridFSBucket, ObjectId } from "mongodb";
3
+ import sharp from "sharp";
4
+ import { r as registerUploadPostProcessor, d as registerUploadPostProcessorTask } from "../postProcessors-D27fGZP0.js";
5
+ import { g as getBucketName } from "../shared-CJrm9Wjp.js";
6
+ import { r as registerConvertHeifToWebpTask } from "../convertHeifToWebp-C-DGXZ2k.js";
7
+ const IMAGE_VARIANTS_PROCESSOR_ID = "rb-image-variants";
8
+ const IMAGE_VARIANTS_VERSION = 1;
9
+ const IMAGE_VARIANT_WIDTHS = [320, 640, 960, 1600];
10
+ const IMAGE_VARIANT_QUALITY = 82;
11
+ const IMAGE_VARIANT_MIME_TYPE = "image/webp";
12
+ const IMAGE_VARIANT_FORMAT = "webp";
13
+ const IMAGE_VARIANT_MAX_INPUT_BYTES = 32 * 1024 * 1024;
14
+ const IMAGE_VARIANT_MAX_INPUT_PIXELS = 128 * 1024 * 1024;
15
+ const supportedImageMimeTypes = /* @__PURE__ */ new Set(["image/avif", "image/heic", "image/heif", "image/jpeg", "image/png", "image/webp"]);
16
+ const normalizeMimeType = (value) => value.trim().toLowerCase();
17
+ const toObjectId = (value) => {
18
+ try {
19
+ return new ObjectId(value);
20
+ } catch {
21
+ return null;
22
+ }
23
+ };
24
+ const readGridFsFile = async (bucket, fileId) => new Promise((resolve, reject) => {
25
+ const chunks = [];
26
+ const stream = bucket.openDownloadStream(fileId);
27
+ stream.on("data", (chunk) => {
28
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
29
+ });
30
+ stream.once("error", reject);
31
+ stream.once("end", () => resolve(Buffer.concat(chunks)));
32
+ });
33
+ const writeGridFsFile = async (bucket, filename, data, metadata) => new Promise((resolve, reject) => {
34
+ const stream = bucket.openUploadStream(filename, {
35
+ metadata
36
+ });
37
+ stream.once("error", reject);
38
+ stream.once("finish", () => resolve(String(stream.id ?? "")));
39
+ stream.end(data);
40
+ });
41
+ const imageVariantsPostProcessor = {
42
+ id: IMAGE_VARIANTS_PROCESSOR_ID,
43
+ version: IMAGE_VARIANTS_VERSION,
44
+ match: ({
45
+ mimeType,
46
+ metadata
47
+ }) => {
48
+ if (typeof metadata.variantOf === "string") return false;
49
+ return supportedImageMimeTypes.has(normalizeMimeType(mimeType));
50
+ },
51
+ process: async ({
52
+ tenantId,
53
+ fileId,
54
+ filename,
55
+ isPublic,
56
+ userId,
57
+ ownerKeyHash,
58
+ totalSize
59
+ }) => {
60
+ const originalObjectId = toObjectId(fileId);
61
+ if (!originalObjectId) return;
62
+ const fsDb = await getTenantFilesystemDb(tenantId);
63
+ const nativeDb = fsDb.db;
64
+ if (!nativeDb) return;
65
+ const bucketName = getBucketName();
66
+ const filesCollection = nativeDb.collection(`${bucketName}.files`);
67
+ const existingFile = await filesCollection.findOne({
68
+ _id: originalObjectId
69
+ });
70
+ if (!existingFile) return;
71
+ const existingImageMetadata = existingFile && typeof existingFile.metadata === "object" && existingFile.metadata ? existingFile.metadata.image : null;
72
+ if (existingImageMetadata && typeof existingImageMetadata === "object" && existingImageMetadata.variantsStatus === "done" && existingImageMetadata.variantsVersion === IMAGE_VARIANTS_VERSION) {
73
+ return;
74
+ }
75
+ const markVariantsSkipped = async (reason) => {
76
+ await filesCollection.updateOne({
77
+ _id: originalObjectId
78
+ }, {
79
+ $set: {
80
+ "metadata.image.variantsStatus": "skipped",
81
+ "metadata.image.variantsVersion": IMAGE_VARIANTS_VERSION,
82
+ "metadata.image.variantsSkippedReason": reason
83
+ },
84
+ $unset: {
85
+ "metadata.image.variants": ""
86
+ }
87
+ });
88
+ };
89
+ const existingFileLength = typeof existingFile.length === "number" ? existingFile.length : null;
90
+ const sourceBytes = existingFileLength ?? totalSize;
91
+ if (sourceBytes > IMAGE_VARIANT_MAX_INPUT_BYTES) {
92
+ await markVariantsSkipped("source_too_large");
93
+ return;
94
+ }
95
+ const bucket = new GridFSBucket(nativeDb, {
96
+ bucketName
97
+ });
98
+ const source = await readGridFsFile(bucket, originalObjectId);
99
+ const metadata = await sharp(source, {
100
+ limitInputPixels: IMAGE_VARIANT_MAX_INPUT_PIXELS
101
+ }).metadata();
102
+ if (!metadata.width || !metadata.height) {
103
+ await markVariantsSkipped("missing_dimensions");
104
+ return;
105
+ }
106
+ const targetWidths = IMAGE_VARIANT_WIDTHS.filter((width) => width < metadata.width);
107
+ const variants = {};
108
+ for (const width of targetWidths) {
109
+ const output = await sharp(source, {
110
+ limitInputPixels: IMAGE_VARIANT_MAX_INPUT_PIXELS
111
+ }).rotate().resize({
112
+ width,
113
+ withoutEnlargement: true
114
+ }).webp({
115
+ quality: IMAGE_VARIANT_QUALITY,
116
+ effort: 4
117
+ }).toBuffer({
118
+ resolveWithObject: true
119
+ });
120
+ const variantFileId = await writeGridFsFile(bucket, `${filename}.${width}.${IMAGE_VARIANT_FORMAT}`, output.data, {
121
+ mimeType: IMAGE_VARIANT_MIME_TYPE,
122
+ totalSize: output.data.length,
123
+ variantOf: fileId,
124
+ variantWidth: width,
125
+ variantFormat: IMAGE_VARIANT_FORMAT,
126
+ variantsVersion: IMAGE_VARIANTS_VERSION,
127
+ ...typeof isPublic === "boolean" ? {
128
+ isPublic
129
+ } : {},
130
+ ...userId ? {
131
+ userId
132
+ } : {},
133
+ ...ownerKeyHash ? {
134
+ ownerKeyHash
135
+ } : {}
136
+ });
137
+ if (!variantFileId) continue;
138
+ variants[String(width)] = {
139
+ fileId: variantFileId,
140
+ width: output.info.width,
141
+ height: output.info.height,
142
+ mimeType: IMAGE_VARIANT_MIME_TYPE,
143
+ size: output.data.length
144
+ };
145
+ }
146
+ await filesCollection.updateOne({
147
+ _id: originalObjectId
148
+ }, {
149
+ $set: {
150
+ "metadata.image": {
151
+ width: metadata.width,
152
+ height: metadata.height,
153
+ format: metadata.format,
154
+ variantsStatus: Object.keys(variants).length ? "done" : "skipped",
155
+ variantsVersion: IMAGE_VARIANTS_VERSION,
156
+ variants
157
+ }
158
+ }
159
+ });
160
+ }
161
+ };
162
+ let isImageVariantsPostProcessorRegistered = false;
163
+ const registerImageVariantsPostProcessor = () => {
164
+ if (isImageVariantsPostProcessorRegistered) return;
165
+ registerUploadPostProcessor(imageVariantsPostProcessor);
166
+ isImageVariantsPostProcessorRegistered = true;
167
+ };
168
+ const registerUploadWorkerTasks = () => {
169
+ registerConvertHeifToWebpTask();
170
+ registerImageVariantsPostProcessor();
171
+ registerUploadPostProcessorTask();
172
+ };
173
+ export {
174
+ registerUploadWorkerTasks
175
+ };
176
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sources":["../../src/uploads/api/file-uploads/imageVariantsPostProcessor.ts","../../src/uploads/worker.ts"],"sourcesContent":["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\nconst imageVariantsPostProcessor = {\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} satisfies Parameters<typeof registerUploadPostProcessor>[0]\n\nlet isImageVariantsPostProcessorRegistered = false\n\nexport const registerImageVariantsPostProcessor = (): void => {\n if (isImageVariantsPostProcessorRegistered) return\n\n registerUploadPostProcessor(imageVariantsPostProcessor)\n isImageVariantsPostProcessorRegistered = true\n}\n","import { registerImageVariantsPostProcessor } from \"./api/file-uploads/imageVariantsPostProcessor\"\nimport { registerConvertHeifToWebpTask } from \"./api/file-uploads/processors/convertHeifToWebp\"\nimport { registerUploadPostProcessorTask } from \"./api/file-uploads/postProcessors\"\n\n\nexport const registerUploadWorkerTasks = (): void => {\n registerConvertHeifToWebpTask()\n registerImageVariantsPostProcessor()\n registerUploadPostProcessorTask()\n}\n"],"names":["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","Set","normalizeMimeType","value","trim","toLowerCase","toObjectId","ObjectId","readGridFsFile","bucket","fileId","Promise","resolve","reject","chunks","stream","openDownloadStream","on","chunk","push","Buffer","isBuffer","from","once","concat","writeGridFsFile","filename","data","metadata","openUploadStream","String","id","end","imageVariantsPostProcessor","version","match","mimeType","variantOf","has","process","tenantId","isPublic","userId","ownerKeyHash","totalSize","originalObjectId","fsDb","getTenantFilesystemDb","nativeDb","db","bucketName","getBucketName","filesCollection","collection","existingFile","findOne","_id","existingImageMetadata","image","variantsStatus","variantsVersion","markVariantsSkipped","reason","updateOne","$set","$unset","existingFileLength","length","sourceBytes","GridFSBucket","source","sharp","limitInputPixels","width","height","targetWidths","filter","variants","output","rotate","resize","withoutEnlargement","webp","quality","effort","toBuffer","resolveWithObject","variantFileId","variantWidth","variantFormat","info","size","format","Object","keys","isImageVariantsPostProcessorRegistered","registerImageVariantsPostProcessor","registerUploadPostProcessor","registerUploadWorkerTasks","registerConvertHeifToWebpTask","registerUploadPostProcessorTask"],"mappings":";;;;;;AAQA,MAAMA,8BAA8B;AACpC,MAAMC,yBAAyB;AAC/B,MAAMC,uBAAuB,CAAC,KAAK,KAAK,KAAK,IAAI;AACjD,MAAMC,wBAAwB;AAC9B,MAAMC,0BAA0B;AAChC,MAAMC,uBAAuB;AAC7B,MAAMC,gCAAgC,KAAK,OAAO;AAClD,MAAMC,iCAAiC,MAAM,OAAO;AAEpD,MAAMC,0BAA0B,oBAAIC,IAAI,CACtC,cACA,cACA,cACA,cACA,aACA,YAAY,CACb;AAUD,MAAMC,oBAAoBA,CAACC,UAA0BA,MAAMC,KAAAA,EAAOC,YAAAA;AAElE,MAAMC,aAAaA,CAACH,UAAmC;AACrD,MAAI;AACF,WAAO,IAAII,SAASJ,KAAK;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,MAAMK,iBAAiB,OAAOC,QAAsBC,WAAsC,IAAIC,QAAQ,CAACC,SAASC,WAAW;AACzH,QAAMC,SAAmB,CAAA;AACzB,QAAMC,SAASN,OAAOO,mBAAmBN,MAAM;AAE/CK,SAAOE,GAAG,QAASC,CAAAA,UAAU;AAC3BJ,WAAOK,KAAKC,OAAOC,SAASH,KAAK,IAAIA,QAAQE,OAAOE,KAAKJ,KAAK,CAAC;AAAA,EACjE,CAAC;AACDH,SAAOQ,KAAK,SAASV,MAAM;AAC3BE,SAAOQ,KAAK,OAAO,MAAMX,QAAQQ,OAAOI,OAAOV,MAAM,CAAC,CAAC;AACzD,CAAC;AAED,MAAMW,kBAAkB,OACtBhB,QACAiB,UACAC,MACAC,aACoB,IAAIjB,QAAQ,CAACC,SAASC,WAAW;AACrD,QAAME,SAASN,OAAOoB,iBAAiBH,UAAU;AAAA,IAC/CE;AAAAA,EAAAA,CACD;AAEDb,SAAOQ,KAAK,SAASV,MAAM;AAC3BE,SAAOQ,KAAK,UAAU,MAAMX,QAAQkB,OAAQf,OAAuCgB,MAAM,EAAE,CAAC,CAAC;AAC7FhB,SAAOiB,IAAIL,IAAI;AACjB,CAAC;AAED,MAAMM,6BAA6B;AAAA,EACjCF,IAAIvC;AAAAA,EACJ0C,SAASzC;AAAAA,EACT0C,OAAOA,CAAC;AAAA,IAAEC;AAAAA,IAAUR;AAAAA,EAAAA,MAAe;AACjC,QAAI,OAAOA,SAASS,cAAc,SAAU,QAAO;AACnD,WAAOrC,wBAAwBsC,IAAIpC,kBAAkBkC,QAAQ,CAAC;AAAA,EAChE;AAAA,EACAG,SAAS,OAAO;AAAA,IAAEC;AAAAA,IAAU9B;AAAAA,IAAQgB;AAAAA,IAAUe;AAAAA,IAAUC;AAAAA,IAAQC;AAAAA,IAAcC;AAAAA,EAAAA,MAAgB;AAC5F,UAAMC,mBAAmBvC,WAAWI,MAAM;AAC1C,QAAI,CAACmC,iBAAkB;AAEvB,UAAMC,OAAO,MAAMC,sBAAsBP,QAAQ;AACjD,UAAMQ,WAAWF,KAAKG;AACtB,QAAI,CAACD,SAAU;AAEf,UAAME,aAAaC,cAAAA;AACnB,UAAMC,kBAAkBJ,SAASK,WAAW,GAAGH,UAAU,QAAQ;AACjE,UAAMI,eAAe,MAAMF,gBAAgBG,QAAQ;AAAA,MAAEC,KAAKX;AAAAA,IAAAA,CAAkB;AAC5E,QAAI,CAACS,aAAc;AAEnB,UAAMG,wBAAwBH,gBAAgB,OAAOA,aAAa1B,aAAa,YAAY0B,aAAa1B,WACnG0B,aAAa1B,SAAqC8B,QACnD;AAEJ,QACED,yBACA,OAAOA,0BAA0B,YAChCA,sBAAkDE,mBAAmB,UACrEF,sBAAkDG,oBAAoBnE,wBACvE;AACA;AAAA,IACF;AAEA,UAAMoE,sBAAsB,OAAOC,WAAkC;AACnE,YAAMV,gBAAgBW,UACpB;AAAA,QAAEP,KAAKX;AAAAA,MAAAA,GACP;AAAA,QACEmB,MAAM;AAAA,UACJ,iCAAiC;AAAA,UACjC,kCAAkCvE;AAAAA,UAClC,wCAAwCqE;AAAAA,QAAAA;AAAAA,QAE1CG,QAAQ;AAAA,UACN,2BAA2B;AAAA,QAAA;AAAA,MAC7B,CAEJ;AAAA,IACF;AAEA,UAAMC,qBAAqB,OAAOZ,aAAaa,WAAW,WAAWb,aAAaa,SAAS;AAC3F,UAAMC,cAAcF,sBAAsBtB;AAC1C,QAAIwB,cAActE,+BAA+B;AAC/C,YAAM+D,oBAAoB,kBAAkB;AAC5C;AAAA,IACF;AAEA,UAAMpD,SAAS,IAAI4D,aAAarB,UAAU;AAAA,MAAEE;AAAAA,IAAAA,CAAY;AACxD,UAAMoB,SAAS,MAAM9D,eAAeC,QAAQoC,gBAAgB;AAC5D,UAAMjB,WAAW,MAAM2C,MAAMD,QAAQ;AAAA,MAAEE,kBAAkBzE;AAAAA,IAAAA,CAAgC,EAAE6B,SAAAA;AAE3F,QAAI,CAACA,SAAS6C,SAAS,CAAC7C,SAAS8C,QAAQ;AACvC,YAAMb,oBAAoB,oBAAoB;AAC9C;AAAA,IACF;AAEA,UAAMc,eAAejF,qBAAqBkF,OAAQH,CAAAA,UAAUA,QAAQ7C,SAAS6C,KAAK;AAClF,UAAMI,WAA+C,CAAA;AAErD,eAAWJ,SAASE,cAAc;AAChC,YAAMG,SAAS,MAAMP,MAAMD,QAAQ;AAAA,QAAEE,kBAAkBzE;AAAAA,MAAAA,CAAgC,EACpFgF,OAAAA,EACAC,OAAO;AAAA,QAAEP;AAAAA,QAAOQ,oBAAoB;AAAA,MAAA,CAAM,EAC1CC,KAAK;AAAA,QAAEC,SAASxF;AAAAA,QAAuByF,QAAQ;AAAA,MAAA,CAAG,EAClDC,SAAS;AAAA,QAAEC,mBAAmB;AAAA,MAAA,CAAM;AAEvC,YAAMC,gBAAgB,MAAM9D,gBAC1BhB,QACA,GAAGiB,QAAQ,IAAI+C,KAAK,IAAI5E,oBAAoB,IAC5CiF,OAAOnD,MACP;AAAA,QACES,UAAUxC;AAAAA,QACVgD,WAAWkC,OAAOnD,KAAKwC;AAAAA,QACvB9B,WAAW3B;AAAAA,QACX8E,cAAcf;AAAAA,QACdgB,eAAe5F;AAAAA,QACf+D,iBAAiBnE;AAAAA,QACjB,GAAI,OAAOgD,aAAa,YAAY;AAAA,UAAEA;AAAAA,QAAAA,IAAa,CAAA;AAAA,QACnD,GAAIC,SAAS;AAAA,UAAEA;AAAAA,QAAAA,IAAW,CAAA;AAAA,QAC1B,GAAIC,eAAe;AAAA,UAAEA;AAAAA,QAAAA,IAAiB,CAAA;AAAA,MAAC,CAE3C;AAEA,UAAI,CAAC4C,cAAe;AAEpBV,eAAS/C,OAAO2C,KAAK,CAAC,IAAI;AAAA,QACxB/D,QAAQ6E;AAAAA,QACRd,OAAOK,OAAOY,KAAKjB;AAAAA,QACnBC,QAAQI,OAAOY,KAAKhB;AAAAA,QACpBtC,UAAUxC;AAAAA,QACV+F,MAAMb,OAAOnD,KAAKwC;AAAAA,MAAAA;AAAAA,IAEtB;AAEA,UAAMf,gBAAgBW,UACpB;AAAA,MAAEP,KAAKX;AAAAA,IAAAA,GACP;AAAA,MACEmB,MAAM;AAAA,QACJ,kBAAkB;AAAA,UAChBS,OAAO7C,SAAS6C;AAAAA,UAChBC,QAAQ9C,SAAS8C;AAAAA,UACjBkB,QAAQhE,SAASgE;AAAAA,UACjBjC,gBAAgBkC,OAAOC,KAAKjB,QAAQ,EAAEV,SAAS,SAAS;AAAA,UACxDP,iBAAiBnE;AAAAA,UACjBoF;AAAAA,QAAAA;AAAAA,MACF;AAAA,IACF,CAEJ;AAAA,EACF;AACF;AAEA,IAAIkB,yCAAyC;AAEtC,MAAMC,qCAAqCA,MAAY;AAC5D,MAAID,uCAAwC;AAE5CE,8BAA4BhE,0BAA0B;AACtD8D,2CAAyC;AAC3C;ACjMO,MAAMG,4BAA4BA,MAAY;AACnDC,gCAAAA;AACAH,qCAAAA;AACAI,kCAAAA;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../src/uploads.ts"],"names":[],"mappings":"AAAA,OAAO,uCAAuC,CAAA;AAC9C,OAAO,uDAAuD,CAAA;AAG9D,cAAc,kBAAkB,CAAA;AAChC,cAAc,2CAA2C,CAAA"}
1
+ {"version":3,"file":"uploads.d.ts","sourceRoot":"","sources":["../src/uploads.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAA;AAChC,cAAc,2CAA2C,CAAA"}
package/dist/uploads.js CHANGED
@@ -1,16 +1,23 @@
1
- import { q, r, f, u, v, w, x, y, z, A, B, C } from "./uploads-BAxHzidK.js";
1
+ import { c, a, e, g, b, r, d, f, h, u, i, j } from "./postProcessors-D27fGZP0.js";
2
+ const routes = Object.entries({
3
+ .../* @__PURE__ */ Object.assign({ "./api/file-uploads/handler.ts": () => import("./handler-BUjHw_zG.js"), "./api/files/handler.ts": () => import("./handler-F0gFTzvh.js") })
4
+ }).reduce((acc, [path, mod]) => {
5
+ acc[path.replace("./api/", "@rpcbase/server/uploads/api/")] = mod;
6
+ return acc;
7
+ }, {});
2
8
  export {
3
- q as clearUploadPostProcessors,
4
- r as clearUploadProcessors,
5
- f as enqueueUploadPostProcessors,
6
- u as getUploadPostProcessors,
7
- v as getUploadProcessors,
8
- w as registerUploadPostProcessor,
9
- x as registerUploadProcessor,
10
- y as routes,
11
- z as runUploadPostProcessors,
12
- A as unregisterUploadPostProcessor,
13
- B as unregisterUploadProcessor,
14
- C as uploadPostProcessorTaskName
9
+ c as clearUploadPostProcessors,
10
+ a as clearUploadProcessors,
11
+ e as enqueueUploadPostProcessors,
12
+ g as getUploadPostProcessors,
13
+ b as getUploadProcessors,
14
+ r as registerUploadPostProcessor,
15
+ d as registerUploadPostProcessorTask,
16
+ f as registerUploadProcessor,
17
+ routes,
18
+ h as runUploadPostProcessors,
19
+ u as unregisterUploadPostProcessor,
20
+ i as unregisterUploadProcessor,
21
+ j as uploadPostProcessorTaskName
15
22
  };
16
23
  //# sourceMappingURL=uploads.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
1
+ {"version":3,"file":"uploads.js","sources":["../src/uploads/routes.ts"],"sourcesContent":["export const routes = Object.entries({\n ...import.meta.glob(\"./api/**/handler.ts\"),\n}).reduce<Record<string, unknown>>((acc, [path, mod]) => {\n acc[path.replace(\"./api/\", \"@rpcbase/server/uploads/api/\")] = mod\n return acc\n}, {})\n\n"],"names":["routes","Object","entries","import","reduce","acc","path","mod","replace"],"mappings":";AAAO,MAAMA,SAASC,OAAOC,QAAQ;AAAA,EACnC,GAAGC,uBAAAA,OAAAA,EAAAA,iCAAAA,MAAAA,OAAAA,uBAAAA,GAAAA,0BAAAA,MAAAA,OAAAA,uBAAAA,EAAAA,CAAAA;AACL,CAAC,EAAEC,OAAgC,CAACC,KAAK,CAACC,MAAMC,GAAG,MAAM;AACvDF,MAAIC,KAAKE,QAAQ,UAAU,8BAA8B,CAAC,IAAID;AAC9D,SAAOF;AACT,GAAG,CAAA,CAAE;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/server",
3
- "version": "0.550.0",
3
+ "version": "0.552.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"
@@ -23,6 +23,11 @@
23
23
  "import": "./dist/uploads.js",
24
24
  "default": "./dist/uploads.js"
25
25
  },
26
+ "./uploads/worker": {
27
+ "types": "./dist/uploads/worker.d.ts",
28
+ "import": "./dist/uploads/worker.js",
29
+ "default": "./dist/uploads/worker.js"
30
+ },
26
31
  "./notifications": {
27
32
  "types": "./dist/notifications.d.ts",
28
33
  "import": "./dist/notifications.js",