@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/CHANGELOG.md +12 -0
- package/README.md +15 -12
- package/dist/client.d.ts +2 -2
- package/dist/client.js +180 -20
- package/dist/contract.d.ts +261 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +180 -20
- package/dist/server.d.ts +20 -2
- package/dist/server.js +127 -13
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
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
|
|
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,
|
|
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, ["
|
|
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).
|
|
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,
|
|
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),
|
|
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
|
-
|
|
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,
|
|
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
|
|
3098
|
-
|
|
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
|
|
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
|
|
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,
|
|
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, ["
|
|
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).
|
|
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,
|
|
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 };
|