secure-upload-fastify-sdk 1.0.4 → 1.0.6
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/README.md +181 -1
- package/dist/index.js +103 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -4
- package/dist/index.mjs.map +1 -1
- package/dist/server/fastify-plugin.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +103 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +103 -4
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/routes/multipart.d.ts.map +1 -1
- package/dist/server/types.d.ts +74 -1
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/utils/repository/index.js +51 -1
- package/dist/server/utils/repository/index.js.map +1 -1
- package/dist/server/utils/repository/index.mjs +51 -1
- package/dist/server/utils/repository/index.mjs.map +1 -1
- package/dist/server/utils/repository/memory.d.ts +7 -1
- package/dist/server/utils/repository/memory.d.ts.map +1 -1
- package/dist/server/utils/repository/prisma.d.ts +8 -1
- package/dist/server/utils/repository/prisma.d.ts.map +1 -1
- package/dist/server/utils/repository/types.d.ts +38 -2
- package/dist/server/utils/repository/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -300,7 +300,12 @@ function toFileRecord(row) {
|
|
|
300
300
|
meta: row.meta && typeof row.meta === "object" ? row.meta : null,
|
|
301
301
|
createdAt: row.createdAt,
|
|
302
302
|
updatedAt: row.updatedAt,
|
|
303
|
-
deletedAt: row.deletedAt
|
|
303
|
+
deletedAt: row.deletedAt,
|
|
304
|
+
// v1.5.1+:水印溯源字段(可选;旧 schema/老库里 row 可能没有,需要兜底)
|
|
305
|
+
watermarked: row.watermarked ?? false,
|
|
306
|
+
isOriginal: row.isOriginal ?? true,
|
|
307
|
+
parentId: row.parentId ?? null,
|
|
308
|
+
retentionExpiresAt: row.retentionExpiresAt ?? null
|
|
304
309
|
};
|
|
305
310
|
}
|
|
306
311
|
var PrismaMultipartRepository = class {
|
|
@@ -466,6 +471,27 @@ var PrismaFileRepository = class {
|
|
|
466
471
|
});
|
|
467
472
|
return toFileRecord(row);
|
|
468
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* v1.5.1: 钩子 onComplete 返回 patch 后 SDK 调这个方法
|
|
476
|
+
* - 只更新传入的字段;其他字段保留原值
|
|
477
|
+
* - 文件不存在 → 抛错(由调用方决定是否捕获)
|
|
478
|
+
* - 业务字段 watermarked/isOriginal/parentId/retentionExpiresAt 需要 schema v1.4.0+
|
|
479
|
+
*/
|
|
480
|
+
async update(id, patch) {
|
|
481
|
+
const data = {};
|
|
482
|
+
if (patch.storageKey !== void 0) data.storageKey = patch.storageKey;
|
|
483
|
+
if (patch.size !== void 0) data.size = BigInt(patch.size);
|
|
484
|
+
if (patch.contentType !== void 0) data.contentType = patch.contentType;
|
|
485
|
+
if (patch.meta !== void 0) data.meta = patch.meta;
|
|
486
|
+
if (patch.watermarked !== void 0) data.watermarked = patch.watermarked;
|
|
487
|
+
if (patch.isOriginal !== void 0) data.isOriginal = patch.isOriginal;
|
|
488
|
+
if (patch.parentId !== void 0) data.parentId = patch.parentId;
|
|
489
|
+
if (patch.retentionExpiresAt !== void 0) {
|
|
490
|
+
data.retentionExpiresAt = patch.retentionExpiresAt;
|
|
491
|
+
}
|
|
492
|
+
const row = await this.prisma.file.update({ where: { id }, data });
|
|
493
|
+
return toFileRecord(row);
|
|
494
|
+
}
|
|
469
495
|
async softDelete(id, metaPatch) {
|
|
470
496
|
if (metaPatch) {
|
|
471
497
|
const cur = await this.prisma.file.findUnique({ where: { id } });
|
|
@@ -692,6 +718,30 @@ var InMemoryFileRepository = class {
|
|
|
692
718
|
};
|
|
693
719
|
this.store.set(id, next);
|
|
694
720
|
}
|
|
721
|
+
/**
|
|
722
|
+
* v1.5.1: 钩子 onComplete 返回 patch 后 SDK 调这个方法
|
|
723
|
+
* - 只更新传入的字段;其他字段保留原值
|
|
724
|
+
* - 文件不存在 → 抛错(由调用方决定是否捕获)
|
|
725
|
+
*/
|
|
726
|
+
async update(id, patch) {
|
|
727
|
+
const rec = this.store.get(id);
|
|
728
|
+
if (!rec) throw new Error("NOT_FOUND");
|
|
729
|
+
const now = /* @__PURE__ */ new Date();
|
|
730
|
+
const next = {
|
|
731
|
+
...rec,
|
|
732
|
+
storageKey: patch.storageKey ?? rec.storageKey,
|
|
733
|
+
size: patch.size !== void 0 ? BigInt(patch.size) : rec.size,
|
|
734
|
+
contentType: patch.contentType ?? rec.contentType,
|
|
735
|
+
meta: patch.meta === void 0 ? rec.meta : patch.meta,
|
|
736
|
+
watermarked: patch.watermarked ?? rec.watermarked,
|
|
737
|
+
isOriginal: patch.isOriginal ?? rec.isOriginal,
|
|
738
|
+
parentId: patch.parentId === void 0 ? rec.parentId : patch.parentId,
|
|
739
|
+
retentionExpiresAt: patch.retentionExpiresAt === void 0 ? rec.retentionExpiresAt : patch.retentionExpiresAt,
|
|
740
|
+
updatedAt: now
|
|
741
|
+
};
|
|
742
|
+
this.store.set(id, next);
|
|
743
|
+
return next;
|
|
744
|
+
}
|
|
695
745
|
async listOrphans(opts) {
|
|
696
746
|
const sinceMs = opts.sinceDays * 24 * 3600 * 1e3;
|
|
697
747
|
const list = [];
|
|
@@ -1139,6 +1189,47 @@ async function lock(rt, key, ttlMs, fn, retries = 0) {
|
|
|
1139
1189
|
}
|
|
1140
1190
|
return await memoryWithLock(key, fn, retries);
|
|
1141
1191
|
}
|
|
1192
|
+
async function streamToBuffer(stream) {
|
|
1193
|
+
const chunks = [];
|
|
1194
|
+
for await (const chunk of stream) {
|
|
1195
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
1196
|
+
}
|
|
1197
|
+
return Buffer.concat(chunks);
|
|
1198
|
+
}
|
|
1199
|
+
async function runOnComplete(rt, file, log) {
|
|
1200
|
+
if (!rt.onComplete) return file;
|
|
1201
|
+
try {
|
|
1202
|
+
const patch = await rt.onComplete({
|
|
1203
|
+
file,
|
|
1204
|
+
storage: rt.storage,
|
|
1205
|
+
log,
|
|
1206
|
+
getOriginalBuffer: async () => {
|
|
1207
|
+
const stream = await Promise.resolve(rt.storage.get(file.storageKey));
|
|
1208
|
+
return streamToBuffer(stream);
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
if (!patch || Object.keys(patch).length === 0) {
|
|
1212
|
+
return file;
|
|
1213
|
+
}
|
|
1214
|
+
const updated = await rt.fileRepo.update(file.id, patch);
|
|
1215
|
+
log.info(
|
|
1216
|
+
{
|
|
1217
|
+
fileId: file.id,
|
|
1218
|
+
patchKeys: Object.keys(patch),
|
|
1219
|
+
newStorageKey: patch.storageKey,
|
|
1220
|
+
watermarked: patch.watermarked
|
|
1221
|
+
},
|
|
1222
|
+
"\u2705 onComplete \u94A9\u5B50\u5DF2\u5E94\u7528 patch"
|
|
1223
|
+
);
|
|
1224
|
+
return updated;
|
|
1225
|
+
} catch (err) {
|
|
1226
|
+
log.warn(
|
|
1227
|
+
{ err, fileId: file.id, uploadId: file.uploadId },
|
|
1228
|
+
"\u26A0\uFE0F onComplete \u94A9\u5B50\u6267\u884C\u5931\u8D25,\u5DF2\u8DF3\u8FC7\u4E1A\u52A1\u540E\u5904\u7406(file record \u4FDD\u6301\u539F\u72B6)"
|
|
1229
|
+
);
|
|
1230
|
+
return file;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1142
1233
|
async function registerMultipartRoutes(app, rt) {
|
|
1143
1234
|
if (!rt.config.enabled) {
|
|
1144
1235
|
app.log.warn("\u26A0\uFE0F multipart \u4E0A\u4F20\u5DF2\u7981\u7528 (enabled=false)");
|
|
@@ -1444,8 +1535,14 @@ async function registerMultipartRoutes(app, rt) {
|
|
|
1444
1535
|
contentHash: finalHash,
|
|
1445
1536
|
meta: rec.meta ?? void 0
|
|
1446
1537
|
});
|
|
1538
|
+
const finalFile = await runOnComplete(rt, file2, req.log);
|
|
1447
1539
|
await rt.multipartRepo.markCompleted(rec.id, fileId);
|
|
1448
|
-
return {
|
|
1540
|
+
return {
|
|
1541
|
+
idempotent: false,
|
|
1542
|
+
fileId: finalFile.id,
|
|
1543
|
+
size: Number(finalFile.size),
|
|
1544
|
+
finalHash
|
|
1545
|
+
};
|
|
1449
1546
|
}
|
|
1450
1547
|
);
|
|
1451
1548
|
if (!result.idempotent) {
|
|
@@ -1458,7 +1555,8 @@ async function registerMultipartRoutes(app, rt) {
|
|
|
1458
1555
|
uploadId: body.uploadId,
|
|
1459
1556
|
fileId: result.fileId,
|
|
1460
1557
|
size: result.size,
|
|
1461
|
-
userId: rec.userId
|
|
1558
|
+
userId: rec.userId,
|
|
1559
|
+
watermarkHook: rt.onComplete ? "on" : "off"
|
|
1462
1560
|
},
|
|
1463
1561
|
"\u2705 multipart: complete"
|
|
1464
1562
|
);
|
|
@@ -1934,7 +2032,8 @@ async function secureUploadPluginImpl(app, options) {
|
|
|
1934
2032
|
...options.strategy ?? {}
|
|
1935
2033
|
}
|
|
1936
2034
|
},
|
|
1937
|
-
validateSession: options.sessionValidator ?? defaultSessionValidator
|
|
2035
|
+
validateSession: options.sessionValidator ?? defaultSessionValidator,
|
|
2036
|
+
onComplete: options.onComplete ?? null
|
|
1938
2037
|
};
|
|
1939
2038
|
app.decorate("secureUpload", runtime);
|
|
1940
2039
|
await registerMultipartRoutes(app, runtime);
|