@finueva/drive 0.2.0 → 0.3.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/index.js CHANGED
@@ -10,6 +10,7 @@ const DRIVE_API_ERROR_CODES = Object.freeze([
10
10
  "precondition_failed",
11
11
  "idempotency_conflict",
12
12
  "quota_exceeded",
13
+ "upload_recovery_required",
13
14
  "service_unavailable",
14
15
  "internal_error"
15
16
  ]);
@@ -24,6 +25,7 @@ const DRIVE_API_ERROR_MESSAGES = Object.freeze({
24
25
  precondition_failed: "The request precondition failed.",
25
26
  idempotency_conflict: "The idempotency key conflicts with an earlier request.",
26
27
  quota_exceeded: "The workspace storage quota would be exceeded.",
28
+ upload_recovery_required: "The upload requires recovery before it can continue.",
27
29
  service_unavailable: "The service is temporarily unavailable.",
28
30
  internal_error: "The request could not be completed."
29
31
  });
@@ -79,6 +81,28 @@ async function parseResponse(response, operationSignal, preconditionStatus, succ
79
81
  validators: readValidators(response.headers)
80
82
  });
81
83
  }
84
+ async function parseNoContentResponse(response, operationSignal, preconditionStatus, successStatuses, allowedErrorCodes) {
85
+ const requestId = safeRequestId(response.headers.get("x-request-id"));
86
+ if (requestId === null) {
87
+ cancelResponse(response);
88
+ throw new DriveError("invalid_response", { status: response.status });
89
+ }
90
+ if (!successStatuses.includes(response.status)) throw await normalizeError(response, requestId, operationSignal, preconditionStatus, false, allowedErrorCodes);
91
+ const contentLength = response.headers.get("content-length");
92
+ if (response.body !== null || contentLength !== null && contentLength !== "0" || response.headers.has("content-type")) {
93
+ cancelResponse(response);
94
+ throw new DriveError("invalid_response", {
95
+ status: response.status,
96
+ requestId
97
+ });
98
+ }
99
+ return Object.freeze({
100
+ data: void 0,
101
+ status: response.status,
102
+ requestId,
103
+ validators: Object.freeze({})
104
+ });
105
+ }
82
106
  function parseCollectionEtag(value) {
83
107
  const match = COLLECTION_ETAG.exec(value);
84
108
  if (!match) return void 0;
@@ -137,6 +161,7 @@ function errorStatusMatches(code, status, preconditionStatus, allowsQuotaExceede
137
161
  precondition_failed: preconditionStatus === null ? [] : [preconditionStatus],
138
162
  idempotency_conflict: [409],
139
163
  quota_exceeded: [409],
164
+ upload_recovery_required: [409],
140
165
  service_unavailable: [503],
141
166
  internal_error: [500]
142
167
  }[code].includes(status);
@@ -247,6 +272,7 @@ const WORKSPACE_ID$1 = /^drive\.workspace\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-
247
272
  const VOLUME_ID = /^drive\.volume\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
248
273
  const GRANT_ID$1 = /^drive\.grant\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
249
274
  const UPLOAD_ID$1 = /^drive\.upload\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
275
+ const VERSION_ID = /^drive\.version\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
250
276
  const CURSOR$1 = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
251
277
  const AUTH_ID$1 = /^[A-Za-z0-9_-]{1,128}$/;
252
278
  const GRANT_ETAG = /^"drive\.permission-grant\.v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)"$/;
@@ -269,7 +295,8 @@ const EFFECTIVE_ACTIONS = Object.freeze([
269
295
  "items:update"
270
296
  ]);
271
297
  const MAX_UPLOAD_BYTE_LENGTH$1 = 33554432e4;
272
- const UPLOAD_QUOTA_EXPIRY_MILLISECONDS = 864e5;
298
+ const UPLOAD_PART_BYTE_LENGTH$2 = 32 * 1024 * 1024;
299
+ const CONTENT_DIGEST$1 = /^sha256:[0-9a-f]{64}$/;
273
300
  function isCurrentWorkspace(value) {
274
301
  if (!isExactRecord(value, [
275
302
  "workspaceId",
@@ -350,18 +377,93 @@ function isEffectivePermissionResponse(value, targetItemId) {
350
377
  }
351
378
  return true;
352
379
  }
353
- function isUploadQuotaReservation(value) {
354
- return isExactRecord(value, [
355
- "workspaceId",
380
+ function isUploadSession(value, expectedByteLength) {
381
+ if (!isExactRecord(value, [
382
+ "itemId",
383
+ "versionId",
356
384
  "uploadId",
357
- "parentItemId",
358
- "expectedByteLength",
359
- "state",
360
- "terminalReason",
361
- "createdAtEpochMilliseconds",
385
+ "mode",
386
+ "partByteLength",
387
+ "partCount",
388
+ "revision",
389
+ "expiresAtEpochMilliseconds"
390
+ ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || value.partByteLength !== UPLOAD_PART_BYTE_LENGTH$2 || !isSafeInteger$1(value.partCount) || value.partCount > 1e4 || value.partCount !== Math.ceil(expectedByteLength / UPLOAD_PART_BYTE_LENGTH$2) || (expectedByteLength === 0 ? value.mode !== "server-mediated-zero-byte" : value.mode !== "presigned-multipart") || !isSafeInteger$1(value.revision) || !isSafeInteger$1(value.expiresAtEpochMilliseconds) || value.expiresAtEpochMilliseconds <= Date.now()) return false;
391
+ Object.freeze(value);
392
+ return true;
393
+ }
394
+ function isUploadStatus(value, afterPartNumber, limit) {
395
+ if (!isExactRecord(value, [
396
+ "itemId",
397
+ "versionId",
398
+ "uploadId",
399
+ "mode",
400
+ "lifecycle",
401
+ "revision",
402
+ "partPolicy",
403
+ "confirmedParts",
404
+ "nextAfterPartNumber",
362
405
  "expiresAtEpochMilliseconds",
363
- "terminalAtEpochMilliseconds"
364
- ]) && typeof value.workspaceId === "string" && WORKSPACE_ID$1.test(value.workspaceId) && typeof value.uploadId === "string" && UPLOAD_ID$1.test(value.uploadId) && typeof value.parentItemId === "string" && ITEM_ID$1.test(value.parentItemId) && typeof value.expectedByteLength === "number" && Number.isSafeInteger(value.expectedByteLength) && value.expectedByteLength >= 0 && value.expectedByteLength <= MAX_UPLOAD_BYTE_LENGTH$1 && (value.state === "reserved" || value.state === "converted" || value.state === "released") && (value.terminalReason === null || value.terminalReason === "completed" || value.terminalReason === "aborted" || value.terminalReason === "failed" || value.terminalReason === "expired") && isSafeInteger$1(value.createdAtEpochMilliseconds) && isSafeInteger$1(value.expiresAtEpochMilliseconds) && value.expiresAtEpochMilliseconds - value.createdAtEpochMilliseconds === UPLOAD_QUOTA_EXPIRY_MILLISECONDS && (value.terminalAtEpochMilliseconds === null || isSafeInteger$1(value.terminalAtEpochMilliseconds) && value.terminalAtEpochMilliseconds >= value.createdAtEpochMilliseconds);
406
+ "ready"
407
+ ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || ![
408
+ "initiating",
409
+ "recovery-required",
410
+ "uploading",
411
+ "completing",
412
+ "provider-completed",
413
+ "ready",
414
+ "aborting",
415
+ "aborted"
416
+ ].includes(String(value.lifecycle)) || !isSafeInteger$1(value.revision) || !isExactRecord(value.partPolicy, [
417
+ "partByteLength",
418
+ "partCount",
419
+ "maxParts"
420
+ ]) || value.partPolicy.partByteLength !== UPLOAD_PART_BYTE_LENGTH$2 || !isSafeInteger$1(value.partPolicy.partCount) || value.partPolicy.partCount > 1e4 || value.partPolicy.maxParts !== 1e4 || (value.mode === "server-mediated-zero-byte" ? value.partPolicy.partCount !== 0 : value.partPolicy.partCount < 1) || !Array.isArray(value.confirmedParts) || value.confirmedParts.length > limit || !isSafeInteger$1(value.expiresAtEpochMilliseconds)) return false;
421
+ let previousPartNumber = afterPartNumber;
422
+ for (const part of value.confirmedParts) {
423
+ if (!isExactRecord(part, ["partNumber", "checksumSha256"]) || !isSafeInteger$1(part.partNumber) || part.partNumber <= previousPartNumber || part.partNumber > value.partPolicy.partCount || !isPartChecksum$1(part.checksumSha256)) return false;
424
+ previousPartNumber = part.partNumber;
425
+ }
426
+ if (!(value.nextAfterPartNumber === null || isSafeInteger$1(value.nextAfterPartNumber) && value.confirmedParts.length === limit && value.nextAfterPartNumber === previousPartNumber) || value.mode === "server-mediated-zero-byte" && (value.confirmedParts.length !== 0 || value.nextAfterPartNumber !== null) || value.lifecycle === "ready" !== (value.ready !== null) || value.ready !== null && (!isReadyUpload(value.ready, { uploadId: value.uploadId }) || value.ready.itemId !== value.itemId || value.ready.versionId !== value.versionId)) return false;
427
+ Object.freeze(value.partPolicy);
428
+ for (const part of value.confirmedParts) Object.freeze(part);
429
+ Object.freeze(value.confirmedParts);
430
+ Object.freeze(value);
431
+ return true;
432
+ }
433
+ function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allowInsecureHttp) {
434
+ if (!isExactRecord(value, [
435
+ "url",
436
+ "method",
437
+ "headers",
438
+ "partNumber",
439
+ "expectedByteLength",
440
+ "expiresAtEpochMilliseconds"
441
+ ]) || !isSignedTransferUrl(value.url, allowInsecureHttp) || value.method !== "PUT" || !isExactRecord(value.headers, ["x-amz-checksum-sha256"]) || value.headers["x-amz-checksum-sha256"] !== checksumSha256 || value.partNumber !== expectedPartNumber || !isSafeInteger$1(value.expectedByteLength) || value.expectedByteLength < 1 || value.expectedByteLength > UPLOAD_PART_BYTE_LENGTH$2 || !isSafeInteger$1(value.expiresAtEpochMilliseconds) || value.expiresAtEpochMilliseconds <= Date.now()) return false;
442
+ Object.freeze(value.headers);
443
+ Object.freeze(value);
444
+ return true;
445
+ }
446
+ function isUploadPartResult(value, expectedPartNumber, expectedUploadRevision) {
447
+ if (!isExactRecord(value, ["partNumber", "revision"]) || value.partNumber !== expectedPartNumber || value.revision !== expectedUploadRevision + 1 || !isSafeInteger$1(value.revision)) return false;
448
+ Object.freeze(value);
449
+ return true;
450
+ }
451
+ function isReadyUpload(value, expected) {
452
+ if (!isExactRecord(value, [
453
+ "itemId",
454
+ "versionId",
455
+ "uploadId",
456
+ "byteLength",
457
+ "callerDeclaredContentDigest",
458
+ "displayFilename",
459
+ "mediaType",
460
+ "state"
461
+ ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID.test(value.versionId) || value.uploadId !== expected.uploadId || !isSafeInteger$1(value.byteLength) || value.byteLength < 0 || value.byteLength > MAX_UPLOAD_BYTE_LENGTH$1 || typeof value.callerDeclaredContentDigest !== "string" || !CONTENT_DIGEST$1.test(value.callerDeclaredContentDigest) || !isSafeFilename$1(value.displayFilename) || !isMediaType$1(value.mediaType) || value.state !== "ready" || expected.byteLength !== void 0 && value.byteLength !== expected.byteLength || expected.callerDeclaredContentDigest !== void 0 && value.callerDeclaredContentDigest !== expected.callerDeclaredContentDigest || expected.displayFilename !== void 0 && value.displayFilename !== expected.displayFilename || expected.mediaType !== void 0 && value.mediaType !== expected.mediaType) return false;
462
+ Object.freeze(value);
463
+ return true;
464
+ }
465
+ function isPartChecksum$1(value) {
466
+ return typeof value === "string" && /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(value);
365
467
  }
366
468
  function mutationValidatorsAreCoherent(headers) {
367
469
  const collection = headers.get("drive-permission-collection-etag");
@@ -418,6 +520,19 @@ function isSafeFilename$1(value) {
418
520
  }
419
521
  return true;
420
522
  }
523
+ function isMediaType$1(value) {
524
+ return typeof value === "string" && value.length <= 255 && /^[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?\/[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?$/.test(value);
525
+ }
526
+ function isSignedTransferUrl(value, allowInsecureHttp) {
527
+ if (typeof value !== "string" || value.length < 1 || value.length > 8192 || value !== value.trim()) return false;
528
+ try {
529
+ const url = new URL(value);
530
+ const loopbackHost = url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]";
531
+ return (url.protocol === "https:" || url.protocol === "http:" && allowInsecureHttp && loopbackHost) && url.username === "" && url.password === "" && url.hash === "" && url.host !== "";
532
+ } catch {
533
+ return false;
534
+ }
535
+ }
421
536
  function filenameIsReserved$1(value) {
422
537
  const base = value.split(".", 1)[0].toUpperCase();
423
538
  return value === "." || value === ".." || [
@@ -457,7 +572,10 @@ const PERMISSION_ACTIONS = Object.freeze([
457
572
  "items:update"
458
573
  ]);
459
574
  const IDEMPOTENCY_KEY = /^[A-Za-z0-9_-]{16,128}$/;
575
+ const CONTENT_DIGEST = /^sha256:[0-9a-f]{64}$/;
576
+ const PART_CHECKSUM = /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/;
460
577
  const MAX_UPLOAD_BYTE_LENGTH = 33554432e4;
578
+ const UPLOAD_PART_BYTE_LENGTH$1 = 32 * 1024 * 1024;
461
579
  function validateCurrentWorkspaceInput(value) {
462
580
  const signal = validateSignal(captureRecord(value === void 0 ? {} : value, [], ["signal"]).signal);
463
581
  return signal === void 0 ? {} : { signal };
@@ -596,26 +714,133 @@ function validateCreateUploadInput(value) {
596
714
  "workspaceId",
597
715
  "parentItemId",
598
716
  "expectedByteLength",
717
+ "displayFilename",
718
+ "mediaType",
719
+ "callerDeclaredContentDigest",
720
+ "protectionClassification",
599
721
  "idempotencyKey"
600
722
  ], ["signal"]);
601
723
  const signal = validateSignal(input.signal);
602
- if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.parentItemId !== "string" || !ITEM_ID.test(input.parentItemId) || typeof input.expectedByteLength !== "number" || !Number.isSafeInteger(input.expectedByteLength) || input.expectedByteLength < 0 || input.expectedByteLength > MAX_UPLOAD_BYTE_LENGTH || !isIdempotencyKey(input.idempotencyKey)) throw new DriveError("invalid_input");
724
+ if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.parentItemId !== "string" || !ITEM_ID.test(input.parentItemId) || typeof input.expectedByteLength !== "number" || !Number.isSafeInteger(input.expectedByteLength) || input.expectedByteLength < 0 || input.expectedByteLength > MAX_UPLOAD_BYTE_LENGTH || !isSafeFilename(input.displayFilename) || !isMediaType(input.mediaType) || typeof input.callerDeclaredContentDigest !== "string" || !CONTENT_DIGEST.test(input.callerDeclaredContentDigest) || input.protectionClassification !== "ordinary" && input.protectionClassification !== "opaque-encrypted" || !isIdempotencyKey(input.idempotencyKey)) throw new DriveError("invalid_input");
603
725
  return {
604
726
  workspaceId: input.workspaceId,
605
727
  parentItemId: input.parentItemId,
606
728
  expectedByteLength: input.expectedByteLength,
729
+ displayFilename: input.displayFilename,
730
+ mediaType: input.mediaType,
731
+ callerDeclaredContentDigest: input.callerDeclaredContentDigest,
732
+ protectionClassification: input.protectionClassification,
607
733
  idempotencyKey: input.idempotencyKey,
608
734
  ...signal === void 0 ? {} : { signal }
609
735
  };
610
736
  }
737
+ function validateGetUploadStatusInput(value) {
738
+ const input = captureRecord(value, ["workspaceId", "uploadId"], [
739
+ "afterPartNumber",
740
+ "limit",
741
+ "signal"
742
+ ]);
743
+ const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
744
+ if (input.afterPartNumber !== void 0 && (!isSafeInteger(input.afterPartNumber) || input.afterPartNumber > 1e4) || input.limit !== void 0 && (!isSafeInteger(input.limit) || input.limit < 1 || input.limit > 100)) throw new DriveError("invalid_input");
745
+ return {
746
+ ...upload,
747
+ ...input.afterPartNumber === void 0 ? {} : { afterPartNumber: input.afterPartNumber },
748
+ ...input.limit === void 0 ? {} : { limit: input.limit }
749
+ };
750
+ }
751
+ function validateCreateUploadPartDescriptorInput(value) {
752
+ const input = captureRecord(value, [
753
+ "workspaceId",
754
+ "uploadId",
755
+ "partNumber",
756
+ "checksumSha256"
757
+ ], ["signal"]);
758
+ const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
759
+ if (!isPartNumber(input.partNumber) || !isPartChecksum(input.checksumSha256)) throw new DriveError("invalid_input");
760
+ return {
761
+ ...upload,
762
+ partNumber: input.partNumber,
763
+ checksumSha256: input.checksumSha256
764
+ };
765
+ }
766
+ function validateRecordUploadPartInput(value) {
767
+ const input = captureRecord(value, [
768
+ "workspaceId",
769
+ "uploadId",
770
+ "partNumber",
771
+ "expectedUploadRevision",
772
+ "byteLength",
773
+ "etag",
774
+ "checksumSha256"
775
+ ], ["signal"]);
776
+ const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
777
+ if (!isPartNumber(input.partNumber) || !isSafeInteger(input.expectedUploadRevision) || input.expectedUploadRevision >= Number.MAX_SAFE_INTEGER || !isSafeInteger(input.byteLength) || input.byteLength < 1 || input.byteLength > UPLOAD_PART_BYTE_LENGTH$1 || !isEtag$1(input.etag) || !isPartChecksum(input.checksumSha256)) throw new DriveError("invalid_input");
778
+ return {
779
+ ...upload,
780
+ partNumber: input.partNumber,
781
+ expectedUploadRevision: input.expectedUploadRevision,
782
+ byteLength: input.byteLength,
783
+ etag: input.etag,
784
+ checksumSha256: input.checksumSha256
785
+ };
786
+ }
787
+ function validateCompleteUploadInput(value) {
788
+ const input = captureRecord(value, [
789
+ "workspaceId",
790
+ "uploadId",
791
+ "idempotencyKey"
792
+ ], ["signal"]);
793
+ const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
794
+ if (!isIdempotencyKey(input.idempotencyKey)) throw new DriveError("invalid_input");
795
+ return {
796
+ ...upload,
797
+ idempotencyKey: input.idempotencyKey
798
+ };
799
+ }
611
800
  function validateAbortUploadInput(value) {
612
801
  const input = captureRecord(value, ["workspaceId", "uploadId"], ["signal"]);
802
+ return validateUploadPath(input.workspaceId, input.uploadId, input.signal);
803
+ }
804
+ function validateUploadFileInput(value) {
805
+ const input = captureRecord(value, [
806
+ "workspaceId",
807
+ "parentItemId",
808
+ "source",
809
+ "displayFilename",
810
+ "idempotencyKey",
811
+ "completionIdempotencyKey"
812
+ ], [
813
+ "mediaType",
814
+ "protectionClassification",
815
+ "signal",
816
+ "onProgress"
817
+ ]);
613
818
  const signal = validateSignal(input.signal);
614
- if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.uploadId !== "string" || !UPLOAD_ID.test(input.uploadId)) throw new DriveError("invalid_input");
819
+ const mediaType = input.mediaType ?? "application/octet-stream";
820
+ const protectionClassification = input.protectionClassification ?? "ordinary";
821
+ let source;
822
+ let byteLength;
823
+ try {
824
+ if (!(input.source instanceof Blob)) throw new DriveError("invalid_input");
825
+ source = input.source;
826
+ byteLength = source.size;
827
+ } catch (error) {
828
+ if (error instanceof DriveError) throw error;
829
+ throw new DriveError("invalid_input");
830
+ }
831
+ if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.parentItemId !== "string" || !ITEM_ID.test(input.parentItemId) || !Number.isSafeInteger(byteLength) || byteLength < 0 || byteLength > MAX_UPLOAD_BYTE_LENGTH || !isSafeFilename(input.displayFilename) || !isMediaType(mediaType) || protectionClassification !== "ordinary" && protectionClassification !== "opaque-encrypted" || !isIdempotencyKey(input.idempotencyKey) || !isIdempotencyKey(input.completionIdempotencyKey) || input.onProgress !== void 0 && typeof input.onProgress !== "function") throw new DriveError("invalid_input");
615
832
  return {
616
833
  workspaceId: input.workspaceId,
617
- uploadId: input.uploadId,
618
- ...signal === void 0 ? {} : { signal }
834
+ parentItemId: input.parentItemId,
835
+ source,
836
+ byteLength,
837
+ displayFilename: input.displayFilename,
838
+ mediaType,
839
+ protectionClassification,
840
+ idempotencyKey: input.idempotencyKey,
841
+ completionIdempotencyKey: input.completionIdempotencyKey,
842
+ ...signal === void 0 ? {} : { signal },
843
+ ...input.onProgress === void 0 ? {} : { onProgress: input.onProgress }
619
844
  };
620
845
  }
621
846
  function resourcePath(input) {
@@ -702,6 +927,27 @@ function captureArray(value) {
702
927
  function isIdempotencyKey(value) {
703
928
  return typeof value === "string" && IDEMPOTENCY_KEY.test(value);
704
929
  }
930
+ function validateUploadPath(workspaceId, uploadId, signalValue) {
931
+ const signal = validateSignal(signalValue);
932
+ if (typeof workspaceId !== "string" || !WORKSPACE_ID.test(workspaceId) || typeof uploadId !== "string" || !UPLOAD_ID.test(uploadId)) throw new DriveError("invalid_input");
933
+ return {
934
+ workspaceId,
935
+ uploadId,
936
+ ...signal === void 0 ? {} : { signal }
937
+ };
938
+ }
939
+ function isPartNumber(value) {
940
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 && value <= 1e4;
941
+ }
942
+ function isPartChecksum(value) {
943
+ return typeof value === "string" && PART_CHECKSUM.test(value);
944
+ }
945
+ function isEtag$1(value) {
946
+ return typeof value === "string" && value.length >= 1 && value.length <= 1024 && /^[\x20-\x7e]+$/.test(value);
947
+ }
948
+ function isMediaType(value) {
949
+ return typeof value === "string" && value.length <= 255 && /^[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?\/[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?$/.test(value);
950
+ }
705
951
  function isExpiry(value) {
706
952
  return value === null || isSafeInteger(value);
707
953
  }
@@ -1188,7 +1434,7 @@ async function execute(runtime, signal, preconditionStatus, send, successStatuse
1188
1434
  signal: operationSignal
1189
1435
  });
1190
1436
  if (!capturedResponse) throw new DriveError("network_error");
1191
- return await parseResponse(capturedResponse, operationSignal, preconditionStatus, successStatuses, guard, allowsQuotaExceeded, allowedErrorCodes);
1437
+ return guard === null ? await parseNoContentResponse(capturedResponse, operationSignal, preconditionStatus, successStatuses, allowedErrorCodes) : await parseResponse(capturedResponse, operationSignal, preconditionStatus, successStatuses, guard, allowsQuotaExceeded, allowedErrorCodes);
1192
1438
  } catch (error) {
1193
1439
  if (operation.didTimeout()) throw new DriveError("timeout");
1194
1440
  if (error instanceof DriveError) throw error;
@@ -1276,8 +1522,32 @@ const CURRENT_WORKSPACE_ERROR_CODES = Object.freeze([
1276
1522
  "invalid_request",
1277
1523
  "service_unavailable"
1278
1524
  ]);
1279
- function createDriveClientInternal(config) {
1280
- const runtime = createClientRuntime(config);
1525
+ const TRANSFER_ERROR_CODES = Object.freeze([
1526
+ "authentication_required",
1527
+ "identity_authority_unavailable",
1528
+ "permission_denied",
1529
+ "resource_not_found",
1530
+ "invalid_request",
1531
+ "precondition_failed",
1532
+ "upload_recovery_required",
1533
+ "service_unavailable"
1534
+ ]);
1535
+ const STATUS_ERROR_CODES = Object.freeze([
1536
+ "authentication_required",
1537
+ "identity_authority_unavailable",
1538
+ "permission_denied",
1539
+ "resource_not_found",
1540
+ "invalid_request",
1541
+ "service_unavailable"
1542
+ ]);
1543
+ const CREATE_UPLOAD_ERROR_CODES = Object.freeze([
1544
+ ...TRANSFER_ERROR_CODES,
1545
+ "invalid_idempotency_key",
1546
+ "idempotency_conflict",
1547
+ "quota_exceeded"
1548
+ ]);
1549
+ const COMPLETE_UPLOAD_ERROR_CODES = Object.freeze([...TRANSFER_ERROR_CODES, "invalid_idempotency_key"]);
1550
+ function createDriveOperations(runtime) {
1281
1551
  return Object.freeze({
1282
1552
  getCurrentWorkspace: (input) => getCurrentWorkspace(runtime, input),
1283
1553
  listFolderChildren: (input) => listFolderChildren(runtime, input),
@@ -1288,6 +1558,10 @@ function createDriveClientInternal(config) {
1288
1558
  updateItemPermission: (input) => updateItemPermission(runtime, input),
1289
1559
  revokeItemPermission: (input) => revokeItemPermission(runtime, input),
1290
1560
  createUpload: (input) => createUpload(runtime, input),
1561
+ getUploadStatus: (input) => getUploadStatus(runtime, input),
1562
+ createUploadPartDescriptor: (input) => createUploadPartDescriptor(runtime, input),
1563
+ recordUploadPart: (input) => recordUploadPart(runtime, input),
1564
+ completeUpload: (input) => completeUpload(runtime, input),
1291
1565
  abortUpload: (input) => abortUpload(runtime, input)
1292
1566
  });
1293
1567
  }
@@ -1405,11 +1679,81 @@ async function createUpload(runtime, input) {
1405
1679
  },
1406
1680
  body: {
1407
1681
  parentItemId: validated.parentItemId,
1408
- expectedByteLength: validated.expectedByteLength
1682
+ expectedByteLength: validated.expectedByteLength,
1683
+ displayFilename: validated.displayFilename,
1684
+ mediaType: validated.mediaType,
1685
+ callerDeclaredContentDigest: validated.callerDeclaredContentDigest,
1686
+ protectionClassification: validated.protectionClassification
1687
+ }
1688
+ }),
1689
+ ...requestOptions
1690
+ }), [200, 201], (value) => isUploadSession(value, validated.expectedByteLength), true, CREATE_UPLOAD_ERROR_CODES);
1691
+ }
1692
+ async function getUploadStatus(runtime, input) {
1693
+ const validated = validateGetUploadStatusInput(input);
1694
+ const afterPartNumber = validated.afterPartNumber ?? 0;
1695
+ const limit = validated.limit ?? 100;
1696
+ return execute(runtime, validated.signal, null, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}", {
1697
+ ...operationOptions("getUploadStatus", { params: {
1698
+ path: {
1699
+ workspaceId: validated.workspaceId,
1700
+ uploadId: validated.uploadId
1701
+ },
1702
+ query: {
1703
+ ...validated.afterPartNumber === void 0 ? {} : { afterPartNumber: String(validated.afterPartNumber) },
1704
+ ...validated.limit === void 0 ? {} : { limit: String(validated.limit) }
1705
+ }
1706
+ } }),
1707
+ ...requestOptions
1708
+ }), [200], (value) => isUploadStatus(value, afterPartNumber, limit), false, STATUS_ERROR_CODES);
1709
+ }
1710
+ async function createUploadPartDescriptor(runtime, input) {
1711
+ const validated = validateCreateUploadPartDescriptorInput(input);
1712
+ return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/parts", {
1713
+ ...operationOptions("createUploadPartDescriptor", {
1714
+ params: { path: {
1715
+ workspaceId: validated.workspaceId,
1716
+ uploadId: validated.uploadId
1717
+ } },
1718
+ body: {
1719
+ partNumber: validated.partNumber,
1720
+ checksumSha256: validated.checksumSha256
1409
1721
  }
1410
1722
  }),
1411
1723
  ...requestOptions
1412
- }), [200, 201], (value) => isUploadQuotaReservation(value) && value.workspaceId === validated.workspaceId && value.parentItemId === validated.parentItemId && value.expectedByteLength === validated.expectedByteLength && value.state === "reserved" && value.terminalReason === null && value.terminalAtEpochMilliseconds === null, true);
1724
+ }), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, validated.checksumSha256, new URL(runtime.baseUrl).protocol === "http:"), false, TRANSFER_ERROR_CODES);
1725
+ }
1726
+ async function recordUploadPart(runtime, input) {
1727
+ const validated = validateRecordUploadPartInput(input);
1728
+ return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/parts/{partNumber}", {
1729
+ ...operationOptions("recordUploadPart", {
1730
+ params: { path: {
1731
+ workspaceId: validated.workspaceId,
1732
+ uploadId: validated.uploadId,
1733
+ partNumber: String(validated.partNumber)
1734
+ } },
1735
+ body: {
1736
+ expectedUploadRevision: validated.expectedUploadRevision,
1737
+ byteLength: validated.byteLength,
1738
+ etag: validated.etag,
1739
+ checksumSha256: validated.checksumSha256
1740
+ }
1741
+ }),
1742
+ ...requestOptions
1743
+ }), [200], (value) => isUploadPartResult(value, validated.partNumber, validated.expectedUploadRevision), false, TRANSFER_ERROR_CODES);
1744
+ }
1745
+ async function completeUpload(runtime, input) {
1746
+ const validated = validateCompleteUploadInput(input);
1747
+ return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}/complete", {
1748
+ ...operationOptions("completeUpload", { params: {
1749
+ path: {
1750
+ workspaceId: validated.workspaceId,
1751
+ uploadId: validated.uploadId
1752
+ },
1753
+ header: { "Idempotency-Key": validated.idempotencyKey }
1754
+ } }),
1755
+ ...requestOptions
1756
+ }), [200], (value) => isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
1413
1757
  }
1414
1758
  async function abortUpload(runtime, input) {
1415
1759
  const validated = validateAbortUploadInput(input);
@@ -1419,12 +1763,717 @@ async function abortUpload(runtime, input) {
1419
1763
  uploadId: validated.uploadId
1420
1764
  } } }),
1421
1765
  ...requestOptions
1422
- }), [200], (value) => isUploadQuotaReservation(value) && value.workspaceId === validated.workspaceId && value.uploadId === validated.uploadId && value.state === "released" && value.terminalReason === "aborted" && value.terminalAtEpochMilliseconds !== null);
1766
+ }), [204], null, false, TRANSFER_ERROR_CODES);
1767
+ }
1768
+ //#endregion
1769
+ //#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/_u64.js
1770
+ const fromNumH = (n) => n / 2 ** 32 | 0;
1771
+ const fromNumL = (n) => n >>> 0;
1772
+ function setU64FromNum(view, byteOffset, n, isLE) {
1773
+ const h = fromNumH(n);
1774
+ const l = fromNumL(n);
1775
+ view.setUint32(byteOffset, isLE ? l : h, isLE);
1776
+ view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
1777
+ }
1778
+ //#endregion
1779
+ //#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/utils.js
1780
+ function isBytes(a) {
1781
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
1782
+ }
1783
+ const atitle = (title) => title ? `"${title}" ` : "";
1784
+ function anumber(n, title = "") {
1785
+ if (typeof n !== "number") throw new TypeError(atitle(title) + "expected number, got " + typeof n);
1786
+ if (!Number.isSafeInteger(n) || n < 0) throw new RangeError(atitle(title) + "expected integer >= 0, got " + n);
1787
+ return n;
1788
+ }
1789
+ function abytes(value, length, title = "") {
1790
+ if (isBytes(value) && (length === void 0 || value.length === length)) return value;
1791
+ if (length !== void 0) anumber(length, "length");
1792
+ const bytes = isBytes(value);
1793
+ const ofLen = length !== void 0 ? ` of length ${length}` : "";
1794
+ const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
1795
+ const message = atitle(title) + "expected Uint8Array" + ofLen + ", got " + got;
1796
+ if (!bytes) throw new TypeError(message);
1797
+ throw new RangeError(message);
1798
+ }
1799
+ const aobject = (value, label) => {
1800
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
1801
+ };
1802
+ function aexists(instance, checkFinished = true) {
1803
+ if (instance.destroyed) throw new Error("hash was destroyed");
1804
+ if (checkFinished && instance.finished) throw new Error("digest() was already called");
1805
+ }
1806
+ function aoutput(out, instance) {
1807
+ abytes(out, void 0, "output");
1808
+ const min = instance.outputLen;
1809
+ if (!(out.length >= min)) throw new RangeError("\"output\" expected length >= " + min);
1810
+ }
1811
+ function clean(...arrays) {
1812
+ for (let i = 0; i < arrays.length; i++) arrays[i].fill(0);
1813
+ }
1814
+ function createView(arr) {
1815
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
1816
+ }
1817
+ function rotr(word, shift) {
1818
+ return word << 32 - shift | word >>> shift;
1819
+ }
1820
+ const hasHexBuiltin = (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
1821
+ const hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
1822
+ function bytesToHex(bytes) {
1823
+ abytes(bytes);
1824
+ if (hasHexBuiltin) return bytes.toHex();
1825
+ let hex = "";
1826
+ for (let i = 0; i < bytes.length; i++) hex += hexes[bytes[i]];
1827
+ return hex;
1828
+ }
1829
+ function checkOpts(defaults, opts, title = "opts") {
1830
+ aobject(defaults, "defaults");
1831
+ if (opts !== void 0) aobject(opts, title);
1832
+ return Object.assign(defaults, opts);
1833
+ }
1834
+ function createHasher(hashCons, info = {}) {
1835
+ if (typeof hashCons !== "function") throw new TypeError("\"hashCons\" expected function, got type=" + typeof hashCons);
1836
+ info = checkOpts({}, info, "info");
1837
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
1838
+ const tmp = hashCons(void 0);
1839
+ hashC.outputLen = tmp.outputLen;
1840
+ hashC.blockLen = tmp.blockLen;
1841
+ hashC.canXOF = tmp.canXOF;
1842
+ hashC.create = (opts) => hashCons(opts);
1843
+ Object.assign(hashC, info);
1844
+ return Object.freeze(hashC);
1845
+ }
1846
+ const oidNist = (suffix) => ({ oid: Uint8Array.from([
1847
+ 6,
1848
+ 9,
1849
+ 96,
1850
+ 134,
1851
+ 72,
1852
+ 1,
1853
+ 101,
1854
+ 3,
1855
+ 4,
1856
+ 2,
1857
+ suffix
1858
+ ]) });
1859
+ //#endregion
1860
+ //#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/_md.js
1861
+ function Chi(a, b, c) {
1862
+ return a & b ^ ~a & c;
1863
+ }
1864
+ function Maj(a, b, c) {
1865
+ return a & b ^ a & c ^ b & c;
1866
+ }
1867
+ var HashMD = class {
1868
+ blockLen;
1869
+ outputLen;
1870
+ canXOF = false;
1871
+ padOffset;
1872
+ isLE;
1873
+ buffer;
1874
+ view;
1875
+ finished = false;
1876
+ length = 0;
1877
+ pos = 0;
1878
+ destroyed = false;
1879
+ constructor(blockLen, outputLen, padOffset, isLE) {
1880
+ this.blockLen = blockLen;
1881
+ this.outputLen = outputLen;
1882
+ this.padOffset = padOffset;
1883
+ this.isLE = isLE;
1884
+ this.buffer = new Uint8Array(blockLen);
1885
+ this.view = createView(this.buffer);
1886
+ }
1887
+ update(data) {
1888
+ aexists(this);
1889
+ abytes(data);
1890
+ const { view, buffer, blockLen } = this;
1891
+ const len = data.length;
1892
+ let processed = false;
1893
+ for (let pos = 0; pos < len;) {
1894
+ const take = Math.min(blockLen - this.pos, len - pos);
1895
+ if (take === blockLen) {
1896
+ const dataView = createView(data);
1897
+ for (; blockLen <= len - pos; pos += blockLen) this.process(dataView, pos);
1898
+ processed = true;
1899
+ continue;
1900
+ }
1901
+ buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
1902
+ this.pos += take;
1903
+ pos += take;
1904
+ if (this.pos === blockLen) {
1905
+ this.process(view, 0);
1906
+ this.pos = 0;
1907
+ processed = true;
1908
+ }
1909
+ }
1910
+ this.length += data.length;
1911
+ if (processed) this.roundClean();
1912
+ return this;
1913
+ }
1914
+ digestInto(out) {
1915
+ aexists(this);
1916
+ aoutput(out, this);
1917
+ this.finished = true;
1918
+ const { buffer, view, blockLen, isLE } = this;
1919
+ let { pos } = this;
1920
+ buffer[pos++] = 128;
1921
+ buffer.fill(0, pos);
1922
+ if (this.padOffset > blockLen - pos) {
1923
+ this.process(view, 0);
1924
+ buffer.fill(0);
1925
+ }
1926
+ setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
1927
+ this.process(view, 0);
1928
+ this.roundClean();
1929
+ const oview = out === buffer ? view : createView(out);
1930
+ const len = this.outputLen;
1931
+ const outLen = len / 4;
1932
+ const state = this.get();
1933
+ if (len % 4 || outLen > state.length) throw new Error("invalid outputLen");
1934
+ for (let i = 0; i < outLen; i++) oview.setUint32(4 * i, state[i], isLE);
1935
+ }
1936
+ digest() {
1937
+ const { buffer, outputLen } = this;
1938
+ this.digestInto(buffer);
1939
+ const res = buffer.slice(0, outputLen);
1940
+ this.destroy();
1941
+ return res;
1942
+ }
1943
+ _cloneIntoMeta(to) {
1944
+ const { buffer, length, finished, destroyed, pos } = this;
1945
+ to.destroyed = destroyed;
1946
+ to.finished = finished;
1947
+ to.length = length;
1948
+ to.pos = pos;
1949
+ if (pos) to.buffer.set(buffer);
1950
+ return to;
1951
+ }
1952
+ clone() {
1953
+ return this._cloneInto();
1954
+ }
1955
+ };
1956
+ const SHA256_IV = Uint32Array.from([
1957
+ 1779033703,
1958
+ 3144134277,
1959
+ 1013904242,
1960
+ 2773480762,
1961
+ 1359893119,
1962
+ 2600822924,
1963
+ 528734635,
1964
+ 1541459225
1965
+ ]);
1966
+ //#endregion
1967
+ //#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/sha2.js
1968
+ const SHA256_K = Uint32Array.from([
1969
+ 1116352408,
1970
+ 1899447441,
1971
+ 3049323471,
1972
+ 3921009573,
1973
+ 961987163,
1974
+ 1508970993,
1975
+ 2453635748,
1976
+ 2870763221,
1977
+ 3624381080,
1978
+ 310598401,
1979
+ 607225278,
1980
+ 1426881987,
1981
+ 1925078388,
1982
+ 2162078206,
1983
+ 2614888103,
1984
+ 3248222580,
1985
+ 3835390401,
1986
+ 4022224774,
1987
+ 264347078,
1988
+ 604807628,
1989
+ 770255983,
1990
+ 1249150122,
1991
+ 1555081692,
1992
+ 1996064986,
1993
+ 2554220882,
1994
+ 2821834349,
1995
+ 2952996808,
1996
+ 3210313671,
1997
+ 3336571891,
1998
+ 3584528711,
1999
+ 113926993,
2000
+ 338241895,
2001
+ 666307205,
2002
+ 773529912,
2003
+ 1294757372,
2004
+ 1396182291,
2005
+ 1695183700,
2006
+ 1986661051,
2007
+ 2177026350,
2008
+ 2456956037,
2009
+ 2730485921,
2010
+ 2820302411,
2011
+ 3259730800,
2012
+ 3345764771,
2013
+ 3516065817,
2014
+ 3600352804,
2015
+ 4094571909,
2016
+ 275423344,
2017
+ 430227734,
2018
+ 506948616,
2019
+ 659060556,
2020
+ 883997877,
2021
+ 958139571,
2022
+ 1322822218,
2023
+ 1537002063,
2024
+ 1747873779,
2025
+ 1955562222,
2026
+ 2024104815,
2027
+ 2227730452,
2028
+ 2361852424,
2029
+ 2428436474,
2030
+ 2756734187,
2031
+ 3204031479,
2032
+ 3329325298
2033
+ ]);
2034
+ const SHA256_W = new Uint32Array(64);
2035
+ var SHA2_32B = class extends HashMD {
2036
+ A = 0;
2037
+ B = 0;
2038
+ C = 0;
2039
+ D = 0;
2040
+ E = 0;
2041
+ F = 0;
2042
+ G = 0;
2043
+ H = 0;
2044
+ constructor(outputLen, IV) {
2045
+ super(64, outputLen, 8, false);
2046
+ this.A = IV[0] | 0;
2047
+ this.B = IV[1] | 0;
2048
+ this.C = IV[2] | 0;
2049
+ this.D = IV[3] | 0;
2050
+ this.E = IV[4] | 0;
2051
+ this.F = IV[5] | 0;
2052
+ this.G = IV[6] | 0;
2053
+ this.H = IV[7] | 0;
2054
+ }
2055
+ get() {
2056
+ const { A, B, C, D, E, F, G, H } = this;
2057
+ return [
2058
+ A,
2059
+ B,
2060
+ C,
2061
+ D,
2062
+ E,
2063
+ F,
2064
+ G,
2065
+ H
2066
+ ];
2067
+ }
2068
+ set(A, B, C, D, E, F, G, H) {
2069
+ this.A = A | 0;
2070
+ this.B = B | 0;
2071
+ this.C = C | 0;
2072
+ this.D = D | 0;
2073
+ this.E = E | 0;
2074
+ this.F = F | 0;
2075
+ this.G = G | 0;
2076
+ this.H = H | 0;
2077
+ }
2078
+ _cloneInto(to) {
2079
+ (to ||= new this.constructor()).set(...this.get());
2080
+ return this._cloneIntoMeta(to);
2081
+ }
2082
+ process(view, offset) {
2083
+ for (let i = 0; i < 16; i++, offset += 4) SHA256_W[i] = view.getUint32(offset, false);
2084
+ for (let i = 16; i < 64; i++) {
2085
+ const W15 = SHA256_W[i - 15];
2086
+ const W2 = SHA256_W[i - 2];
2087
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
2088
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
2089
+ SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
2090
+ }
2091
+ let { A, B, C, D, E, F, G, H } = this;
2092
+ for (let i = 0; i < 64; i++) {
2093
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
2094
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
2095
+ const T2 = (rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22)) + Maj(A, B, C) | 0;
2096
+ H = G;
2097
+ G = F;
2098
+ F = E;
2099
+ E = D + T1 | 0;
2100
+ D = C;
2101
+ C = B;
2102
+ B = A;
2103
+ A = T1 + T2 | 0;
2104
+ }
2105
+ A = A + this.A | 0;
2106
+ B = B + this.B | 0;
2107
+ C = C + this.C | 0;
2108
+ D = D + this.D | 0;
2109
+ E = E + this.E | 0;
2110
+ F = F + this.F | 0;
2111
+ G = G + this.G | 0;
2112
+ H = H + this.H | 0;
2113
+ this.set(A, B, C, D, E, F, G, H);
2114
+ }
2115
+ roundClean() {
2116
+ clean(SHA256_W);
2117
+ }
2118
+ destroy() {
2119
+ this.destroyed = true;
2120
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
2121
+ clean(this.buffer);
2122
+ }
2123
+ };
2124
+ var _SHA256 = class extends SHA2_32B {
2125
+ constructor() {
2126
+ super(32, SHA256_IV);
2127
+ }
2128
+ };
2129
+ const sha256 = createHasher(() => new _SHA256(), oidNist(1));
2130
+ //#endregion
2131
+ //#region src/internal/client/upload.ts
2132
+ const UPLOAD_PART_BYTE_LENGTH = 32 * 1024 * 1024;
2133
+ const STATUS_PAGE_LIMIT = 100;
2134
+ const STATUS_PAGE_MAXIMUM = 100;
2135
+ const ABORT_DEADLINE_MILLISECONDS = 5e3;
2136
+ async function uploadFileInternal(runtime, input, controls) {
2137
+ const validated = validateUploadFileInput(input);
2138
+ const totalPartCount = Math.ceil(validated.byteLength / UPLOAD_PART_BYTE_LENGTH);
2139
+ emitProgress(validated.onProgress, "preparing", 0, validated.byteLength, 0, totalPartCount);
2140
+ let session;
2141
+ try {
2142
+ const digests = await hashSource(validated.source, validated.byteLength, totalPartCount, validated.signal);
2143
+ const created = await controls.createUpload({
2144
+ workspaceId: validated.workspaceId,
2145
+ parentItemId: validated.parentItemId,
2146
+ expectedByteLength: validated.byteLength,
2147
+ displayFilename: validated.displayFilename,
2148
+ mediaType: validated.mediaType,
2149
+ callerDeclaredContentDigest: digests.callerDeclaredContentDigest,
2150
+ protectionClassification: validated.protectionClassification,
2151
+ idempotencyKey: validated.idempotencyKey,
2152
+ ...validated.signal === void 0 ? {} : { signal: validated.signal }
2153
+ });
2154
+ session = created.data;
2155
+ assertSessionPolicy(session, validated.byteLength, totalPartCount, created.status, created.requestId);
2156
+ const resumed = await readResumeState(controls, validated, session, digests);
2157
+ emitProgress(validated.onProgress, "uploading", resumed.confirmedByteLength, validated.byteLength, resumed.confirmedParts.size, totalPartCount);
2158
+ if (resumed.readyResult) {
2159
+ emitProgress(validated.onProgress, "completing", resumed.confirmedByteLength, validated.byteLength, resumed.confirmedParts.size, totalPartCount);
2160
+ return resumed.readyResult;
2161
+ }
2162
+ let revision = resumed.revision;
2163
+ let confirmedByteLength = resumed.confirmedByteLength;
2164
+ let confirmedPartCount = resumed.confirmedParts.size;
2165
+ if (resumed.lifecycle === "uploading") for (const partNumber of pendingUploadPartNumbers(session.partCount, resumed.confirmedParts)) {
2166
+ const index = partNumber - 1;
2167
+ throwIfCallerAborted(validated.signal);
2168
+ const start = index * session.partByteLength;
2169
+ const end = Math.min(start + session.partByteLength, validated.byteLength);
2170
+ const expectedByteLength = end - start;
2171
+ const checksumSha256 = digests.partChecksums[index];
2172
+ if (!checksumSha256) throw new DriveError("invalid_response");
2173
+ const descriptorResult = await controls.createUploadPartDescriptor({
2174
+ workspaceId: validated.workspaceId,
2175
+ uploadId: session.uploadId,
2176
+ partNumber,
2177
+ checksumSha256,
2178
+ ...validated.signal === void 0 ? {} : { signal: validated.signal }
2179
+ });
2180
+ const descriptor = descriptorResult.data;
2181
+ if (descriptor.expectedByteLength !== expectedByteLength || descriptor.expiresAtEpochMilliseconds > session.expiresAtEpochMilliseconds) throw new DriveError("invalid_response", {
2182
+ status: descriptorResult.status,
2183
+ requestId: descriptorResult.requestId
2184
+ });
2185
+ const etag = await putPart(runtime, descriptor, slicePart(validated.source, start, end, expectedByteLength), checksumSha256, validated.signal);
2186
+ revision = await recordPartWithReconciliation(controls, validated, session, partNumber, revision, expectedByteLength, etag, checksumSha256);
2187
+ confirmedByteLength += expectedByteLength;
2188
+ confirmedPartCount += 1;
2189
+ emitProgress(validated.onProgress, "uploading", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
2190
+ }
2191
+ emitProgress(validated.onProgress, "completing", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
2192
+ return await completeWithReconciliation(controls, validated, session, digests);
2193
+ } catch (error) {
2194
+ if (validated.signal?.aborted && session) await bestEffortAbort(controls, validated.workspaceId, session.uploadId);
2195
+ if (error instanceof DriveError) throw error;
2196
+ throw validated.signal?.aborted ? new DriveError("aborted") : new DriveError("invalid_input");
2197
+ }
2198
+ }
2199
+ function* pendingUploadPartNumbers(partCount, confirmedParts) {
2200
+ for (let partNumber = 1; partNumber <= partCount; partNumber += 1) if (!confirmedParts.has(partNumber)) yield partNumber;
2201
+ }
2202
+ async function readResumeState(controls, input, session, digests) {
2203
+ const confirmedParts = new Set();
2204
+ let confirmedByteLength = 0;
2205
+ let afterPartNumber = 0;
2206
+ let baseline;
2207
+ let baselineRequestId;
2208
+ let readyResult;
2209
+ for (let pageNumber = 0; pageNumber < STATUS_PAGE_MAXIMUM; pageNumber += 1) {
2210
+ const result = await controls.getUploadStatus({
2211
+ workspaceId: input.workspaceId,
2212
+ uploadId: session.uploadId,
2213
+ afterPartNumber,
2214
+ limit: STATUS_PAGE_LIMIT,
2215
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2216
+ });
2217
+ const status = result.data;
2218
+ assertStatusMatchesSession(status, session);
2219
+ if (baseline) assertSameStatusSnapshot(status, baseline);
2220
+ else {
2221
+ baseline = status;
2222
+ baselineRequestId = result.requestId;
2223
+ }
2224
+ for (const part of status.confirmedParts) {
2225
+ const expectedChecksum = digests.partChecksums[part.partNumber - 1];
2226
+ if (!expectedChecksum || part.checksumSha256 !== expectedChecksum || confirmedParts.has(part.partNumber)) throw new DriveError("invalid_response", {
2227
+ status: result.status,
2228
+ requestId: result.requestId
2229
+ });
2230
+ confirmedParts.add(part.partNumber);
2231
+ confirmedByteLength += expectedPartByteLength(input.byteLength, part.partNumber);
2232
+ }
2233
+ if (status.lifecycle === "ready" && status.ready) {
2234
+ assertReadyMatchesInput(status.ready, session, input, digests, result.requestId);
2235
+ readyResult = resultFromStatus(result, status.ready);
2236
+ }
2237
+ if (status.nextAfterPartNumber === null) break;
2238
+ if (pageNumber === STATUS_PAGE_MAXIMUM - 1) throw new DriveError("invalid_response", {
2239
+ status: result.status,
2240
+ requestId: result.requestId
2241
+ });
2242
+ afterPartNumber = status.nextAfterPartNumber;
2243
+ }
2244
+ if (!baseline) throw new DriveError("invalid_response");
2245
+ if (session.mode === "presigned-multipart" && [
2246
+ "completing",
2247
+ "provider-completed",
2248
+ "ready"
2249
+ ].includes(baseline.lifecycle) && confirmedParts.size !== session.partCount) throw new DriveError("invalid_response");
2250
+ failForTerminalStatus(baseline.lifecycle, baselineRequestId);
2251
+ return Object.freeze({
2252
+ revision: baseline.revision,
2253
+ confirmedParts,
2254
+ confirmedByteLength,
2255
+ lifecycle: baseline.lifecycle,
2256
+ ...readyResult === void 0 ? {} : { readyResult }
2257
+ });
2258
+ }
2259
+ async function recordPartWithReconciliation(controls, input, session, partNumber, expectedUploadRevision, byteLength, etag, checksumSha256) {
2260
+ const record = (revision) => controls.recordUploadPart({
2261
+ workspaceId: input.workspaceId,
2262
+ uploadId: session.uploadId,
2263
+ partNumber,
2264
+ expectedUploadRevision: revision,
2265
+ byteLength,
2266
+ etag,
2267
+ checksumSha256,
2268
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2269
+ });
2270
+ try {
2271
+ return (await record(expectedUploadRevision)).data.revision;
2272
+ } catch (error) {
2273
+ if (!isAmbiguousControlFailure(error) || input.signal?.aborted) throw error;
2274
+ const statusResult = await controls.getUploadStatus({
2275
+ workspaceId: input.workspaceId,
2276
+ uploadId: session.uploadId,
2277
+ afterPartNumber: partNumber - 1,
2278
+ limit: 1,
2279
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2280
+ });
2281
+ const status = statusResult.data;
2282
+ assertStatusMatchesSession(status, session);
2283
+ failForTerminalStatus(status.lifecycle, statusResult.requestId);
2284
+ const confirmed = status.confirmedParts.find((part) => part.partNumber === partNumber);
2285
+ if (confirmed) {
2286
+ if (confirmed.checksumSha256 !== checksumSha256) throw new DriveError("invalid_response", {
2287
+ status: statusResult.status,
2288
+ requestId: statusResult.requestId
2289
+ });
2290
+ return status.revision;
2291
+ }
2292
+ if (status.lifecycle !== "uploading") throw new DriveError("precondition_failed");
2293
+ return (await record(status.revision)).data.revision;
2294
+ }
2295
+ }
2296
+ async function completeWithReconciliation(controls, input, session, digests) {
2297
+ try {
2298
+ const completed = await controls.completeUpload({
2299
+ workspaceId: input.workspaceId,
2300
+ uploadId: session.uploadId,
2301
+ idempotencyKey: input.completionIdempotencyKey,
2302
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2303
+ });
2304
+ assertReadyMatchesInput(completed.data, session, input, digests, completed.requestId);
2305
+ return completed;
2306
+ } catch (error) {
2307
+ if (!isAmbiguousControlFailure(error) || input.signal?.aborted) throw error;
2308
+ const statusResult = await controls.getUploadStatus({
2309
+ workspaceId: input.workspaceId,
2310
+ uploadId: session.uploadId,
2311
+ afterPartNumber: 0,
2312
+ limit: 1,
2313
+ ...input.signal === void 0 ? {} : { signal: input.signal }
2314
+ });
2315
+ const status = statusResult.data;
2316
+ assertStatusMatchesSession(status, session);
2317
+ if (status.lifecycle !== "ready" || !status.ready) throw error;
2318
+ assertReadyMatchesInput(status.ready, session, input, digests, statusResult.requestId);
2319
+ return resultFromStatus(statusResult, status.ready);
2320
+ }
2321
+ }
2322
+ async function hashSource(source, byteLength, partCount, signal) {
2323
+ const fullHash = sha256.create();
2324
+ const partChecksums = [];
2325
+ for (let index = 0; index < partCount; index += 1) {
2326
+ throwIfCallerAborted(signal);
2327
+ const start = index * UPLOAD_PART_BYTE_LENGTH;
2328
+ const end = Math.min(start + UPLOAD_PART_BYTE_LENGTH, byteLength);
2329
+ const part = slicePart(source, start, end, end - start);
2330
+ let buffer;
2331
+ try {
2332
+ buffer = signal ? await raceWithAbort(part.arrayBuffer(), signal) : await part.arrayBuffer();
2333
+ } catch (error) {
2334
+ if (error instanceof DriveError) throw error;
2335
+ throw signal?.aborted ? new DriveError("aborted") : new DriveError("invalid_input");
2336
+ }
2337
+ if (buffer.byteLength !== end - start) throw new DriveError("invalid_input");
2338
+ const bytes = new Uint8Array(buffer);
2339
+ fullHash.update(bytes);
2340
+ partChecksums.push(toBase64(sha256(bytes)));
2341
+ }
2342
+ return Object.freeze({
2343
+ callerDeclaredContentDigest: `sha256:${bytesToHex(fullHash.digest())}`,
2344
+ partChecksums: Object.freeze(partChecksums)
2345
+ });
2346
+ }
2347
+ async function putPart(runtime, descriptor, part, checksumSha256, callerSignal) {
2348
+ const remainingMilliseconds = descriptor.expiresAtEpochMilliseconds - Date.now();
2349
+ if (remainingMilliseconds < 1) throw new DriveError("invalid_response");
2350
+ const operation = createOperationSignal(callerSignal, Math.min(runtime.timeoutMilliseconds, remainingMilliseconds));
2351
+ let response;
2352
+ try {
2353
+ response = await raceWithAbort(runtime.fetchImplementation(descriptor.url, {
2354
+ method: descriptor.method,
2355
+ body: part,
2356
+ headers: descriptor.headers,
2357
+ credentials: "omit",
2358
+ cache: "no-store",
2359
+ redirect: "error",
2360
+ referrerPolicy: "no-referrer",
2361
+ signal: operation.signal
2362
+ }), operation.signal);
2363
+ if (!(response instanceof Response)) throw new DriveError("invalid_response");
2364
+ const etag = response.headers.get("etag");
2365
+ const responseChecksum = response.headers.get("x-amz-checksum-sha256");
2366
+ if (response.status < 200 || response.status > 299 || !isEtag(etag) || responseChecksum !== checksumSha256) throw new DriveError("invalid_response", { status: response.status });
2367
+ return etag;
2368
+ } catch (error) {
2369
+ if (operation.didTimeout()) throw new DriveError("timeout");
2370
+ if (callerSignal?.aborted) throw new DriveError("aborted");
2371
+ if (error instanceof DriveError) throw error;
2372
+ throw new DriveError("network_error");
2373
+ } finally {
2374
+ operation.dispose();
2375
+ response?.body?.cancel().catch(() => {});
2376
+ }
2377
+ }
2378
+ function assertSessionPolicy(session, byteLength, partCount, status, requestId) {
2379
+ const expectedMode = byteLength === 0 ? "server-mediated-zero-byte" : "presigned-multipart";
2380
+ if (session.mode !== expectedMode || session.partByteLength !== UPLOAD_PART_BYTE_LENGTH || session.partCount !== partCount || session.expiresAtEpochMilliseconds <= Date.now()) throw new DriveError("invalid_response", {
2381
+ status,
2382
+ requestId
2383
+ });
2384
+ }
2385
+ function assertStatusMatchesSession(status, session) {
2386
+ if (status.itemId !== session.itemId || status.versionId !== session.versionId || status.uploadId !== session.uploadId || status.mode !== session.mode || status.revision < session.revision || status.partPolicy.partByteLength !== session.partByteLength || status.partPolicy.partCount !== session.partCount || status.partPolicy.maxParts !== 1e4 || status.expiresAtEpochMilliseconds !== session.expiresAtEpochMilliseconds) throw new DriveError("invalid_response");
2387
+ }
2388
+ function assertSameStatusSnapshot(status, baseline) {
2389
+ if (status.itemId !== baseline.itemId || status.versionId !== baseline.versionId || status.uploadId !== baseline.uploadId || status.mode !== baseline.mode || status.lifecycle !== baseline.lifecycle || status.revision !== baseline.revision || status.partPolicy.partByteLength !== baseline.partPolicy.partByteLength || status.partPolicy.partCount !== baseline.partPolicy.partCount || status.partPolicy.maxParts !== baseline.partPolicy.maxParts || status.expiresAtEpochMilliseconds !== baseline.expiresAtEpochMilliseconds || JSON.stringify(status.ready) !== JSON.stringify(baseline.ready)) throw new DriveError("invalid_response");
2390
+ }
2391
+ function assertReadyMatchesInput(ready, session, input, digests, requestId) {
2392
+ if (ready.itemId !== session.itemId || ready.versionId !== session.versionId || ready.uploadId !== session.uploadId || ready.byteLength !== input.byteLength || ready.callerDeclaredContentDigest !== digests.callerDeclaredContentDigest || ready.displayFilename !== input.displayFilename || ready.mediaType !== input.mediaType) throw new DriveError("invalid_response", {
2393
+ status: 200,
2394
+ requestId
2395
+ });
2396
+ }
2397
+ function failForTerminalStatus(lifecycle, requestId) {
2398
+ if (lifecycle === "initiating" || lifecycle === "recovery-required") throw new DriveError("upload_recovery_required", {
2399
+ status: 409,
2400
+ ...requestId === void 0 ? {} : { requestId }
2401
+ });
2402
+ if (lifecycle === "aborting" || lifecycle === "aborted") throw new DriveError("precondition_failed", {
2403
+ status: 409,
2404
+ ...requestId === void 0 ? {} : { requestId }
2405
+ });
2406
+ }
2407
+ function resultFromStatus(status, ready) {
2408
+ return Object.freeze({
2409
+ data: ready,
2410
+ status: status.status,
2411
+ requestId: status.requestId,
2412
+ validators: status.validators
2413
+ });
2414
+ }
2415
+ function expectedPartByteLength(byteLength, partNumber) {
2416
+ return Math.min(UPLOAD_PART_BYTE_LENGTH, byteLength - (partNumber - 1) * UPLOAD_PART_BYTE_LENGTH);
2417
+ }
2418
+ function slicePart(source, start, end, expectedByteLength) {
2419
+ try {
2420
+ const part = source.slice(start, end);
2421
+ if (!(part instanceof Blob) || part.size !== expectedByteLength) throw new DriveError("invalid_input");
2422
+ return part;
2423
+ } catch (error) {
2424
+ if (error instanceof DriveError) throw error;
2425
+ throw new DriveError("invalid_input");
2426
+ }
2427
+ }
2428
+ function emitProgress(callback, phase, confirmedByteLength, totalByteLength, confirmedPartCount, totalPartCount) {
2429
+ if (!callback) return;
2430
+ const progress = Object.freeze({
2431
+ phase,
2432
+ confirmedByteLength,
2433
+ totalByteLength,
2434
+ confirmedPartCount,
2435
+ totalPartCount
2436
+ });
2437
+ try {
2438
+ callback(progress);
2439
+ } catch {}
2440
+ }
2441
+ async function bestEffortAbort(controls, workspaceId, uploadId) {
2442
+ const controller = new AbortController();
2443
+ const timeout = setTimeout(() => controller.abort(), ABORT_DEADLINE_MILLISECONDS);
2444
+ try {
2445
+ await controls.abortUpload({
2446
+ workspaceId,
2447
+ uploadId,
2448
+ signal: controller.signal
2449
+ });
2450
+ } catch {} finally {
2451
+ clearTimeout(timeout);
2452
+ }
2453
+ }
2454
+ function isAmbiguousControlFailure(value) {
2455
+ return value instanceof DriveError && (value.code === "network_error" || value.code === "timeout" || value.code === "invalid_response");
2456
+ }
2457
+ function throwIfCallerAborted(signal) {
2458
+ if (signal?.aborted) throw new DriveError("aborted");
2459
+ }
2460
+ function toBase64(bytes) {
2461
+ let binary = "";
2462
+ for (const byte of bytes) binary += String.fromCharCode(byte);
2463
+ return btoa(binary);
2464
+ }
2465
+ function isEtag(value) {
2466
+ return value !== null && value.length >= 1 && value.length <= 1024 && /^[\x20-\x7e]+$/.test(value);
1423
2467
  }
1424
2468
  //#endregion
1425
2469
  //#region src/client.ts
1426
2470
  function createDriveClient(config) {
1427
- return createDriveClientInternal(config);
2471
+ const runtime = createClientRuntime(config);
2472
+ const operations = createDriveOperations(runtime);
2473
+ return Object.freeze({
2474
+ ...operations,
2475
+ uploadFile: (input) => uploadFileInternal(runtime, input, operations)
2476
+ });
1428
2477
  }
1429
2478
  //#endregion
1430
2479
  export { DRIVE_API_ERROR_CODES, DRIVE_API_ERROR_MESSAGES, DriveError, createDriveClient };