@rpcbase/server 0.600.0 → 0.602.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.
Files changed (50) hide show
  1. package/dist/{email-Co1GNjlT.js → email-CK8NNDQY.js} +48 -24
  2. package/dist/email-CK8NNDQY.js.map +1 -0
  3. package/dist/email.d.ts +9 -0
  4. package/dist/email.d.ts.map +1 -1
  5. package/dist/fileReferences-Ca0tivFd.js +101 -0
  6. package/dist/fileReferences-Ca0tivFd.js.map +1 -0
  7. package/dist/{handler-Fk-5fOSm.js → handler-BUTqP40B.js} +2 -2
  8. package/dist/{handler-Fk-5fOSm.js.map → handler-BUTqP40B.js.map} +1 -1
  9. package/dist/{handler-C92_gJkX.js → handler-BgcIWWMc.js} +2 -2
  10. package/dist/{handler-C92_gJkX.js.map → handler-BgcIWWMc.js.map} +1 -1
  11. package/dist/{handler-CapJTGzc.js → handler-CqSlSCdd.js} +215 -57
  12. package/dist/handler-CqSlSCdd.js.map +1 -0
  13. package/dist/{handler-BqlcQ9sE.js → handler-LRLmxrsg.js} +69 -24
  14. package/dist/handler-LRLmxrsg.js.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +148 -4
  18. package/dist/index.js.map +1 -1
  19. package/dist/initServer.d.ts.map +1 -1
  20. package/dist/notifications.js +2 -2
  21. package/dist/postProcessors-iffHvje4.js.map +1 -1
  22. package/dist/rts/index.js +1 -1
  23. package/dist/{schemas-B2fUvgYo.js → schemas-POKnVn0c.js} +58 -2
  24. package/dist/schemas-POKnVn0c.js.map +1 -0
  25. package/dist/serviceWorker.d.ts +7 -0
  26. package/dist/serviceWorker.d.ts.map +1 -0
  27. package/dist/{shared-DfrVDSp0.js → shared-Zt17vuAT.js} +54 -2
  28. package/dist/shared-Zt17vuAT.js.map +1 -0
  29. package/dist/uploads/api/file-uploads/fileReferences.d.ts +42 -0
  30. package/dist/uploads/api/file-uploads/fileReferences.d.ts.map +1 -0
  31. package/dist/uploads/api/file-uploads/handlers/completeUpload.d.ts.map +1 -1
  32. package/dist/uploads/api/file-uploads/handlers/initUpload.d.ts.map +1 -1
  33. package/dist/uploads/api/file-uploads/imageVariantsPostProcessor.d.ts.map +1 -1
  34. package/dist/uploads/api/file-uploads/index.d.ts +23 -0
  35. package/dist/uploads/api/file-uploads/index.d.ts.map +1 -1
  36. package/dist/uploads/api/file-uploads/postProcessors.d.ts +2 -0
  37. package/dist/uploads/api/file-uploads/postProcessors.d.ts.map +1 -1
  38. package/dist/uploads/api/file-uploads/shared.d.ts +21 -0
  39. package/dist/uploads/api/file-uploads/shared.d.ts.map +1 -1
  40. package/dist/uploads/api/files/handlers/deleteFile.d.ts.map +1 -1
  41. package/dist/uploads/api/files/handlers/getFile.d.ts.map +1 -1
  42. package/dist/uploads/worker.js +3 -2
  43. package/dist/uploads/worker.js.map +1 -1
  44. package/dist/uploads.js +2 -2
  45. package/package.json +1 -1
  46. package/dist/email-Co1GNjlT.js.map +0 -1
  47. package/dist/handler-BqlcQ9sE.js.map +0 -1
  48. package/dist/handler-CapJTGzc.js.map +0 -1
  49. package/dist/schemas-B2fUvgYo.js.map +0 -1
  50. package/dist/shared-DfrVDSp0.js.map +0 -1
@@ -1,4 +1,5 @@
1
- import { d as getUploadKeyHash, i as getBucketName, p as getUserId, u as getTenantId } from "./shared-DfrVDSp0.js";
1
+ import { _ as getUserId, h as getUploadKeyHash, m as getTenantId, s as getBucketName, y as resolveStoredUploadAccessScope } from "./shared-Zt17vuAT.js";
2
+ import { i as findUploadFileReference, r as deleteUploadFileReference } from "./fileReferences-Ca0tivFd.js";
2
3
  import { GridFSBucket, ObjectId } from "mongodb";
3
4
  import { getTenantFilesystemDb } from "@rpcbase/db";
4
5
  //#region src/uploads/api/files/handlers/deleteFile.ts
@@ -45,7 +46,8 @@ var deleteFile = async (_payload, ctx) => {
45
46
  error: "filesystem_db_unavailable"
46
47
  };
47
48
  }
48
- const bucket = new GridFSBucket(nativeDb, { bucketName: getBucketName() });
49
+ const bucketName = getBucketName();
50
+ const bucket = new GridFSBucket(nativeDb, { bucketName });
49
51
  const userId = getUserId(ctx);
50
52
  const uploadKeyHash = getUploadKeyHash(ctx);
51
53
  if (!userId && !uploadKeyHash) {
@@ -55,6 +57,35 @@ var deleteFile = async (_payload, ctx) => {
55
57
  error: "unauthorized"
56
58
  };
57
59
  }
60
+ const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId);
61
+ if (reference) {
62
+ const referenceMetadata = reference;
63
+ const metadataUserId = resolveHeaderString$1(reference.userId);
64
+ const ownerKeyHash = resolveHeaderString$1(reference.ownerKeyHash);
65
+ const accessScope = resolveStoredUploadAccessScope(referenceMetadata);
66
+ if (!Boolean(userId && metadataUserId && userId === metadataUserId) && !Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash) && !(accessScope === "tenant" && Boolean(userId))) {
67
+ ctx.res.status(401);
68
+ return {
69
+ ok: false,
70
+ error: "unauthorized"
71
+ };
72
+ }
73
+ try {
74
+ await deleteUploadFileReference({
75
+ tenantId,
76
+ bucketName,
77
+ referenceId: fileObjectId
78
+ });
79
+ } catch {
80
+ ctx.res.status(500);
81
+ return {
82
+ ok: false,
83
+ error: "delete_failed"
84
+ };
85
+ }
86
+ ctx.res.status(204);
87
+ return { ok: true };
88
+ }
58
89
  const [file] = await bucket.find({ _id: fileObjectId }).limit(1).toArray();
59
90
  if (!file) {
60
91
  ctx.res.status(204);
@@ -62,13 +93,23 @@ var deleteFile = async (_payload, ctx) => {
62
93
  }
63
94
  const metadataUserId = resolveHeaderString$1(file?.metadata?.userId);
64
95
  const ownerKeyHash = resolveHeaderString$1(file?.metadata?.ownerKeyHash);
65
- if (!Boolean(userId && metadataUserId && userId === metadataUserId) && !Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)) {
96
+ const rawMetadata = file?.metadata;
97
+ const fileMetadata = rawMetadata && typeof rawMetadata === "object" ? rawMetadata : {};
98
+ const accessScope = resolveStoredUploadAccessScope(fileMetadata);
99
+ if (!Boolean(userId && metadataUserId && userId === metadataUserId) && !Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash) && !(accessScope === "tenant" && Boolean(userId))) {
66
100
  ctx.res.status(401);
67
101
  return {
68
102
  ok: false,
69
103
  error: "unauthorized"
70
104
  };
71
105
  }
106
+ if (fileMetadata.deduplication && typeof fileMetadata.deduplication === "object") {
107
+ ctx.res.status(409);
108
+ return {
109
+ ok: false,
110
+ error: "file_reference_required"
111
+ };
112
+ }
72
113
  try {
73
114
  const variantIds = (await bucket.find({ "metadata.variantOf": fileObjectId.toHexString() }).toArray()).map((variant) => variant?._id).filter((id) => id instanceof ObjectId);
74
115
  await deleteGridFsFile(bucket, fileObjectId);
@@ -90,15 +131,6 @@ var resolveHeaderString = (value) => {
90
131
  const normalized = value.trim();
91
132
  return normalized ? normalized : null;
92
133
  };
93
- var resolveHeaderBoolean = (value) => {
94
- if (typeof value === "boolean") return value;
95
- if (typeof value !== "string") return null;
96
- const normalized = value.trim().toLowerCase();
97
- if (!normalized) return null;
98
- if (normalized === "true") return true;
99
- if (normalized === "false") return false;
100
- return null;
101
- };
102
134
  var escapeHeaderFilename = (filename) => filename.replace(/[\\"]/g, "_");
103
135
  var parseRequestedWidth = (value) => {
104
136
  if (typeof value !== "string") return null;
@@ -168,28 +200,41 @@ var getFile = async (_payload, ctx) => {
168
200
  ctx.res.status(500).end();
169
201
  return {};
170
202
  }
171
- const bucket = new GridFSBucket(nativeDb, { bucketName: getBucketName() });
172
- const [file] = await bucket.find({ _id: fileObjectId }).limit(1).toArray();
203
+ const bucketName = getBucketName();
204
+ const bucket = new GridFSBucket(nativeDb, { bucketName });
205
+ const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId);
206
+ const blobObjectId = reference?.blobId ?? fileObjectId;
207
+ const [file] = await bucket.find({ _id: blobObjectId }).limit(1).toArray();
173
208
  if (!file) {
174
209
  ctx.res.status(404).end();
175
210
  return {};
176
211
  }
177
- if (!(resolveHeaderBoolean(file?.metadata?.isPublic) ?? false)) {
212
+ const rawMetadata = reference ?? file?.metadata;
213
+ const fileMetadata = rawMetadata && typeof rawMetadata === "object" ? rawMetadata : {};
214
+ const accessScope = resolveStoredUploadAccessScope(fileMetadata);
215
+ if (accessScope !== "public") {
178
216
  const userId = getUserId(ctx);
179
- const uploadKeyHash = getUploadKeyHash(ctx);
180
- const metadataUserId = resolveHeaderString(file?.metadata?.userId);
181
- const ownerKeyHash = resolveHeaderString(file?.metadata?.ownerKeyHash);
182
- if (!Boolean(userId && metadataUserId && userId === metadataUserId) && !Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)) {
183
- ctx.res.status(401).end();
184
- return {};
217
+ if (accessScope === "tenant") {
218
+ if (!userId) {
219
+ ctx.res.status(401).end();
220
+ return {};
221
+ }
222
+ } else {
223
+ const uploadKeyHash = getUploadKeyHash(ctx);
224
+ const metadataUserId = resolveHeaderString(fileMetadata.userId);
225
+ const ownerKeyHash = resolveHeaderString(fileMetadata.ownerKeyHash);
226
+ if (!Boolean(userId && metadataUserId && userId === metadataUserId) && !Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)) {
227
+ ctx.res.status(401).end();
228
+ return {};
229
+ }
185
230
  }
186
231
  }
187
232
  const variantFileObjectId = selectVariantFileId(file, parseRequestedWidth(ctx.req.query?.w), ctx.req.query?.variant);
188
233
  const [variantFile] = variantFileObjectId ? await bucket.find({ _id: variantFileObjectId }).limit(1).toArray() : [];
189
- const selectedFileObjectId = variantFile ? variantFileObjectId : fileObjectId;
234
+ const selectedFileObjectId = variantFile ? variantFileObjectId : blobObjectId;
190
235
  const selectedFile = variantFile ?? file;
191
236
  const mimeType = resolveHeaderString(selectedFile?.metadata?.mimeType) ?? "application/octet-stream";
192
- const filenameSafe = escapeHeaderFilename(resolveHeaderString(selectedFile?.filename) ?? fileIdRaw);
237
+ const filenameSafe = escapeHeaderFilename(resolveHeaderString(reference?.filename ?? selectedFile?.filename) ?? fileIdRaw);
193
238
  const cacheControl = "private, max-age=0, must-revalidate";
194
239
  const md5 = resolveHeaderString(selectedFile?.md5);
195
240
  const uploadDate = selectedFile?.uploadDate instanceof Date ? selectedFile.uploadDate : null;
@@ -242,4 +287,4 @@ var handler_default = (api) => {
242
287
  //#endregion
243
288
  export { handler_default as default };
244
289
 
245
- //# sourceMappingURL=handler-BqlcQ9sE.js.map
290
+ //# sourceMappingURL=handler-LRLmxrsg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-LRLmxrsg.js","names":["ApiHandler","getTenantFilesystemDb","GridFSBucket","ObjectId","deleteUploadFileReference","findUploadFileReference","getBucketName","getTenantId","getUploadKeyHash","getUserId","resolveStoredUploadAccessScope","SessionUser","DeleteResponsePayload","ok","error","resolveHeaderString","value","normalized","trim","isFileNotFoundError","message","Error","String","includes","deleteGridFsFile","bucket","fileId","Promise","delete","deleteFile","Record","_payload","ctx","tenantId","res","status","fileIdRaw","req","params","fileObjectId","fsDb","nativeDb","db","bucketName","userId","uploadKeyHash","reference","referenceMetadata","metadataUserId","ownerKeyHash","accessScope","authorizedByUser","Boolean","authorizedByKey","authorizedByTenant","referenceId","file","find","_id","limit","toArray","metadata","rawMetadata","fileMetadata","deduplication","variants","toHexString","variantIds","map","variant","filter","id","variantId","ApiHandler","getTenantFilesystemDb","GridFSBucket","ObjectId","findUploadFileReference","getBucketName","getTenantId","getUploadKeyHash","getUserId","resolveStoredUploadAccessScope","SessionUser","resolveHeaderString","value","normalized","trim","escapeHeaderFilename","filename","replace","parseRequestedWidth","parsed","Number","isFinite","Math","floor","resolveImageVariants","file","Record","metadata","image","variants","resolveVariantFileId","variant","fileId","selectVariantFileId","requestedWidth","requestedVariant","aliasWidth","toLowerCase","variantFileId","String","targetWidth","widths","Object","keys","map","width","filter","isInteger","sort","a","b","selectedWidth","reduce","selected","selectedDistance","abs","distance","getFile","_payload","ctx","Promise","tenantId","res","status","end","fileIdRaw","req","params","fileObjectId","fsDb","nativeDb","db","bucketName","bucket","reference","blobObjectId","blobId","find","_id","limit","toArray","rawMetadata","fileMetadata","accessScope","userId","uploadKeyHash","metadataUserId","ownerKeyHash","authorizedByUser","Boolean","authorizedByKey","query","w","variantFileObjectId","variantFile","selectedFileObjectId","selectedFile","mimeTypeFromMetadata","mimeType","filenameFromDb","filenameSafe","cacheControl","md5","uploadDate","Date","etagValue","toHexString","length","getTime","etag","ifNoneMatch","headers","candidates","split","includes","setHeader","flushHeaders","method","stream","openDownloadStream","on","destroy","pipe","Route","GetRoute","DeleteRoute"],"sources":["../src/uploads/api/files/handlers/deleteFile.ts","../src/uploads/api/files/handlers/getFile.ts","../src/uploads/api/files/index.ts","../src/uploads/api/files/handler.ts"],"sourcesContent":["import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\n\nimport {\n deleteUploadFileReference,\n findUploadFileReference,\n} from \"../../file-uploads/fileReferences\"\nimport {\n getBucketName,\n getTenantId,\n getUploadKeyHash,\n getUserId,\n resolveStoredUploadAccessScope,\n type SessionUser,\n} from \"../../file-uploads/shared\"\n\n\ntype DeleteResponsePayload = {\n ok: boolean\n error?: string\n}\n\nconst resolveHeaderString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized ? normalized : null\n}\n\nconst isFileNotFoundError = (error: unknown): boolean => {\n const message = error instanceof Error ? error.message : String(error)\n return message.includes(\"FileNotFound\")\n}\n\nconst deleteGridFsFile = async (bucket: GridFSBucket, fileId: ObjectId): Promise<void> => {\n try {\n await bucket.delete(fileId)\n } catch (error) {\n if (!isFileNotFoundError(error)) throw error\n }\n}\n\nexport const deleteFile: ApiHandler<Record<string, never>, DeleteResponsePayload, SessionUser> = async (\n _payload,\n ctx,\n): Promise<DeleteResponsePayload> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400)\n return { ok: false, error: \"tenant_missing\" }\n }\n\n const fileIdRaw = String(ctx.req.params?.fileId ?? \"\").trim()\n let fileObjectId: ObjectId\n try {\n fileObjectId = new ObjectId(fileIdRaw)\n } catch {\n ctx.res.status(400)\n return { ok: false, error: \"invalid_file_id\" }\n }\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) {\n ctx.res.status(500)\n return { ok: false, error: \"filesystem_db_unavailable\" }\n }\n\n const bucketName = getBucketName()\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n\n const userId = getUserId(ctx)\n const uploadKeyHash = getUploadKeyHash(ctx)\n if (!userId && !uploadKeyHash) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId)\n if (reference) {\n const referenceMetadata = reference as unknown as Record<string, unknown>\n const metadataUserId = resolveHeaderString(reference.userId)\n const ownerKeyHash = resolveHeaderString(reference.ownerKeyHash)\n const accessScope = resolveStoredUploadAccessScope(referenceMetadata)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n const authorizedByTenant = accessScope === \"tenant\" && Boolean(userId)\n\n if (!authorizedByUser && !authorizedByKey && !authorizedByTenant) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n try {\n await deleteUploadFileReference({\n tenantId,\n bucketName,\n referenceId: fileObjectId,\n })\n } catch {\n ctx.res.status(500)\n return { ok: false, error: \"delete_failed\" }\n }\n\n ctx.res.status(204)\n return { ok: true }\n }\n\n const [file] = await bucket.find({ _id: fileObjectId }).limit(1).toArray()\n if (!file) {\n ctx.res.status(204)\n return { ok: true }\n }\n\n const metadataUserId = resolveHeaderString((file as any)?.metadata?.userId)\n const ownerKeyHash = resolveHeaderString((file as any)?.metadata?.ownerKeyHash)\n const rawMetadata = (file as any)?.metadata\n const fileMetadata = rawMetadata && typeof rawMetadata === \"object\"\n ? rawMetadata as Record<string, unknown>\n : {}\n const accessScope = resolveStoredUploadAccessScope(fileMetadata)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n const authorizedByTenant = accessScope === \"tenant\" && Boolean(userId)\n\n if (!authorizedByUser && !authorizedByKey && !authorizedByTenant) {\n ctx.res.status(401)\n return { ok: false, error: \"unauthorized\" }\n }\n\n if (fileMetadata.deduplication && typeof fileMetadata.deduplication === \"object\") {\n ctx.res.status(409)\n return { ok: false, error: \"file_reference_required\" }\n }\n\n try {\n const variants = await bucket.find({ \"metadata.variantOf\": fileObjectId.toHexString() }).toArray()\n const variantIds = variants\n .map((variant) => (variant as any)?._id)\n .filter((id): id is ObjectId => id instanceof ObjectId)\n\n await deleteGridFsFile(bucket, fileObjectId)\n for (const variantId of variantIds) {\n await deleteGridFsFile(bucket, variantId)\n }\n } catch {\n ctx.res.status(500)\n return { ok: false, error: \"delete_failed\" }\n }\n\n ctx.res.status(204)\n return { ok: true }\n}\n","import { ApiHandler } from \"@rpcbase/api\"\nimport { getTenantFilesystemDb } from \"@rpcbase/db\"\nimport { GridFSBucket, ObjectId } from \"mongodb\"\n\nimport { findUploadFileReference } from \"../../file-uploads/fileReferences\"\nimport {\n getBucketName,\n getTenantId,\n getUploadKeyHash,\n getUserId,\n resolveStoredUploadAccessScope,\n type SessionUser,\n} from \"../../file-uploads/shared\"\n\n\nconst resolveHeaderString = (value: unknown): string | null => {\n if (typeof value !== \"string\") return null\n const normalized = value.trim()\n return normalized ? normalized : null\n}\n\nconst escapeHeaderFilename = (filename: string): string => filename.replace(/[\\\\\"]/g, \"_\")\n\nconst parseRequestedWidth = (value: unknown): number | null => {\n if (typeof value !== \"string\") return null\n const parsed = Number(value.trim())\n if (!Number.isFinite(parsed) || parsed <= 0) return null\n return Math.floor(parsed)\n}\n\nconst resolveImageVariants = (file: unknown): Record<string, unknown> | null => {\n const metadata = (file as any)?.metadata\n if (!metadata || typeof metadata !== \"object\") return null\n const image = (metadata as Record<string, unknown>).image\n if (!image || typeof image !== \"object\") return null\n const variants = (image as Record<string, unknown>).variants\n if (!variants || typeof variants !== \"object\") return null\n return variants as Record<string, unknown>\n}\n\nconst resolveVariantFileId = (variant: unknown): ObjectId | null => {\n if (!variant || typeof variant !== \"object\") return null\n const fileId = (variant as Record<string, unknown>).fileId\n if (typeof fileId !== \"string\") return null\n try {\n return new ObjectId(fileId)\n } catch {\n return null\n }\n}\n\nconst selectVariantFileId = (file: unknown, requestedWidth: number | null, requestedVariant: unknown): ObjectId | null => {\n const variants = resolveImageVariants(file)\n if (!variants) return null\n\n let aliasWidth: number | null = null\n if (typeof requestedVariant === \"string\") {\n const normalized = requestedVariant.trim().toLowerCase()\n aliasWidth = normalized === \"thumb\" ? 320 : normalized === \"small\" ? 640 : normalized === \"medium\" ? 960 : normalized === \"large\" ? 1600 : null\n if (aliasWidth) {\n const variantFileId = resolveVariantFileId(variants[String(aliasWidth)])\n if (variantFileId) return variantFileId\n }\n }\n\n const targetWidth = aliasWidth ?? requestedWidth\n if (!targetWidth) return null\n\n const widths = Object.keys(variants)\n .map((width) => Number(width))\n .filter((width) => Number.isInteger(width) && width > 0)\n .sort((a, b) => a - b)\n\n const selectedWidth = widths.reduce<number | null>((selected, width) => {\n if (selected === null) return width\n\n const selectedDistance = Math.abs(selected - targetWidth)\n const distance = Math.abs(width - targetWidth)\n if (distance < selectedDistance) return width\n if (distance === selectedDistance && width > selected) return width\n return selected\n }, null)\n return selectedWidth ? resolveVariantFileId(variants[String(selectedWidth)]) : null\n}\n\nexport const getFile: ApiHandler<Record<string, never>, Record<string, never>, SessionUser> = async (\n _payload,\n ctx,\n): Promise<Record<string, never>> => {\n const tenantId = getTenantId(ctx)\n if (!tenantId) {\n ctx.res.status(400).end()\n return {}\n }\n\n const fileIdRaw = String(ctx.req.params?.fileId ?? \"\").trim()\n let fileObjectId: ObjectId\n try {\n fileObjectId = new ObjectId(fileIdRaw)\n } catch {\n ctx.res.status(400).end()\n return {}\n }\n\n const fsDb = await getTenantFilesystemDb(tenantId)\n const nativeDb = fsDb.db\n if (!nativeDb) {\n ctx.res.status(500).end()\n return {}\n }\n\n const bucketName = getBucketName()\n const bucket = new GridFSBucket(nativeDb, { bucketName })\n const reference = await findUploadFileReference(nativeDb, bucketName, fileObjectId)\n const blobObjectId = reference?.blobId ?? fileObjectId\n\n const [file] = await bucket.find({ _id: blobObjectId }).limit(1).toArray()\n if (!file) {\n ctx.res.status(404).end()\n return {}\n }\n\n const rawMetadata = reference ?? (file as any)?.metadata\n const fileMetadata = rawMetadata && typeof rawMetadata === \"object\"\n ? rawMetadata as Record<string, unknown>\n : {}\n const accessScope = resolveStoredUploadAccessScope(fileMetadata)\n if (accessScope !== \"public\") {\n const userId = getUserId(ctx)\n if (accessScope === \"tenant\") {\n if (!userId) {\n ctx.res.status(401).end()\n return {}\n }\n } else {\n const uploadKeyHash = getUploadKeyHash(ctx)\n const metadataUserId = resolveHeaderString(fileMetadata.userId)\n const ownerKeyHash = resolveHeaderString(fileMetadata.ownerKeyHash)\n\n const authorizedByUser = Boolean(userId && metadataUserId && userId === metadataUserId)\n const authorizedByKey = Boolean(uploadKeyHash && ownerKeyHash && uploadKeyHash === ownerKeyHash)\n\n if (!authorizedByUser && !authorizedByKey) {\n ctx.res.status(401).end()\n return {}\n }\n }\n }\n\n const requestedWidth = parseRequestedWidth((ctx.req.query as any)?.w)\n const variantFileObjectId = selectVariantFileId(file, requestedWidth, (ctx.req.query as any)?.variant)\n const [variantFile] = variantFileObjectId\n ? await bucket.find({ _id: variantFileObjectId }).limit(1).toArray()\n : []\n const selectedFileObjectId = variantFile ? variantFileObjectId as ObjectId : blobObjectId\n const selectedFile = variantFile ?? file\n\n const mimeTypeFromMetadata = resolveHeaderString((selectedFile as any)?.metadata?.mimeType)\n const mimeType = mimeTypeFromMetadata ?? \"application/octet-stream\"\n const filenameFromDb = resolveHeaderString(reference?.filename ?? (selectedFile as any)?.filename)\n const filename = filenameFromDb ?? fileIdRaw\n const filenameSafe = escapeHeaderFilename(filename)\n\n const cacheControl = \"private, max-age=0, must-revalidate\"\n const md5 = resolveHeaderString((selectedFile as any)?.md5)\n const uploadDate = (selectedFile as any)?.uploadDate instanceof Date ? (selectedFile as any).uploadDate : null\n const etagValue = md5 ?? `${selectedFileObjectId.toHexString()}-${String((selectedFile as any)?.length ?? 0)}-${String(uploadDate?.getTime() ?? 0)}`\n const etag = md5 ? `\"${etagValue}\"` : `W/\"${etagValue}\"`\n const ifNoneMatch = resolveHeaderString((ctx.req.headers as any)?.[\"if-none-match\"])\n if (ifNoneMatch) {\n const candidates = ifNoneMatch.split(\",\").map((value) => value.trim()).filter(Boolean)\n if (candidates.includes(\"*\") || candidates.includes(etag)) {\n ctx.res.status(304)\n ctx.res.setHeader(\"Cache-Control\", cacheControl)\n ctx.res.setHeader(\"ETag\", etag)\n ctx.res.end()\n return {}\n }\n }\n\n ctx.res.status(200)\n ctx.res.setHeader(\"Content-Type\", mimeType)\n ctx.res.setHeader(\"Content-Length\", String((selectedFile as any)?.length ?? 0))\n ctx.res.setHeader(\"Content-Disposition\", `inline; filename=\"${filenameSafe}\"`)\n ctx.res.setHeader(\"Cache-Control\", cacheControl)\n ctx.res.setHeader(\"ETag\", etag)\n ctx.res.setHeader(\"X-Content-Type-Options\", \"nosniff\")\n if (mimeType === \"image/svg+xml\") {\n ctx.res.setHeader(\n \"Content-Security-Policy\",\n \"default-src 'none'; style-src 'unsafe-inline'; sandbox; base-uri 'none'; form-action 'none'\",\n )\n }\n ctx.res.flushHeaders()\n\n if (ctx.req.method === \"HEAD\") {\n ctx.res.end()\n return {}\n }\n\n const stream = bucket.openDownloadStream(selectedFileObjectId)\n\n stream.on(\"error\", () => {\n try {\n ctx.res.destroy()\n } catch {\n //\n }\n })\n\n stream.pipe(ctx.res)\n return {}\n}\n","export const Route = \"/api/rb/files/:fileId\"\n\nexport const GetRoute = Route\nexport const DeleteRoute = Route\n","import { Api } from \"@rpcbase/api\"\n\nimport { deleteFile } from \"./handlers/deleteFile\"\nimport { getFile } from \"./handlers/getFile\"\n\nimport * as Files from \"./index\"\n\n\nexport default (api: Api) => {\n api.get(Files.GetRoute, getFile)\n api.delete(Files.DeleteRoute, deleteFile)\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -6,4 +6,5 @@ export * from './passwordHashStorage';
6
6
  export * from './ssrMiddleware';
7
7
  export type { HtmlOutlets } from './htmlTemplate';
8
8
  export * from './email';
9
+ export * from './serviceWorker';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,iBAAiB,CAAA;AAC/B,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,cAAc,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,iBAAiB,CAAA;AAC/B,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,cAAc,SAAS,CAAA;AACvB,cAAc,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { i as __toESM, n as sendEmail, r as __commonJSMin, t as EmailDeliveryError } from "./email-Co1GNjlT.js";
1
+ import { a as __commonJSMin, i as sendEmail, n as configureEmailTransport, o as __toESM, r as createResendEmailTransport, t as EmailDeliveryError } from "./email-CK8NNDQY.js";
2
2
  import { c as runRtsQuery, d as getDerivedKey, i as normalizeRtsQueryOptions, n as buildRtsAbilityFromRequest, o as resolveRtsRequestTenantId, r as isRtsRequestAuthorized, s as runRtsCount, t as RTS_QUERY_WINDOW_MAX_COUNT, u as syncAuthenticatedSessionMiddleware } from "./queryWindow-DP8zD0lb.js";
3
3
  import session from "express-session";
4
4
  import { RedisStore } from "connect-redis";
@@ -4152,6 +4152,149 @@ var developmentSessionMiddleware = (sessionMiddleware) => {
4152
4152
  };
4153
4153
  };
4154
4154
  //#endregion
4155
+ //#region src/serviceWorker.ts
4156
+ var RPCBASE_SERVICE_WORKER_PATH = "/rpcbase-service-worker.js";
4157
+ var RPCBASE_SERVICE_WORKER_MESSAGE_SOURCE = "@rpcbase/service-worker";
4158
+ var rpcbaseServiceWorkerSource = `
4159
+ const MESSAGE_SOURCE = ${JSON.stringify(RPCBASE_SERVICE_WORKER_MESSAGE_SOURCE)}
4160
+
4161
+ const getSameOriginWindowClients = async () => {
4162
+ const windowClients = await self.clients.matchAll({ type: "window", includeUncontrolled: true })
4163
+ return windowClients.filter((client) => {
4164
+ try {
4165
+ return new URL(client.url).origin === self.location.origin
4166
+ } catch {
4167
+ return false
4168
+ }
4169
+ })
4170
+ }
4171
+
4172
+ const normalizeMessage = (value) => {
4173
+ if (!value || typeof value !== "object") return null
4174
+ if (value.source !== MESSAGE_SOURCE || typeof value.type !== "string" || !value.type.trim()) return null
4175
+ return {
4176
+ source: MESSAGE_SOURCE,
4177
+ type: value.type.trim(),
4178
+ ...(value.payload === undefined ? {} : { payload: value.payload }),
4179
+ }
4180
+ }
4181
+
4182
+ const broadcastMessage = async (message, excludedClientId) => {
4183
+ const windowClients = await getSameOriginWindowClients()
4184
+ for (const client of windowClients) {
4185
+ if (client.id === excludedClientId) continue
4186
+ client.postMessage(message)
4187
+ }
4188
+ }
4189
+
4190
+ const showNotificationFromMessage = async (message) => {
4191
+ if (message.type !== "notifications.show") return false
4192
+ const payload = message.payload
4193
+ if (!payload || typeof payload !== "object") return false
4194
+ const title = typeof payload.title === "string" ? payload.title.trim() : ""
4195
+ if (!title) return false
4196
+ const options = payload.options && typeof payload.options === "object" ? payload.options : undefined
4197
+ await self.registration.showNotification(title, options)
4198
+ return true
4199
+ }
4200
+
4201
+ const getTargetUrl = (link, linkMode, client) => {
4202
+ try {
4203
+ if (linkMode === "merge_current_search" && client) {
4204
+ const currentUrl = new URL(client.url)
4205
+ const actionUrl = new URL(link, currentUrl)
4206
+ actionUrl.searchParams.forEach((value, key) => currentUrl.searchParams.set(key, value))
4207
+ if (actionUrl.hash) currentUrl.hash = actionUrl.hash
4208
+ return currentUrl.origin === self.location.origin ? currentUrl.href : null
4209
+ }
4210
+
4211
+ const targetUrl = new URL(link, self.location.origin)
4212
+ return targetUrl.origin === self.location.origin ? targetUrl.href : null
4213
+ } catch {
4214
+ return null
4215
+ }
4216
+ }
4217
+
4218
+ self.addEventListener("install", (event) => event.waitUntil(self.skipWaiting()))
4219
+
4220
+ self.addEventListener("activate", (event) => {
4221
+ event.waitUntil((async () => {
4222
+ await self.clients.claim()
4223
+ await broadcastMessage({ source: MESSAGE_SOURCE, type: "worker.ready" })
4224
+ })())
4225
+ })
4226
+
4227
+ self.addEventListener("message", (event) => {
4228
+ const message = normalizeMessage(event.data)
4229
+ if (!message) return
4230
+
4231
+ event.waitUntil((async () => {
4232
+ if (await showNotificationFromMessage(message)) return
4233
+ const sourceClientId = event.source && typeof event.source.id === "string"
4234
+ ? event.source.id
4235
+ : undefined
4236
+ await broadcastMessage(message, sourceClientId)
4237
+ })())
4238
+ })
4239
+
4240
+ self.addEventListener("push", (event) => {
4241
+ let message = null
4242
+ try {
4243
+ message = normalizeMessage(event.data ? event.data.json() : null)
4244
+ } catch {
4245
+ return
4246
+ }
4247
+ if (!message || message.type !== "notifications.show") return
4248
+ event.waitUntil(showNotificationFromMessage(message))
4249
+ })
4250
+
4251
+ self.addEventListener("notificationclick", (event) => {
4252
+ event.notification.close()
4253
+ event.waitUntil((async () => {
4254
+ const data = event.notification.data && typeof event.notification.data === "object"
4255
+ ? event.notification.data
4256
+ : {}
4257
+ const link = typeof data.link === "string" ? data.link.trim() : ""
4258
+ const linkMode = data.linkMode === "merge_current_search" ? "merge_current_search" : "navigate"
4259
+ const windowClients = await getSameOriginWindowClients()
4260
+ const client = windowClients.find((candidate) => candidate.focused) ?? windowClients[0]
4261
+
4262
+ if (!link) {
4263
+ if (client) await client.focus()
4264
+ return
4265
+ }
4266
+
4267
+ const targetUrl = getTargetUrl(link, linkMode, client)
4268
+ if (!targetUrl) return
4269
+
4270
+ if (client) {
4271
+ try {
4272
+ const navigatedClient = await client.navigate(targetUrl)
4273
+ await (navigatedClient ?? client).focus()
4274
+ return
4275
+ } catch {
4276
+ await self.clients.openWindow(targetUrl)
4277
+ return
4278
+ }
4279
+ }
4280
+
4281
+ await self.clients.openWindow(targetUrl)
4282
+ })())
4283
+ })
4284
+ `.trimStart();
4285
+ var rpcbaseServiceWorkerRequestHandler = (_req, res) => {
4286
+ res.set({
4287
+ "Cache-Control": "no-cache",
4288
+ "Content-Type": "application/javascript; charset=utf-8",
4289
+ "Service-Worker-Allowed": "/",
4290
+ "X-Content-Type-Options": "nosniff"
4291
+ });
4292
+ res.send(rpcbaseServiceWorkerSource);
4293
+ };
4294
+ var registerRpcbaseServiceWorkerRoute = (app) => {
4295
+ app.get(RPCBASE_SERVICE_WORKER_PATH, rpcbaseServiceWorkerRequestHandler);
4296
+ };
4297
+ //#endregion
4155
4298
  //#region src/initServer.ts
4156
4299
  process.env = {
4157
4300
  ...env,
@@ -4228,6 +4371,7 @@ var initServer = async (app, serverEnv) => {
4228
4371
  }
4229
4372
  next();
4230
4373
  });
4374
+ registerRpcbaseServiceWorkerRoute(app);
4231
4375
  metricsIngestProxyMiddleware(app);
4232
4376
  const posthog = getPosthogClient(serverEnv);
4233
4377
  if (posthog) {
@@ -4615,8 +4759,6 @@ async function applyRouteLoaders(req, res, dataRoutes) {
4615
4759
  statusCode: 200
4616
4760
  };
4617
4761
  const runLoaderWithTimeout = async (route, params) => {
4618
- await resolveLazyRoute(route);
4619
- if (!route.loader) return null;
4620
4762
  let timeoutId;
4621
4763
  const timeoutPromise = new Promise((_, reject) => {
4622
4764
  timeoutId = setTimeout(() => {
@@ -4636,6 +4778,8 @@ async function applyRouteLoaders(req, res, dataRoutes) {
4636
4778
  });
4637
4779
  const loaderPromise = (async () => {
4638
4780
  try {
4781
+ await resolveLazyRoute(route);
4782
+ if (!route.loader) return null;
4639
4783
  const data = await route.loader({
4640
4784
  params,
4641
4785
  ctx: {
@@ -5374,6 +5518,6 @@ var ssrMiddleware = ({ viteInstance, dataRoutes, errorExtraComponent, getHtmlOut
5374
5518
  }
5375
5519
  };
5376
5520
  //#endregion
5377
- export { EmailDeliveryError, bindShutdownSignals, getDerivedKey, hashPassword, hashPasswordForStorage, initServer, onShutdown, sendEmail, ssrMiddleware, verifyPasswordFromStorage };
5521
+ export { EmailDeliveryError, RPCBASE_SERVICE_WORKER_MESSAGE_SOURCE, RPCBASE_SERVICE_WORKER_PATH, bindShutdownSignals, configureEmailTransport, createResendEmailTransport, getDerivedKey, hashPassword, hashPasswordForStorage, initServer, onShutdown, registerRpcbaseServiceWorkerRoute, rpcbaseServiceWorkerRequestHandler, rpcbaseServiceWorkerSource, sendEmail, ssrMiddleware, verifyPasswordFromStorage };
5378
5522
 
5379
5523
  //# sourceMappingURL=index.js.map