@rpcbase/server 0.513.0 → 0.514.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.
@@ -2,7 +2,7 @@ import { models, getTenantFilesystemDb } from "@rpcbase/db";
2
2
  import { GridFSBucket, ObjectId } from "mongodb";
3
3
  import { JSDOM } from "jsdom";
4
4
  import createDOMPurify from "dompurify";
5
- import { g as getTenantId, a as getModelCtx, b as buildUploadsAbility, c as getUploadSessionAccessQuery, e as ensureUploadIndexes, d as getBucketName, f as getUserId, h as getChunkSizeBytes, i as getSessionTtlMs, j as computeSha256Hex, t as toBufferPayload, n as normalizeSha256Hex, k as getMaxClientUploadBytesPerSecond, l as getRawBodyLimitBytes } from "./shared-BJomDDWK.js";
5
+ import { g as getTenantId, a as getModelCtx, b as buildUploadsAbility, c as getUploadSessionAccessQuery, e as ensureUploadIndexes, d as getBucketName, f as getUserId, h as getChunkSizeBytes, i as getSessionTtlMs, j as computeSha256Hex, t as toBufferPayload, n as normalizeSha256Hex, k as getMaxClientUploadBytesPerSecond, l as getRawBodyLimitBytes } from "./shared-Dy9x-P7F.js";
6
6
  import { randomBytes } from "node:crypto";
7
7
  import { o as object, n as number, b as boolean, s as string, a as array, _ as _enum } from "./schemas-Cjdjgehl.js";
8
8
  const MAX_SVG_BYTES = 128 * 1024;
@@ -16,12 +16,17 @@ const looksLikeSvgText = (text) => {
16
16
  };
17
17
  const looksLikeSvg = (sniff) => looksLikeSvgText(sniff.toString("utf8"));
18
18
  const sanitizeSvg = (svg) => DOMPurify.sanitize(svg, {
19
- USE_PROFILES: { svg: true, svgFilters: true }
19
+ USE_PROFILES: {
20
+ svg: true,
21
+ svgFilters: true
22
+ }
20
23
  });
21
24
  const sanitizeSvgProcessor = {
22
25
  id: "sanitize-svg",
23
26
  maxBytes: MAX_SVG_BYTES,
24
- match: ({ sniff }) => looksLikeSvg(sniff),
27
+ match: ({
28
+ sniff
29
+ }) => looksLikeSvg(sniff),
25
30
  process: (data) => {
26
31
  if (data.length > MAX_SVG_BYTES) {
27
32
  throw new Error("svg_too_large");
@@ -38,7 +43,10 @@ const sanitizeSvgProcessor = {
38
43
  if (sanitizedBuffer.length > MAX_SVG_BYTES) {
39
44
  throw new Error("svg_too_large");
40
45
  }
41
- return { data: sanitizedBuffer, mimeType: "image/svg+xml" };
46
+ return {
47
+ data: sanitizedBuffer,
48
+ mimeType: "image/svg+xml"
49
+ };
42
50
  }
43
51
  };
44
52
  const uploadProcessors = Object.freeze([sanitizeSvgProcessor]);
@@ -115,53 +123,94 @@ const completeUpload = async (_payload, ctx) => {
115
123
  const tenantId = getTenantId(ctx);
116
124
  if (!tenantId) {
117
125
  ctx.res.status(400);
118
- return { ok: false, error: "tenant_missing" };
126
+ return {
127
+ ok: false,
128
+ error: "tenant_missing"
129
+ };
119
130
  }
120
131
  const uploadId = String(ctx.req.params?.uploadId ?? "").trim();
121
132
  if (!uploadId) {
122
133
  ctx.res.status(400);
123
- return { ok: false, error: "invalid_upload_id" };
134
+ return {
135
+ ok: false,
136
+ error: "invalid_upload_id"
137
+ };
124
138
  }
125
139
  const modelCtx = getModelCtx(ctx, tenantId);
126
- const [UploadSession, UploadChunk] = await Promise.all([
127
- models.get("RBUploadSession", modelCtx),
128
- models.get("RBUploadChunk", modelCtx)
129
- ]);
140
+ const [UploadSession, UploadChunk] = await Promise.all([models.get("RBUploadSession", modelCtx), models.get("RBUploadChunk", modelCtx)]);
130
141
  const ability = buildUploadsAbility(ctx, tenantId);
131
142
  if (!ability.can("update", "RBUploadSession")) {
132
143
  ctx.res.status(401);
133
- return { ok: false, error: "unauthorized" };
144
+ return {
145
+ ok: false,
146
+ error: "unauthorized"
147
+ };
134
148
  }
135
- const existing = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "read")] }).lean();
149
+ const existing = await UploadSession.findOne({
150
+ $and: [{
151
+ _id: uploadId
152
+ }, getUploadSessionAccessQuery(ability, "read")]
153
+ }).lean();
136
154
  if (!existing) {
137
155
  ctx.res.status(404);
138
- return { ok: false, error: "not_found" };
156
+ return {
157
+ ok: false,
158
+ error: "not_found"
159
+ };
139
160
  }
140
161
  if (existing.status === "done" && existing.fileId) {
141
- return { ok: true, fileId: existing.fileId };
162
+ return {
163
+ ok: true,
164
+ fileId: existing.fileId
165
+ };
142
166
  }
143
- const locked = await UploadSession.findOneAndUpdate(
144
- { $and: [{ _id: uploadId }, { status: "uploading" }, getUploadSessionAccessQuery(ability, "update")] },
145
- { $set: { status: "assembling" }, $unset: { error: "" } },
146
- { new: true }
147
- ).lean();
167
+ const locked = await UploadSession.findOneAndUpdate({
168
+ $and: [{
169
+ _id: uploadId
170
+ }, {
171
+ status: "uploading"
172
+ }, getUploadSessionAccessQuery(ability, "update")]
173
+ }, {
174
+ $set: {
175
+ status: "assembling"
176
+ },
177
+ $unset: {
178
+ error: ""
179
+ }
180
+ }, {
181
+ new: true
182
+ }).lean();
148
183
  if (!locked) {
149
184
  ctx.res.status(409);
150
- return { ok: false, error: "not_uploading" };
185
+ return {
186
+ ok: false,
187
+ error: "not_uploading"
188
+ };
151
189
  }
152
190
  await ensureUploadIndexes(UploadSession, UploadChunk);
153
191
  const fsDb = await getTenantFilesystemDb(tenantId);
154
192
  const nativeDb = fsDb.db;
155
193
  if (!nativeDb) {
156
- await UploadSession.updateOne(
157
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
158
- { $set: { status: "error", error: "filesystem_db_unavailable" } }
159
- );
194
+ await UploadSession.updateOne({
195
+ $and: [{
196
+ _id: uploadId
197
+ }, getUploadSessionAccessQuery(ability, "update")]
198
+ }, {
199
+ $set: {
200
+ status: "error",
201
+ error: "filesystem_db_unavailable"
202
+ }
203
+ });
160
204
  ctx.res.status(500);
161
- return { ok: false, error: "assembly_failed" };
205
+ return {
206
+ ok: false,
207
+ error: "assembly_failed"
208
+ };
162
209
  }
163
210
  const bucketName = getBucketName();
164
- const bucket = new GridFSBucket(nativeDb, { bucketName });
211
+ const bucket = new GridFSBucket(nativeDb, {
212
+ bucketName
213
+ });
165
214
  const lockedUserId = typeof locked.userId === "string" ? locked.userId : void 0;
166
215
  const maxProcessorBytes = getMaxUploadProcessorBytes();
167
216
  const shouldBufferForProcessing = locked.totalSize <= maxProcessorBytes;
@@ -172,7 +221,11 @@ const completeUpload = async (_payload, ctx) => {
172
221
  if (!shouldBufferForProcessing && declaredSvg) {
173
222
  throw new Error("svg_too_large");
174
223
  }
175
- const cursor = UploadChunk.find({ uploadId }).sort({ index: 1 }).cursor();
224
+ const cursor = UploadChunk.find({
225
+ uploadId
226
+ }).sort({
227
+ index: 1
228
+ }).cursor();
176
229
  let expectedIndex = 0;
177
230
  const chunks = [];
178
231
  let bufferedBytes = 0;
@@ -214,9 +267,15 @@ const completeUpload = async (_payload, ctx) => {
214
267
  tenantId,
215
268
  mimeType: locked.mimeType,
216
269
  totalSize: locked.totalSize,
217
- ...typeof locked.isPublic === "boolean" ? { isPublic: locked.isPublic } : {},
218
- ...typeof locked.ownerKeyHash === "string" ? { ownerKeyHash: locked.ownerKeyHash } : {},
219
- ...lockedUserId ? { userId: lockedUserId } : {}
270
+ ...typeof locked.isPublic === "boolean" ? {
271
+ isPublic: locked.isPublic
272
+ } : {},
273
+ ...typeof locked.ownerKeyHash === "string" ? {
274
+ ownerKeyHash: locked.ownerKeyHash
275
+ } : {},
276
+ ...lockedUserId ? {
277
+ userId: lockedUserId
278
+ } : {}
220
279
  }
221
280
  });
222
281
  for (const pending of pendingChunks) {
@@ -240,7 +299,11 @@ const completeUpload = async (_payload, ctx) => {
240
299
  }
241
300
  if (shouldBufferForProcessing) {
242
301
  const assembled = Buffer.concat(chunks, bufferedBytes);
243
- const { data: processed, mimeType: processedMimeType, applied } = await applyUploadProcessors(assembled, {
302
+ const {
303
+ data: processed,
304
+ mimeType: processedMimeType,
305
+ applied
306
+ } = await applyUploadProcessors(assembled, {
244
307
  filename: locked.filename,
245
308
  clientMimeType: locked.mimeType
246
309
  });
@@ -250,10 +313,19 @@ const completeUpload = async (_payload, ctx) => {
250
313
  tenantId,
251
314
  mimeType: processedMimeType,
252
315
  totalSize: locked.totalSize,
253
- ...applied.length ? { processors: applied, processedSize: processed.length } : {},
254
- ...typeof locked.isPublic === "boolean" ? { isPublic: locked.isPublic } : {},
255
- ...typeof locked.ownerKeyHash === "string" ? { ownerKeyHash: locked.ownerKeyHash } : {},
256
- ...lockedUserId ? { userId: lockedUserId } : {}
316
+ ...applied.length ? {
317
+ processors: applied,
318
+ processedSize: processed.length
319
+ } : {},
320
+ ...typeof locked.isPublic === "boolean" ? {
321
+ isPublic: locked.isPublic
322
+ } : {},
323
+ ...typeof locked.ownerKeyHash === "string" ? {
324
+ ownerKeyHash: locked.ownerKeyHash
325
+ } : {},
326
+ ...lockedUserId ? {
327
+ userId: lockedUserId
328
+ } : {}
257
329
  }
258
330
  });
259
331
  const finished = waitForStreamFinished(uploadStream);
@@ -277,9 +349,15 @@ const completeUpload = async (_payload, ctx) => {
277
349
  tenantId,
278
350
  mimeType: locked.mimeType,
279
351
  totalSize: locked.totalSize,
280
- ...typeof locked.isPublic === "boolean" ? { isPublic: locked.isPublic } : {},
281
- ...typeof locked.ownerKeyHash === "string" ? { ownerKeyHash: locked.ownerKeyHash } : {},
282
- ...lockedUserId ? { userId: lockedUserId } : {}
352
+ ...typeof locked.isPublic === "boolean" ? {
353
+ isPublic: locked.isPublic
354
+ } : {},
355
+ ...typeof locked.ownerKeyHash === "string" ? {
356
+ ownerKeyHash: locked.ownerKeyHash
357
+ } : {},
358
+ ...lockedUserId ? {
359
+ userId: lockedUserId
360
+ } : {}
283
361
  }
284
362
  });
285
363
  for (const pending of pendingChunks) {
@@ -295,80 +373,146 @@ const completeUpload = async (_payload, ctx) => {
295
373
  if (!fileId) {
296
374
  throw new Error("missing_file_id");
297
375
  }
298
- await UploadSession.updateOne(
299
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
300
- { $set: { status: "done", fileId }, $unset: { error: "" } }
301
- );
376
+ await UploadSession.updateOne({
377
+ $and: [{
378
+ _id: uploadId
379
+ }, getUploadSessionAccessQuery(ability, "update")]
380
+ }, {
381
+ $set: {
382
+ status: "done",
383
+ fileId
384
+ },
385
+ $unset: {
386
+ error: ""
387
+ }
388
+ });
302
389
  try {
303
- await UploadChunk.deleteMany({ uploadId });
390
+ await UploadChunk.deleteMany({
391
+ uploadId
392
+ });
304
393
  } catch {
305
394
  }
306
- return { ok: true, fileId };
395
+ return {
396
+ ok: true,
397
+ fileId
398
+ };
307
399
  } catch (error) {
308
400
  const message = error instanceof Error ? error.message : String(error);
309
401
  await abortUploadStream(uploadStream);
310
402
  if (message === "missing_chunks") {
311
- await UploadSession.updateOne(
312
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
313
- { $set: { status: "uploading" } }
314
- );
403
+ await UploadSession.updateOne({
404
+ $and: [{
405
+ _id: uploadId
406
+ }, getUploadSessionAccessQuery(ability, "update")]
407
+ }, {
408
+ $set: {
409
+ status: "uploading"
410
+ }
411
+ });
315
412
  ctx.res.status(409);
316
- return { ok: false, error: "missing_chunks" };
413
+ return {
414
+ ok: false,
415
+ error: "missing_chunks"
416
+ };
317
417
  }
318
418
  if (message === "svg_too_large") {
319
- await UploadSession.updateOne(
320
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
321
- { $set: { status: "error", error: message } }
322
- );
419
+ await UploadSession.updateOne({
420
+ $and: [{
421
+ _id: uploadId
422
+ }, getUploadSessionAccessQuery(ability, "update")]
423
+ }, {
424
+ $set: {
425
+ status: "error",
426
+ error: message
427
+ }
428
+ });
323
429
  ctx.res.status(413);
324
- return { ok: false, error: message };
430
+ return {
431
+ ok: false,
432
+ error: message
433
+ };
325
434
  }
326
435
  if (message === "svg_invalid" || message === "svg_sanitize_failed") {
327
- await UploadSession.updateOne(
328
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
329
- { $set: { status: "error", error: message } }
330
- );
436
+ await UploadSession.updateOne({
437
+ $and: [{
438
+ _id: uploadId
439
+ }, getUploadSessionAccessQuery(ability, "update")]
440
+ }, {
441
+ $set: {
442
+ status: "error",
443
+ error: message
444
+ }
445
+ });
331
446
  ctx.res.status(400);
332
- return { ok: false, error: message };
447
+ return {
448
+ ok: false,
449
+ error: message
450
+ };
333
451
  }
334
- await UploadSession.updateOne(
335
- { $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] },
336
- { $set: { status: "error", error: message } }
337
- );
452
+ await UploadSession.updateOne({
453
+ $and: [{
454
+ _id: uploadId
455
+ }, getUploadSessionAccessQuery(ability, "update")]
456
+ }, {
457
+ $set: {
458
+ status: "error",
459
+ error: message
460
+ }
461
+ });
338
462
  ctx.res.status(500);
339
- return { ok: false, error: "assembly_failed" };
463
+ return {
464
+ ok: false,
465
+ error: "assembly_failed"
466
+ };
340
467
  }
341
468
  };
342
469
  const getStatus = async (_payload, ctx) => {
343
470
  const tenantId = getTenantId(ctx);
344
471
  if (!tenantId) {
345
472
  ctx.res.status(400);
346
- return { ok: false, error: "tenant_missing" };
473
+ return {
474
+ ok: false,
475
+ error: "tenant_missing"
476
+ };
347
477
  }
348
478
  const uploadId = String(ctx.req.params?.uploadId ?? "").trim();
349
479
  if (!uploadId) {
350
480
  ctx.res.status(400);
351
- return { ok: false, error: "invalid_upload_id" };
481
+ return {
482
+ ok: false,
483
+ error: "invalid_upload_id"
484
+ };
352
485
  }
353
486
  const modelCtx = getModelCtx(ctx, tenantId);
354
- const [UploadSession, UploadChunk] = await Promise.all([
355
- models.get("RBUploadSession", modelCtx),
356
- models.get("RBUploadChunk", modelCtx)
357
- ]);
487
+ const [UploadSession, UploadChunk] = await Promise.all([models.get("RBUploadSession", modelCtx), models.get("RBUploadChunk", modelCtx)]);
358
488
  const ability = buildUploadsAbility(ctx, tenantId);
359
489
  if (!ability.can("read", "RBUploadSession")) {
360
490
  ctx.res.status(401);
361
- return { ok: false, error: "unauthorized" };
491
+ return {
492
+ ok: false,
493
+ error: "unauthorized"
494
+ };
362
495
  }
363
- const session = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "read")] }).lean();
496
+ const session = await UploadSession.findOne({
497
+ $and: [{
498
+ _id: uploadId
499
+ }, getUploadSessionAccessQuery(ability, "read")]
500
+ }).lean();
364
501
  if (!session) {
365
502
  ctx.res.status(404);
366
- return { ok: false, error: "not_found" };
503
+ return {
504
+ ok: false,
505
+ error: "not_found"
506
+ };
367
507
  }
368
- const receivedDocs = await UploadChunk.find(
369
- { uploadId },
370
- { index: 1, _id: 0 }
371
- ).sort({ index: 1 }).lean();
508
+ const receivedDocs = await UploadChunk.find({
509
+ uploadId
510
+ }, {
511
+ index: 1,
512
+ _id: 0
513
+ }).sort({
514
+ index: 1
515
+ }).lean();
372
516
  const received = receivedDocs.map((doc) => typeof doc.index === "number" ? doc.index : -1).filter((n) => Number.isInteger(n) && n >= 0);
373
517
  return {
374
518
  ok: true,
@@ -376,7 +520,9 @@ const getStatus = async (_payload, ctx) => {
376
520
  chunkSize: session.chunkSize,
377
521
  chunksTotal: session.chunksTotal,
378
522
  received,
379
- ...session.fileId ? { fileId: session.fileId } : {}
523
+ ...session.fileId ? {
524
+ fileId: session.fileId
525
+ } : {}
380
526
  };
381
527
  };
382
528
  const InitRoute = "/api/rb/file-uploads";
@@ -415,22 +561,30 @@ const initUpload = async (payload, ctx) => {
415
561
  const tenantId = getTenantId(ctx);
416
562
  if (!tenantId) {
417
563
  ctx.res.status(400);
418
- return { ok: false, error: "tenant_missing" };
564
+ return {
565
+ ok: false,
566
+ error: "tenant_missing"
567
+ };
419
568
  }
420
569
  const userId = getUserId(ctx);
421
570
  const parsed = initRequestSchema.safeParse(payload ?? {});
422
571
  if (!parsed.success) {
423
572
  ctx.res.status(400);
424
- return { ok: false, error: "invalid_payload" };
573
+ return {
574
+ ok: false,
575
+ error: "invalid_payload"
576
+ };
425
577
  }
426
578
  const chunkSize = getChunkSizeBytes();
427
- const { filename, mimeType, totalSize, isPublic } = parsed.data;
579
+ const {
580
+ filename,
581
+ mimeType,
582
+ totalSize,
583
+ isPublic
584
+ } = parsed.data;
428
585
  const chunksTotal = Math.ceil(totalSize / chunkSize);
429
586
  const modelCtx = getModelCtx(ctx, tenantId);
430
- const [UploadSession, UploadChunk] = await Promise.all([
431
- models.get("RBUploadSession", modelCtx),
432
- models.get("RBUploadChunk", modelCtx)
433
- ]);
587
+ const [UploadSession, UploadChunk] = await Promise.all([models.get("RBUploadSession", modelCtx), models.get("RBUploadChunk", modelCtx)]);
434
588
  await ensureUploadIndexes(UploadSession, UploadChunk);
435
589
  const uploadId = new ObjectId().toString();
436
590
  const now = Date.now();
@@ -439,11 +593,17 @@ const initUpload = async (payload, ctx) => {
439
593
  const ownerKeyHash = uploadKey ? computeSha256Hex(Buffer.from(uploadKey)) : void 0;
440
594
  await UploadSession.create({
441
595
  _id: uploadId,
442
- ...userId ? { userId } : {},
443
- ...ownerKeyHash ? { ownerKeyHash } : {},
596
+ ...userId ? {
597
+ userId
598
+ } : {},
599
+ ...ownerKeyHash ? {
600
+ ownerKeyHash
601
+ } : {},
444
602
  filename,
445
603
  mimeType,
446
- ...typeof isPublic === "boolean" ? { isPublic } : {},
604
+ ...typeof isPublic === "boolean" ? {
605
+ isPublic
606
+ } : {},
447
607
  totalSize,
448
608
  chunkSize,
449
609
  chunksTotal,
@@ -456,58 +616,88 @@ const initUpload = async (payload, ctx) => {
456
616
  uploadId,
457
617
  chunkSize,
458
618
  chunksTotal,
459
- ...uploadKey ? { uploadKey } : {}
619
+ ...uploadKey ? {
620
+ uploadKey
621
+ } : {}
460
622
  };
461
623
  };
462
624
  const uploadChunk = async (payload, ctx) => {
463
625
  const tenantId = getTenantId(ctx);
464
626
  if (!tenantId) {
465
627
  ctx.res.status(400);
466
- return { ok: false, error: "tenant_missing" };
628
+ return {
629
+ ok: false,
630
+ error: "tenant_missing"
631
+ };
467
632
  }
468
633
  const uploadId = String(ctx.req.params?.uploadId ?? "").trim();
469
634
  const indexRaw = String(ctx.req.params?.index ?? "").trim();
470
635
  const index = Number(indexRaw);
471
636
  if (!uploadId || !Number.isInteger(index) || index < 0) {
472
637
  ctx.res.status(400);
473
- return { ok: false, error: "invalid_chunk_ref" };
638
+ return {
639
+ ok: false,
640
+ error: "invalid_chunk_ref"
641
+ };
474
642
  }
475
643
  const modelCtx = getModelCtx(ctx, tenantId);
476
- const [UploadSession, UploadChunk] = await Promise.all([
477
- models.get("RBUploadSession", modelCtx),
478
- models.get("RBUploadChunk", modelCtx)
479
- ]);
644
+ const [UploadSession, UploadChunk] = await Promise.all([models.get("RBUploadSession", modelCtx), models.get("RBUploadChunk", modelCtx)]);
480
645
  const ability = buildUploadsAbility(ctx, tenantId);
481
646
  if (!ability.can("update", "RBUploadSession")) {
482
647
  ctx.res.status(401);
483
- return { ok: false, error: "unauthorized" };
648
+ return {
649
+ ok: false,
650
+ error: "unauthorized"
651
+ };
484
652
  }
485
- const session = await UploadSession.findOne({ $and: [{ _id: uploadId }, getUploadSessionAccessQuery(ability, "update")] }).lean();
653
+ const session = await UploadSession.findOne({
654
+ $and: [{
655
+ _id: uploadId
656
+ }, getUploadSessionAccessQuery(ability, "update")]
657
+ }).lean();
486
658
  if (!session) {
487
659
  ctx.res.status(404);
488
- return { ok: false, error: "not_found" };
660
+ return {
661
+ ok: false,
662
+ error: "not_found"
663
+ };
489
664
  }
490
665
  if (session.status !== "uploading") {
491
666
  ctx.res.status(409);
492
- return { ok: false, error: "not_uploading" };
667
+ return {
668
+ ok: false,
669
+ error: "not_uploading"
670
+ };
493
671
  }
494
672
  if (index >= session.chunksTotal) {
495
673
  ctx.res.status(400);
496
- return { ok: false, error: "index_out_of_range" };
674
+ return {
675
+ ok: false,
676
+ error: "index_out_of_range"
677
+ };
497
678
  }
498
679
  const data = toBufferPayload(payload);
499
680
  if (!data) {
500
681
  ctx.res.status(400);
501
- return { ok: false, error: "invalid_body" };
682
+ return {
683
+ ok: false,
684
+ error: "invalid_body"
685
+ };
502
686
  }
503
687
  const expectedSize = index === session.chunksTotal - 1 ? session.totalSize - session.chunkSize * (session.chunksTotal - 1) : session.chunkSize;
504
688
  if (data.length > expectedSize) {
505
689
  ctx.res.status(413);
506
- return { ok: false, error: "chunk_too_large" };
690
+ return {
691
+ ok: false,
692
+ error: "chunk_too_large"
693
+ };
507
694
  }
508
695
  if (data.length !== expectedSize) {
509
696
  ctx.res.status(400);
510
- return { ok: false, error: "invalid_chunk_size" };
697
+ return {
698
+ ok: false,
699
+ error: "invalid_chunk_size"
700
+ };
511
701
  }
512
702
  const checksumHeader = ctx.req.get("X-Chunk-SHA256");
513
703
  const sha256 = checksumHeader ? computeSha256Hex(data) : void 0;
@@ -515,29 +705,35 @@ const uploadChunk = async (payload, ctx) => {
515
705
  const expectedSha256 = normalizeSha256Hex(checksumHeader);
516
706
  if (sha256 !== expectedSha256) {
517
707
  ctx.res.status(400);
518
- return { ok: false, error: "checksum_mismatch" };
708
+ return {
709
+ ok: false,
710
+ error: "checksum_mismatch"
711
+ };
519
712
  }
520
713
  }
521
714
  await ensureUploadIndexes(UploadSession, UploadChunk);
522
- await UploadChunk.updateOne(
523
- { uploadId, index },
524
- {
525
- $set: {
526
- uploadId,
527
- index,
528
- data,
529
- size: data.length,
530
- sha256,
531
- expiresAt: session.expiresAt
532
- },
533
- $setOnInsert: {
534
- createdAt: /* @__PURE__ */ new Date()
535
- }
715
+ await UploadChunk.updateOne({
716
+ uploadId,
717
+ index
718
+ }, {
719
+ $set: {
720
+ uploadId,
721
+ index,
722
+ data,
723
+ size: data.length,
724
+ sha256,
725
+ expiresAt: session.expiresAt
536
726
  },
537
- { upsert: true }
538
- );
727
+ $setOnInsert: {
728
+ createdAt: /* @__PURE__ */ new Date()
729
+ }
730
+ }, {
731
+ upsert: true
732
+ });
539
733
  ctx.res.status(204);
540
- return { ok: true };
734
+ return {
735
+ ok: true
736
+ };
541
737
  };
542
738
  const rawBodyParser = ({
543
739
  limitBytes,
@@ -584,7 +780,10 @@ const rawBodyParser = ({
584
780
  done = true;
585
781
  cleanup();
586
782
  req.destroy();
587
- res.status(413).json({ ok: false, error: "chunk_too_large" });
783
+ res.status(413).json({
784
+ ok: false,
785
+ error: "chunk_too_large"
786
+ });
588
787
  return;
589
788
  }
590
789
  chunks.push(buffer);
@@ -666,13 +865,10 @@ const consumeRateBudget = (state, bytes, rateBytesPerSecond, now) => {
666
865
  };
667
866
  const handler = (api) => {
668
867
  const chunkSizeBytes = getChunkSizeBytes();
669
- api.use(
670
- InitRoute,
671
- rawBodyParser({
672
- limitBytes: getRawBodyLimitBytes(chunkSizeBytes),
673
- maxClientBytesPerSecond: getMaxClientUploadBytesPerSecond()
674
- })
675
- );
868
+ api.use(InitRoute, rawBodyParser({
869
+ limitBytes: getRawBodyLimitBytes(chunkSizeBytes),
870
+ maxClientBytesPerSecond: getMaxClientUploadBytesPerSecond()
871
+ }));
676
872
  api.post(InitRoute, initUpload);
677
873
  api.put(ChunkRoute, uploadChunk);
678
874
  api.get(StatusRoute, getStatus);
@@ -681,4 +877,4 @@ const handler = (api) => {
681
877
  export {
682
878
  handler as default
683
879
  };
684
- //# sourceMappingURL=handler-Bh3a6Br1.js.map
880
+ //# sourceMappingURL=handler-GZgk5k3c.js.map