@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.
- package/dist/{email-Co1GNjlT.js → email-CK8NNDQY.js} +48 -24
- package/dist/email-CK8NNDQY.js.map +1 -0
- package/dist/email.d.ts +9 -0
- package/dist/email.d.ts.map +1 -1
- package/dist/fileReferences-Ca0tivFd.js +101 -0
- package/dist/fileReferences-Ca0tivFd.js.map +1 -0
- package/dist/{handler-Fk-5fOSm.js → handler-BUTqP40B.js} +2 -2
- package/dist/{handler-Fk-5fOSm.js.map → handler-BUTqP40B.js.map} +1 -1
- package/dist/{handler-C92_gJkX.js → handler-BgcIWWMc.js} +2 -2
- package/dist/{handler-C92_gJkX.js.map → handler-BgcIWWMc.js.map} +1 -1
- package/dist/{handler-CapJTGzc.js → handler-CqSlSCdd.js} +215 -57
- package/dist/handler-CqSlSCdd.js.map +1 -0
- package/dist/{handler-BqlcQ9sE.js → handler-LRLmxrsg.js} +69 -24
- package/dist/handler-LRLmxrsg.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -4
- package/dist/index.js.map +1 -1
- package/dist/initServer.d.ts.map +1 -1
- package/dist/notifications.js +2 -2
- package/dist/postProcessors-iffHvje4.js.map +1 -1
- package/dist/rts/index.js +1 -1
- package/dist/{schemas-B2fUvgYo.js → schemas-POKnVn0c.js} +58 -2
- package/dist/schemas-POKnVn0c.js.map +1 -0
- package/dist/serviceWorker.d.ts +7 -0
- package/dist/serviceWorker.d.ts.map +1 -0
- package/dist/{shared-DfrVDSp0.js → shared-Zt17vuAT.js} +54 -2
- package/dist/shared-Zt17vuAT.js.map +1 -0
- package/dist/uploads/api/file-uploads/fileReferences.d.ts +42 -0
- package/dist/uploads/api/file-uploads/fileReferences.d.ts.map +1 -0
- package/dist/uploads/api/file-uploads/handlers/completeUpload.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/handlers/initUpload.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/imageVariantsPostProcessor.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/index.d.ts +23 -0
- package/dist/uploads/api/file-uploads/index.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/postProcessors.d.ts +2 -0
- package/dist/uploads/api/file-uploads/postProcessors.d.ts.map +1 -1
- package/dist/uploads/api/file-uploads/shared.d.ts +21 -0
- package/dist/uploads/api/file-uploads/shared.d.ts.map +1 -1
- package/dist/uploads/api/files/handlers/deleteFile.d.ts.map +1 -1
- package/dist/uploads/api/files/handlers/getFile.d.ts.map +1 -1
- package/dist/uploads/worker.js +3 -2
- package/dist/uploads/worker.js.map +1 -1
- package/dist/uploads.js +2 -2
- package/package.json +1 -1
- package/dist/email-Co1GNjlT.js.map +0 -1
- package/dist/handler-BqlcQ9sE.js.map +0 -1
- package/dist/handler-CapJTGzc.js.map +0 -1
- package/dist/schemas-B2fUvgYo.js.map +0 -1
- package/dist/shared-DfrVDSp0.js.map +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
-
|
|
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
|
|
172
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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 :
|
|
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-
|
|
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
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
|
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
|