@finueva/drive 0.5.1 → 0.7.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
@@ -584,12 +584,14 @@ function isUploadStatus(value, afterPartNumber, limit) {
584
584
  "nextAfterPartNumber",
585
585
  "expiresAtEpochMilliseconds",
586
586
  "ready"
587
- ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || ![
587
+ ], ["verification"]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || ![
588
588
  "initiating",
589
589
  "recovery-required",
590
590
  "uploading",
591
591
  "completing",
592
592
  "provider-completed",
593
+ "verifying",
594
+ "failed",
593
595
  "ready",
594
596
  "aborting",
595
597
  "aborted"
@@ -599,18 +601,38 @@ function isUploadStatus(value, afterPartNumber, limit) {
599
601
  "maxParts"
600
602
  ]) || 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;
601
603
  let previousPartNumber = afterPartNumber;
604
+ if (value.verification !== void 0) {
605
+ const progress = value.verification;
606
+ if (!isExactRecord(progress, [
607
+ "state",
608
+ "verifiedByteLength",
609
+ "totalByteLength",
610
+ "revision"
611
+ ]) || ![
612
+ "pending",
613
+ "verified",
614
+ "failed"
615
+ ].includes(String(progress.state)) || !isSafeInteger$1(progress.verifiedByteLength) || !isSafeInteger$1(progress.totalByteLength) || progress.totalByteLength > MAX_UPLOAD_BYTE_LENGTH$1 || progress.verifiedByteLength > progress.totalByteLength || !isSafeInteger$1(progress.revision) || progress.state === "verified" && progress.verifiedByteLength !== progress.totalByteLength) return false;
616
+ Object.freeze(progress);
617
+ }
618
+ if (["verifying", "failed"].includes(String(value.lifecycle)) && value.verification === void 0) return false;
602
619
  for (const part of value.confirmedParts) {
603
620
  if (!isExactRecord(part, ["partNumber", "checksumSha256"]) || !isSafeInteger$1(part.partNumber) || part.partNumber <= previousPartNumber || part.partNumber > value.partPolicy.partCount || !isPartChecksum$1(part.checksumSha256)) return false;
604
621
  previousPartNumber = part.partNumber;
605
622
  }
606
- 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;
623
+ 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 || !isExactRecord(value.verification, [
624
+ "state",
625
+ "verifiedByteLength",
626
+ "totalByteLength",
627
+ "revision"
628
+ ]) || value.verification.state !== "verified" || value.verification.totalByteLength !== value.ready.byteLength)) return false;
607
629
  Object.freeze(value.partPolicy);
608
630
  for (const part of value.confirmedParts) Object.freeze(part);
609
631
  Object.freeze(value.confirmedParts);
610
632
  Object.freeze(value);
611
633
  return true;
612
634
  }
613
- function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allowInsecureHttp) {
635
+ function isUploadPartDescriptor(value, expectedPartNumber, allowInsecureHttp, contentMd5) {
614
636
  if (!isExactRecord(value, [
615
637
  "url",
616
638
  "method",
@@ -618,7 +640,7 @@ function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allow
618
640
  "partNumber",
619
641
  "expectedByteLength",
620
642
  "expiresAtEpochMilliseconds"
621
- ]) || !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;
643
+ ]) || !isSignedTransferUrl(value.url, allowInsecureHttp) || value.method !== "PUT" || !contentMd5 || !isExactRecord(value.headers, ["content-md5"]) || value.headers["content-md5"] !== contentMd5 || 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;
622
644
  Object.freeze(value.headers);
623
645
  Object.freeze(value);
624
646
  return true;
@@ -642,6 +664,19 @@ function isReadyUpload(value, expected) {
642
664
  Object.freeze(value);
643
665
  return true;
644
666
  }
667
+ function isPendingUpload(value, uploadId) {
668
+ if (!isExactRecord(value, [
669
+ "itemId",
670
+ "versionId",
671
+ "uploadId",
672
+ "state",
673
+ "verifiedByteLength",
674
+ "totalByteLength",
675
+ "verificationRevision"
676
+ ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || value.uploadId !== uploadId || value.state !== "verifying" || !isSafeInteger$1(value.verifiedByteLength) || !isSafeInteger$1(value.totalByteLength) || value.totalByteLength > MAX_UPLOAD_BYTE_LENGTH$1 || value.verifiedByteLength > value.totalByteLength || !isSafeInteger$1(value.verificationRevision)) return false;
677
+ Object.freeze(value);
678
+ return true;
679
+ }
645
680
  function isPartChecksum$1(value) {
646
681
  return typeof value === "string" && /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(value);
647
682
  }
@@ -781,9 +816,9 @@ function isSafeCapabilityUrl(value) {
781
816
  return false;
782
817
  }
783
818
  }
784
- function isExactRecord(value, keys) {
819
+ function isExactRecord(value, keys, optional = []) {
785
820
  if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
786
- return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
821
+ return Object.keys(value).every((key) => keys.includes(key) || optional.includes(key)) && keys.every((key) => Object.hasOwn(value, key));
787
822
  }
788
823
  //#endregion
789
824
  //#region src/internal/client/request.ts
@@ -1112,14 +1147,17 @@ function validateCreateUploadPartDescriptorInput(value) {
1112
1147
  "workspaceId",
1113
1148
  "uploadId",
1114
1149
  "partNumber",
1115
- "checksumSha256"
1150
+ "checksumSha256",
1151
+ "contentMd5"
1116
1152
  ], ["signal"]);
1117
1153
  const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
1118
1154
  if (!isPartNumber(input.partNumber) || !isPartChecksum(input.checksumSha256)) throw new DriveError("invalid_input");
1155
+ if (typeof input.contentMd5 !== "string" || !/^[A-Za-z0-9+/]{21}[AQgw]==$/.test(input.contentMd5)) throw new DriveError("invalid_input");
1119
1156
  return {
1120
1157
  ...upload,
1121
1158
  partNumber: input.partNumber,
1122
- checksumSha256: input.checksumSha256
1159
+ checksumSha256: input.checksumSha256,
1160
+ contentMd5: input.contentMd5
1123
1161
  };
1124
1162
  }
1125
1163
  function validateRecordUploadPartInput(value) {
@@ -2437,7 +2475,7 @@ async function getUploadStatus(runtime, input) {
2437
2475
  }
2438
2476
  } }),
2439
2477
  ...requestOptions
2440
- }), [200], (value) => isUploadStatus(value, afterPartNumber, limit), false, STATUS_ERROR_CODES);
2478
+ }), [200], (value) => isUploadStatus(value, afterPartNumber, limit) && value.uploadId === validated.uploadId, false, STATUS_ERROR_CODES);
2441
2479
  }
2442
2480
  async function createUploadPartDescriptor(runtime, input) {
2443
2481
  const validated = validateCreateUploadPartDescriptorInput(input);
@@ -2449,11 +2487,12 @@ async function createUploadPartDescriptor(runtime, input) {
2449
2487
  } },
2450
2488
  body: {
2451
2489
  partNumber: validated.partNumber,
2452
- checksumSha256: validated.checksumSha256
2490
+ checksumSha256: validated.checksumSha256,
2491
+ contentMd5: validated.contentMd5
2453
2492
  }
2454
2493
  }),
2455
2494
  ...requestOptions
2456
- }), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, validated.checksumSha256, new URL(runtime.baseUrl).protocol === "http:"), false, TRANSFER_ERROR_CODES);
2495
+ }), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, new URL(runtime.baseUrl).protocol === "http:", validated.contentMd5), false, TRANSFER_ERROR_CODES);
2457
2496
  }
2458
2497
  async function recordUploadPart(runtime, input) {
2459
2498
  const validated = validateRecordUploadPartInput(input);
@@ -2485,7 +2524,7 @@ async function completeUpload(runtime, input) {
2485
2524
  header: { "Idempotency-Key": validated.idempotencyKey }
2486
2525
  } }),
2487
2526
  ...requestOptions
2488
- }), [200], (value) => isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
2527
+ }), [200, 202], (value, status) => status === 202 ? isPendingUpload(value, validated.uploadId) : isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
2489
2528
  }
2490
2529
  async function abortUpload(runtime, input) {
2491
2530
  const validated = validateAbortUploadInput(input);
@@ -2549,6 +2588,9 @@ function createView(arr) {
2549
2588
  function rotr(word, shift) {
2550
2589
  return word << 32 - shift | word >>> shift;
2551
2590
  }
2591
+ function rotl(word, shift) {
2592
+ return word << shift | word >>> 32 - shift >>> 0;
2593
+ }
2552
2594
  const hasHexBuiltin = (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
2553
2595
  const hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
2554
2596
  function bytesToHex(bytes) {
@@ -2860,6 +2902,115 @@ var _SHA256 = class extends SHA2_32B {
2860
2902
  };
2861
2903
  const sha256 = createHasher(() => new _SHA256(), oidNist(1));
2862
2904
  //#endregion
2905
+ //#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/legacy.js
2906
+ const SHA1_IV = Uint32Array.from([
2907
+ 1732584193,
2908
+ 4023233417,
2909
+ 2562383102,
2910
+ 271733878,
2911
+ 3285377520
2912
+ ]);
2913
+ const p32 = Math.pow(2, 32);
2914
+ const K = Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));
2915
+ const MD5_IV = SHA1_IV.slice(0, 4);
2916
+ const MD5_W = new Uint32Array(16);
2917
+ const MD5_SHIFTS = (() => {
2918
+ const S = [
2919
+ [
2920
+ 7,
2921
+ 12,
2922
+ 17,
2923
+ 22
2924
+ ],
2925
+ [
2926
+ 5,
2927
+ 9,
2928
+ 14,
2929
+ 20
2930
+ ],
2931
+ [
2932
+ 4,
2933
+ 11,
2934
+ 16,
2935
+ 23
2936
+ ],
2937
+ [
2938
+ 6,
2939
+ 10,
2940
+ 15,
2941
+ 21
2942
+ ]
2943
+ ];
2944
+ return Uint8Array.from({ length: 64 }, (_, i) => S[Math.floor(i / 16)][i % 4]);
2945
+ })();
2946
+ var _MD5 = class extends HashMD {
2947
+ A = MD5_IV[0] | 0;
2948
+ B = MD5_IV[1] | 0;
2949
+ C = MD5_IV[2] | 0;
2950
+ D = MD5_IV[3] | 0;
2951
+ constructor() {
2952
+ super(64, 16, 8, true);
2953
+ }
2954
+ get() {
2955
+ const { A, B, C, D } = this;
2956
+ return [
2957
+ A,
2958
+ B,
2959
+ C,
2960
+ D
2961
+ ];
2962
+ }
2963
+ set(A, B, C, D) {
2964
+ this.A = A | 0;
2965
+ this.B = B | 0;
2966
+ this.C = C | 0;
2967
+ this.D = D | 0;
2968
+ }
2969
+ _cloneInto(to) {
2970
+ (to ||= new this.constructor()).set(...this.get());
2971
+ return this._cloneIntoMeta(to);
2972
+ }
2973
+ process(view, offset) {
2974
+ for (let i = 0; i < 16; i++, offset += 4) MD5_W[i] = view.getUint32(offset, true);
2975
+ let { A, B, C, D } = this;
2976
+ for (let i = 0; i < 64; i++) {
2977
+ let F, g;
2978
+ if (i < 16) {
2979
+ F = Chi(B, C, D);
2980
+ g = i;
2981
+ } else if (i < 32) {
2982
+ F = Chi(D, B, C);
2983
+ g = (5 * i + 1) % 16;
2984
+ } else if (i < 48) {
2985
+ F = B ^ C ^ D;
2986
+ g = (3 * i + 5) % 16;
2987
+ } else {
2988
+ F = C ^ (B | ~D);
2989
+ g = 7 * i % 16;
2990
+ }
2991
+ F = F + A + K[i] + MD5_W[g];
2992
+ A = D;
2993
+ D = C;
2994
+ C = B;
2995
+ B = B + rotl(F, MD5_SHIFTS[i]);
2996
+ }
2997
+ A = A + this.A | 0;
2998
+ B = B + this.B | 0;
2999
+ C = C + this.C | 0;
3000
+ D = D + this.D | 0;
3001
+ this.set(A, B, C, D);
3002
+ }
3003
+ roundClean() {
3004
+ clean(MD5_W);
3005
+ }
3006
+ destroy() {
3007
+ this.destroyed = true;
3008
+ this.set(0, 0, 0, 0);
3009
+ clean(this.buffer);
3010
+ }
3011
+ };
3012
+ const md5 = createHasher(() => new _MD5());
3013
+ //#endregion
2863
3014
  //#region src/internal/client/upload.ts
2864
3015
  const UPLOAD_PART_BYTE_LENGTH = 32 * 1024 * 1024;
2865
3016
  const STATUS_PAGE_LIMIT = 100;
@@ -2907,6 +3058,7 @@ async function uploadFileInternal(runtime, input, controls) {
2907
3058
  uploadId: session.uploadId,
2908
3059
  partNumber,
2909
3060
  checksumSha256,
3061
+ contentMd5: digests.partMd5s[index],
2910
3062
  ...validated.signal === void 0 ? {} : { signal: validated.signal }
2911
3063
  });
2912
3064
  const descriptor = descriptorResult.data;
@@ -2914,14 +3066,16 @@ async function uploadFileInternal(runtime, input, controls) {
2914
3066
  status: descriptorResult.status,
2915
3067
  requestId: descriptorResult.requestId
2916
3068
  });
2917
- const etag = await putPart(runtime, descriptor, slicePart(validated.source, start, end, expectedByteLength), checksumSha256, validated.signal);
3069
+ const etag = await putPart(runtime, descriptor, slicePart(validated.source, start, end, expectedByteLength), validated.signal);
2918
3070
  revision = await recordPartWithReconciliation(controls, validated, session, partNumber, revision, expectedByteLength, etag, checksumSha256);
2919
3071
  confirmedByteLength += expectedByteLength;
2920
3072
  confirmedPartCount += 1;
2921
3073
  emitProgress(validated.onProgress, "uploading", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
2922
3074
  }
2923
3075
  emitProgress(validated.onProgress, "completing", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
2924
- return await completeWithReconciliation(controls, validated, session, digests);
3076
+ const completed = await completeWithReconciliation(controls, validated, session, digests);
3077
+ if (completed.data.state === "verifying") emitProgress(validated.onProgress, "verifying", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
3078
+ return completed;
2925
3079
  } catch (error) {
2926
3080
  if (validated.signal?.aborted && session) await bestEffortAbort(controls, validated.workspaceId, session.uploadId);
2927
3081
  if (error instanceof DriveError) throw error;
@@ -2977,6 +3131,7 @@ async function readResumeState(controls, input, session, digests) {
2977
3131
  if (session.mode === "presigned-multipart" && [
2978
3132
  "completing",
2979
3133
  "provider-completed",
3134
+ "verifying",
2980
3135
  "ready"
2981
3136
  ].includes(baseline.lifecycle) && confirmedParts.size !== session.partCount) throw new DriveError("invalid_response");
2982
3137
  failForTerminalStatus(baseline.lifecycle, baselineRequestId);
@@ -3033,7 +3188,8 @@ async function completeWithReconciliation(controls, input, session, digests) {
3033
3188
  idempotencyKey: input.completionIdempotencyKey,
3034
3189
  ...input.signal === void 0 ? {} : { signal: input.signal }
3035
3190
  });
3036
- assertReadyMatchesInput(completed.data, session, input, digests, completed.requestId);
3191
+ if (completed.data.state === "ready") assertReadyMatchesInput(completed.data, session, input, digests, completed.requestId);
3192
+ else if (completed.data.itemId !== session.itemId || completed.data.versionId !== session.versionId || completed.data.uploadId !== session.uploadId || completed.data.totalByteLength !== input.byteLength) throw new DriveError("invalid_response");
3037
3193
  return completed;
3038
3194
  } catch (error) {
3039
3195
  if (!isAmbiguousControlFailure(error) || input.signal?.aborted) throw error;
@@ -3054,6 +3210,7 @@ async function completeWithReconciliation(controls, input, session, digests) {
3054
3210
  async function hashSource(source, byteLength, partCount, signal) {
3055
3211
  const fullHash = sha256.create();
3056
3212
  const partChecksums = [];
3213
+ const partMd5s = [];
3057
3214
  for (let index = 0; index < partCount; index += 1) {
3058
3215
  throwIfCallerAborted(signal);
3059
3216
  const start = index * UPLOAD_PART_BYTE_LENGTH;
@@ -3070,13 +3227,15 @@ async function hashSource(source, byteLength, partCount, signal) {
3070
3227
  const bytes = new Uint8Array(buffer);
3071
3228
  fullHash.update(bytes);
3072
3229
  partChecksums.push(toBase64(sha256(bytes)));
3230
+ partMd5s.push(toBase64(md5(bytes)));
3073
3231
  }
3074
3232
  return Object.freeze({
3075
3233
  callerDeclaredContentDigest: `sha256:${bytesToHex(fullHash.digest())}`,
3076
- partChecksums: Object.freeze(partChecksums)
3234
+ partChecksums: Object.freeze(partChecksums),
3235
+ partMd5s: Object.freeze(partMd5s)
3077
3236
  });
3078
3237
  }
3079
- async function putPart(runtime, descriptor, part, checksumSha256, callerSignal) {
3238
+ async function putPart(runtime, descriptor, part, callerSignal) {
3080
3239
  const remainingMilliseconds = descriptor.expiresAtEpochMilliseconds - Date.now();
3081
3240
  if (remainingMilliseconds < 1) throw new DriveError("invalid_response");
3082
3241
  const operation = createOperationSignal(callerSignal, Math.min(runtime.timeoutMilliseconds, remainingMilliseconds));
@@ -3094,8 +3253,9 @@ async function putPart(runtime, descriptor, part, checksumSha256, callerSignal)
3094
3253
  }), operation.signal);
3095
3254
  if (!(response instanceof Response)) throw new DriveError("invalid_response");
3096
3255
  const etag = response.headers.get("etag");
3097
- const responseChecksum = response.headers.get("x-amz-checksum-sha256");
3098
- if (response.status < 200 || response.status > 299 || !isEtag(etag) || responseChecksum !== checksumSha256) throw new DriveError("invalid_response", { status: response.status });
3256
+ const md5Response = response.headers.get("content-md5");
3257
+ const checksumMatches = md5Response === null || md5Response === descriptor.headers["content-md5"];
3258
+ if (response.status < 200 || response.status > 299 || !isEtag(etag) || !checksumMatches) throw new DriveError("invalid_response", { status: response.status });
3099
3259
  return etag;
3100
3260
  } catch (error) {
3101
3261
  if (operation.didTimeout()) throw new DriveError("timeout");
@@ -3131,7 +3291,7 @@ function failForTerminalStatus(lifecycle, requestId) {
3131
3291
  status: 409,
3132
3292
  ...requestId === void 0 ? {} : { requestId }
3133
3293
  });
3134
- if (lifecycle === "aborting" || lifecycle === "aborted") throw new DriveError("precondition_failed", {
3294
+ if (lifecycle === "aborting" || lifecycle === "aborted" || lifecycle === "failed") throw new DriveError("precondition_failed", {
3135
3295
  status: 409,
3136
3296
  ...requestId === void 0 ? {} : { requestId }
3137
3297
  });
package/dist/server.d.ts CHANGED
@@ -1,5 +1,23 @@
1
- import { $ as UpdateItemInput, A as ListItemVersionsInput, C as FolderPage, D as GetUploadStatusInput, E as GetItemVersionInput, F as ManagedItemVersionPage, I as ManagedItemVersionResource, J as RestoreItemInput, K as ReadyUpload, L as ManagedItemVersionRestoreResult, M as ManagedDownloadRestorePending, N as ManagedItemMetadata, O as ListFolderChildrenInput, P as ManagedItemVersion, Q as TrashItemInput, R as ManagedLifecycleItem, S as FolderItem, T as GetItemInput, W as ProtectionClassification, Y as RestoreItemVersionInput, Z as SearchWorkspaceItemsInput, c as CurrentWorkspace, ct as UploadSession, dt as WorkspaceItemSearchPage, j as ManagedDownloadDescriptor, l as DeleteItemInput, lt as UploadStatus, n as CompleteUploadInput, o as CreateUploadInput, ot as UploadPartDescriptor, q as RecordUploadPartInput, r as CreateDownloadInput, s as CreateUploadPartDescriptorInput, st as UploadPartResult, t as AbortUploadInput, tt as UploadConfirmedPart, u as DownloadItemResult, ut as WorkspaceItemSearchItem, v as DriveServerClient, w as GetCurrentWorkspaceInput, y as DriveServerClientConfig } from "./contract.js";
1
+ import { $ as TrashItemInput, A as ListItemVersionsInput, C as FolderPage, D as GetUploadStatusInput, E as GetItemVersionInput, F as ManagedItemVersionPage, G as ProtectionClassification, I as ManagedItemVersionResource, J as RecordUploadPartInput, L as ManagedItemVersionRestoreResult, M as ManagedDownloadRestorePending, N as ManagedItemMetadata, O as ListFolderChildrenInput, P as ManagedItemVersion, Q as SearchWorkspaceItemsInput, R as ManagedLifecycleItem, S as FolderItem, T as GetItemInput, X as RestoreItemVersionInput, Y as RestoreItemInput, c as CurrentWorkspace, ct as UploadPartDescriptor, dt as UploadStatus, et as UpdateItemInput, ft as WorkspaceItemSearchItem, h as DriveOperationResult, j as ManagedDownloadDescriptor, l as DeleteItemInput, lt as UploadPartResult, m as DriveCredentialProvider, mt as operations, n as CompleteUploadInput, nt as UploadCompletion, o as CreateUploadInput, pt as WorkspaceItemSearchPage, q as ReadyUpload, r as CreateDownloadInput, rt as UploadConfirmedPart, s as CreateUploadPartDescriptorInput, t as AbortUploadInput, u as DownloadItemResult, ut as UploadSession, v as DriveServerClient, w as GetCurrentWorkspaceInput, y as DriveServerClientConfig, z as PendingUpload } from "./contract.js";
2
+ //#region src/internal/provisioning.d.ts
3
+ type Operation = operations["provisionManagedWorkspace"];
4
+ type ProvisionWorkspaceCommand = Operation["requestBody"]["content"]["application/json"];
5
+ type ProvisionWorkspaceResult = Operation["responses"][200]["content"]["application/json"] | Operation["responses"][201]["content"]["application/json"];
6
+ interface DriveProvisioningClientConfig {
7
+ baseUrl: string;
8
+ environment: ProvisionWorkspaceCommand["environment"];
9
+ getProvisioningCredential: DriveCredentialProvider;
10
+ fetch?: typeof globalThis.fetch;
11
+ timeoutMilliseconds?: number;
12
+ }
13
+ interface DriveProvisioningClient {
14
+ provisionWorkspace(command: ProvisionWorkspaceCommand, options?: {
15
+ signal?: AbortSignal;
16
+ }): Promise<DriveOperationResult<ProvisionWorkspaceResult, 200 | 201>>;
17
+ }
18
+ declare function createDriveProvisioningClient(config: DriveProvisioningClientConfig): DriveProvisioningClient;
19
+ //#endregion
2
20
  //#region src/server.d.ts
3
21
  declare function createDriveServerClient(config: DriveServerClientConfig): DriveServerClient;
4
22
  //#endregion
5
- export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, type DeleteItemInput, type DownloadItemResult, type DriveServerClient, type DriveServerClientConfig, type FolderItem, type FolderPage, type GetCurrentWorkspaceInput, type GetItemInput, type GetItemVersionInput, type GetUploadStatusInput, type ListFolderChildrenInput, type ListItemVersionsInput, type ManagedDownloadDescriptor, type ManagedDownloadRestorePending, type ManagedItemMetadata, type ManagedItemVersion, type ManagedItemVersionPage, type ManagedItemVersionResource, type ManagedItemVersionRestoreResult, type ManagedLifecycleItem, type ProtectionClassification, type ReadyUpload, type RecordUploadPartInput, type RestoreItemInput, type RestoreItemVersionInput, type SearchWorkspaceItemsInput, type TrashItemInput, type UpdateItemInput, type UploadConfirmedPart, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveServerClient };
23
+ export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, type DeleteItemInput, type DownloadItemResult, type DriveProvisioningClient, type DriveProvisioningClientConfig, type DriveServerClient, type DriveServerClientConfig, type FolderItem, type FolderPage, type GetCurrentWorkspaceInput, type GetItemInput, type GetItemVersionInput, type GetUploadStatusInput, type ListFolderChildrenInput, type ListItemVersionsInput, type ManagedDownloadDescriptor, type ManagedDownloadRestorePending, type ManagedItemMetadata, type ManagedItemVersion, type ManagedItemVersionPage, type ManagedItemVersionResource, type ManagedItemVersionRestoreResult, type ManagedLifecycleItem, type PendingUpload, type ProtectionClassification, type ProvisionWorkspaceCommand, type ProvisionWorkspaceResult, type ReadyUpload, type RecordUploadPartInput, type RestoreItemInput, type RestoreItemVersionInput, type SearchWorkspaceItemsInput, type TrashItemInput, type UpdateItemInput, type UploadCompletion, type UploadConfirmedPart, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveProvisioningClient, createDriveServerClient };
package/dist/server.js CHANGED
@@ -584,12 +584,14 @@ function isUploadStatus(value, afterPartNumber, limit) {
584
584
  "nextAfterPartNumber",
585
585
  "expiresAtEpochMilliseconds",
586
586
  "ready"
587
- ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || ![
587
+ ], ["verification"]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || typeof value.uploadId !== "string" || !UPLOAD_ID$1.test(value.uploadId) || value.mode !== "presigned-multipart" && value.mode !== "server-mediated-zero-byte" || ![
588
588
  "initiating",
589
589
  "recovery-required",
590
590
  "uploading",
591
591
  "completing",
592
592
  "provider-completed",
593
+ "verifying",
594
+ "failed",
593
595
  "ready",
594
596
  "aborting",
595
597
  "aborted"
@@ -599,18 +601,38 @@ function isUploadStatus(value, afterPartNumber, limit) {
599
601
  "maxParts"
600
602
  ]) || value.partPolicy.partByteLength !== UPLOAD_PART_BYTE_LENGTH$1 || !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;
601
603
  let previousPartNumber = afterPartNumber;
604
+ if (value.verification !== void 0) {
605
+ const progress = value.verification;
606
+ if (!isExactRecord(progress, [
607
+ "state",
608
+ "verifiedByteLength",
609
+ "totalByteLength",
610
+ "revision"
611
+ ]) || ![
612
+ "pending",
613
+ "verified",
614
+ "failed"
615
+ ].includes(String(progress.state)) || !isSafeInteger$1(progress.verifiedByteLength) || !isSafeInteger$1(progress.totalByteLength) || progress.totalByteLength > MAX_UPLOAD_BYTE_LENGTH$1 || progress.verifiedByteLength > progress.totalByteLength || !isSafeInteger$1(progress.revision) || progress.state === "verified" && progress.verifiedByteLength !== progress.totalByteLength) return false;
616
+ Object.freeze(progress);
617
+ }
618
+ if (["verifying", "failed"].includes(String(value.lifecycle)) && value.verification === void 0) return false;
602
619
  for (const part of value.confirmedParts) {
603
620
  if (!isExactRecord(part, ["partNumber", "checksumSha256"]) || !isSafeInteger$1(part.partNumber) || part.partNumber <= previousPartNumber || part.partNumber > value.partPolicy.partCount || !isPartChecksum$1(part.checksumSha256)) return false;
604
621
  previousPartNumber = part.partNumber;
605
622
  }
606
- 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;
623
+ 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 || !isExactRecord(value.verification, [
624
+ "state",
625
+ "verifiedByteLength",
626
+ "totalByteLength",
627
+ "revision"
628
+ ]) || value.verification.state !== "verified" || value.verification.totalByteLength !== value.ready.byteLength)) return false;
607
629
  Object.freeze(value.partPolicy);
608
630
  for (const part of value.confirmedParts) Object.freeze(part);
609
631
  Object.freeze(value.confirmedParts);
610
632
  Object.freeze(value);
611
633
  return true;
612
634
  }
613
- function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allowInsecureHttp) {
635
+ function isUploadPartDescriptor(value, expectedPartNumber, allowInsecureHttp, contentMd5) {
614
636
  if (!isExactRecord(value, [
615
637
  "url",
616
638
  "method",
@@ -618,7 +640,7 @@ function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allow
618
640
  "partNumber",
619
641
  "expectedByteLength",
620
642
  "expiresAtEpochMilliseconds"
621
- ]) || !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$1 || !isSafeInteger$1(value.expiresAtEpochMilliseconds) || value.expiresAtEpochMilliseconds <= Date.now()) return false;
643
+ ]) || !isSignedTransferUrl(value.url, allowInsecureHttp) || value.method !== "PUT" || !contentMd5 || !isExactRecord(value.headers, ["content-md5"]) || value.headers["content-md5"] !== contentMd5 || value.partNumber !== expectedPartNumber || !isSafeInteger$1(value.expectedByteLength) || value.expectedByteLength < 1 || value.expectedByteLength > UPLOAD_PART_BYTE_LENGTH$1 || !isSafeInteger$1(value.expiresAtEpochMilliseconds) || value.expiresAtEpochMilliseconds <= Date.now()) return false;
622
644
  Object.freeze(value.headers);
623
645
  Object.freeze(value);
624
646
  return true;
@@ -642,6 +664,19 @@ function isReadyUpload(value, expected) {
642
664
  Object.freeze(value);
643
665
  return true;
644
666
  }
667
+ function isPendingUpload(value, uploadId) {
668
+ if (!isExactRecord(value, [
669
+ "itemId",
670
+ "versionId",
671
+ "uploadId",
672
+ "state",
673
+ "verifiedByteLength",
674
+ "totalByteLength",
675
+ "verificationRevision"
676
+ ]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.test(value.versionId) || value.uploadId !== uploadId || value.state !== "verifying" || !isSafeInteger$1(value.verifiedByteLength) || !isSafeInteger$1(value.totalByteLength) || value.totalByteLength > MAX_UPLOAD_BYTE_LENGTH$1 || value.verifiedByteLength > value.totalByteLength || !isSafeInteger$1(value.verificationRevision)) return false;
677
+ Object.freeze(value);
678
+ return true;
679
+ }
645
680
  function isPartChecksum$1(value) {
646
681
  return typeof value === "string" && /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(value);
647
682
  }
@@ -781,9 +816,9 @@ function isSafeCapabilityUrl(value) {
781
816
  return false;
782
817
  }
783
818
  }
784
- function isExactRecord(value, keys) {
819
+ function isExactRecord(value, keys, optional = []) {
785
820
  if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
786
- return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
821
+ return Object.keys(value).every((key) => keys.includes(key) || optional.includes(key)) && keys.every((key) => Object.hasOwn(value, key));
787
822
  }
788
823
  //#endregion
789
824
  //#region src/internal/client/request.ts
@@ -1112,14 +1147,17 @@ function validateCreateUploadPartDescriptorInput(value) {
1112
1147
  "workspaceId",
1113
1148
  "uploadId",
1114
1149
  "partNumber",
1115
- "checksumSha256"
1150
+ "checksumSha256",
1151
+ "contentMd5"
1116
1152
  ], ["signal"]);
1117
1153
  const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
1118
1154
  if (!isPartNumber(input.partNumber) || !isPartChecksum(input.checksumSha256)) throw new DriveError("invalid_input");
1155
+ if (typeof input.contentMd5 !== "string" || !/^[A-Za-z0-9+/]{21}[AQgw]==$/.test(input.contentMd5)) throw new DriveError("invalid_input");
1119
1156
  return {
1120
1157
  ...upload,
1121
1158
  partNumber: input.partNumber,
1122
- checksumSha256: input.checksumSha256
1159
+ checksumSha256: input.checksumSha256,
1160
+ contentMd5: input.contentMd5
1123
1161
  };
1124
1162
  }
1125
1163
  function validateRecordUploadPartInput(value) {
@@ -2398,7 +2436,7 @@ async function getUploadStatus(runtime, input) {
2398
2436
  }
2399
2437
  } }),
2400
2438
  ...requestOptions
2401
- }), [200], (value) => isUploadStatus(value, afterPartNumber, limit), false, STATUS_ERROR_CODES);
2439
+ }), [200], (value) => isUploadStatus(value, afterPartNumber, limit) && value.uploadId === validated.uploadId, false, STATUS_ERROR_CODES);
2402
2440
  }
2403
2441
  async function createUploadPartDescriptor(runtime, input) {
2404
2442
  const validated = validateCreateUploadPartDescriptorInput(input);
@@ -2410,11 +2448,12 @@ async function createUploadPartDescriptor(runtime, input) {
2410
2448
  } },
2411
2449
  body: {
2412
2450
  partNumber: validated.partNumber,
2413
- checksumSha256: validated.checksumSha256
2451
+ checksumSha256: validated.checksumSha256,
2452
+ contentMd5: validated.contentMd5
2414
2453
  }
2415
2454
  }),
2416
2455
  ...requestOptions
2417
- }), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, validated.checksumSha256, new URL(runtime.baseUrl).protocol === "http:"), false, TRANSFER_ERROR_CODES);
2456
+ }), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, new URL(runtime.baseUrl).protocol === "http:", validated.contentMd5), false, TRANSFER_ERROR_CODES);
2418
2457
  }
2419
2458
  async function recordUploadPart(runtime, input) {
2420
2459
  const validated = validateRecordUploadPartInput(input);
@@ -2446,7 +2485,7 @@ async function completeUpload(runtime, input) {
2446
2485
  header: { "Idempotency-Key": validated.idempotencyKey }
2447
2486
  } }),
2448
2487
  ...requestOptions
2449
- }), [200], (value) => isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
2488
+ }), [200, 202], (value, status) => status === 202 ? isPendingUpload(value, validated.uploadId) : isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
2450
2489
  }
2451
2490
  async function abortUpload(runtime, input) {
2452
2491
  const validated = validateAbortUploadInput(input);
@@ -2459,6 +2498,81 @@ async function abortUpload(runtime, input) {
2459
2498
  }), [204], null, false, TRANSFER_ERROR_CODES);
2460
2499
  }
2461
2500
  //#endregion
2501
+ //#region src/internal/provisioning.ts
2502
+ const environments = [
2503
+ "local",
2504
+ "development",
2505
+ "staging",
2506
+ "production"
2507
+ ];
2508
+ const identifier = /^[A-Za-z0-9_-]{1,128}$/;
2509
+ function createDriveProvisioningClient(config) {
2510
+ if (!config || !environments.includes(config.environment)) throw new DriveError("invalid_input");
2511
+ const environment = config.environment;
2512
+ const runtime = createClientRuntime({
2513
+ baseUrl: config.baseUrl,
2514
+ getCredential: config.getProvisioningCredential,
2515
+ ...config.fetch === void 0 ? {} : { fetch: config.fetch },
2516
+ ...config.timeoutMilliseconds === void 0 ? {} : { timeoutMilliseconds: config.timeoutMilliseconds }
2517
+ });
2518
+ return Object.freeze({ async provisionWorkspace(command, options) {
2519
+ if (!exact(command, [
2520
+ "version",
2521
+ "environment",
2522
+ "provisioningId",
2523
+ "workspaceReference",
2524
+ "entitlement"
2525
+ ]) || command.version !== 1 || command.environment !== environment || typeof command.provisioningId !== "string" || !identifier.test(command.provisioningId) || !reference(command.workspaceReference) || !entitlement(command.entitlement)) throw new DriveError("invalid_input");
2526
+ const body = {
2527
+ version: command.version,
2528
+ environment: command.environment,
2529
+ provisioningId: command.provisioningId,
2530
+ workspaceReference: { ...command.workspaceReference },
2531
+ entitlement: { ...command.entitlement }
2532
+ };
2533
+ return execute(runtime, options?.signal, null, (api, boundary) => api.POST("/api/v1/platform/workspaces/provision", {
2534
+ ...boundary,
2535
+ redirect: "manual",
2536
+ body
2537
+ }), [200, 201], (value, status) => validResult(value, status, body), false, [
2538
+ "authentication_required",
2539
+ "permission_denied",
2540
+ "idempotency_conflict",
2541
+ "invalid_request",
2542
+ "identity_authority_unavailable",
2543
+ "service_unavailable"
2544
+ ]);
2545
+ } });
2546
+ }
2547
+ function exact(value, keys) {
2548
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
2549
+ }
2550
+ function reference(value) {
2551
+ return exact(value, ["type", "userId"]) && value.type === "personal" && typeof value.userId === "string" && identifier.test(value.userId) || exact(value, ["type", "organizationId"]) && value.type === "organization" && typeof value.organizationId === "string" && identifier.test(value.organizationId);
2552
+ }
2553
+ function entitlement(value) {
2554
+ return exact(value, [
2555
+ "version",
2556
+ "managedStorageEnabled",
2557
+ "managedStorageByteLimit"
2558
+ ]) && typeof value.version === "number" && Number.isSafeInteger(value.version) && value.version >= 0 && typeof value.managedStorageByteLimit === "number" && Number.isSafeInteger(value.managedStorageByteLimit) && (value.managedStorageEnabled === true && value.managedStorageByteLimit > 0 || value.managedStorageEnabled === false && value.managedStorageByteLimit === 0);
2559
+ }
2560
+ function validResult(value, status, command) {
2561
+ if (!exact(value, ["outcome", "workspace"]) || (status === 201 ? value.outcome !== "committed" : value.outcome !== "replayed" && value.outcome !== "superseded") || !exact(value.workspace, [
2562
+ "workspaceId",
2563
+ "rootVolumeId",
2564
+ "rootItemId",
2565
+ "workspaceReference",
2566
+ "entitlement"
2567
+ ])) return false;
2568
+ const { entitlement: current, ...workspace } = value.workspace;
2569
+ if (!isCurrentWorkspace(workspace) || !entitlement(current)) return false;
2570
+ const actual = workspace.workspaceReference;
2571
+ const expected = command.workspaceReference;
2572
+ if (!(actual.type === "personal" && expected.type === "personal" && actual.userId === expected.userId) && !(actual.type === "organization" && expected.type === "organization" && actual.organizationId === expected.organizationId)) return false;
2573
+ return value.outcome === "superseded" ? current.version > command.entitlement.version : current.version === command.entitlement.version && current.managedStorageEnabled === command.entitlement.managedStorageEnabled && current.managedStorageByteLimit === command.entitlement.managedStorageByteLimit;
2574
+ }
2575
+ //#endregion
2462
2576
  //#region src/server.ts
2463
2577
  function createDriveServerClient(config) {
2464
2578
  const credential = config.credential;
@@ -2471,4 +2585,4 @@ function createDriveServerClient(config) {
2471
2585
  });
2472
2586
  }
2473
2587
  //#endregion
2474
- export { createDriveServerClient };
2588
+ export { createDriveProvisioningClient, createDriveServerClient };