@finueva/drive 0.6.0 → 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 +6 -0
- package/README.md +6 -5
- package/dist/client.d.ts +2 -2
- package/dist/client.js +180 -20
- package/dist/contract.d.ts +38 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +180 -20
- package/dist/server.d.ts +2 -2
- package/dist/server.js +51 -12
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @finueva/drive
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 77546b2: Use portable S3 Content-MD5 transport with mandatory independent server-side whole-file and part SHA-256 verification for all uploads. Descriptor requests require `contentMd5`; there is no legacy transport or profile selector. `completeUpload` and `uploadFile` may return HTTP 202 with a `verifying` result; callers can inspect read-only progress and retry completion with the original idempotency key, or explicitly abort the retained upload. No automatic unbounded polling is performed.
|
|
8
|
+
|
|
3
9
|
## 0.6.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ const matches = await drive.searchWorkspaceItems({
|
|
|
44
44
|
limit: 50,
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
const completionIdempotencyKey = crypto.randomUUID();
|
|
47
48
|
const uploaded = await drive.uploadFile({
|
|
48
49
|
workspaceId: workspace.workspaceId,
|
|
49
50
|
parentItemId: workspace.rootItemId,
|
|
@@ -51,7 +52,7 @@ const uploaded = await drive.uploadFile({
|
|
|
51
52
|
displayFilename: file.name,
|
|
52
53
|
mediaType: file.type || "application/octet-stream",
|
|
53
54
|
idempotencyKey: crypto.randomUUID(),
|
|
54
|
-
completionIdempotencyKey
|
|
55
|
+
completionIdempotencyKey,
|
|
55
56
|
onProgress: ({ phase, confirmedByteLength, totalByteLength }) => {
|
|
56
57
|
renderProgress(phase, confirmedByteLength, totalByteLength);
|
|
57
58
|
},
|
|
@@ -126,15 +127,15 @@ Successful calls return `{ data, status, requestId, validators }`. A successful
|
|
|
126
127
|
|
|
127
128
|
`createDownload` returns a short-lived archive descriptor for the current or an explicit immutable version, one visible `restore-pending` result for cold content, or a no-body `304` operation result whose validators retain the source ETag. Full, closed, open, and suffix ranges use the selected archive object's strong ETag; malformed or multiple ranges are served as full representations, while valid non-overlapping ranges fail with `range_not_satisfiable`. `downloadItem` follows a descriptor with no Drive credential, ambient browser credentials, or referrer and returns the provider body as a backpressured `Response`; it preserves the same `304` and cold-restore results without a provider request. It validates exact status, ETag, identity encoding, length, and `Content-Range`, cancels malformed upstream bodies, and keeps caller cancellation/deadline authority active until the stream closes or is cancelled. It never returns Blob, ArrayBuffer, text, or base64 whole-file convenience values.
|
|
128
129
|
|
|
129
|
-
The six low-level upload methods map directly to the Native API. `createUpload` accepts
|
|
130
|
+
The six low-level upload methods map directly to the Native API. `createUpload` accepts a caller-declared whole-file `sha256:{64 lowercase hex}` digest. Portable S3 is the only supported upload transport, with no profile selector. Descriptor requests require `contentMd5` (canonical base64 MD5), and return a required `content-md5` header. Part SHA-256 declarations and opaque provider ETags remain separate callback fields; MD5 is transport error detection, not content identity.
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
Publication independently verifies archive bytes against both whole-file and part SHA-256 declarations. `getUploadStatus` exposes bounded confirmed-part pages and read-only verification progress once verification is admitted. `completeUpload` and `uploadFile` return `DriveOperationResult<UploadCompletion, 200 | 202>`: inspect `data.state` for `ready` versus `verifying`. A `202` is not publication. Retain its `uploadId` and the original completion idempotency key, inspect status, then call `completeUpload` again with that key when appropriate. The SDK does not start an unbounded polling loop. To cancel after a pending result, call `abortUpload({ workspaceId, uploadId })`, which returns bodyless `204`.
|
|
132
133
|
|
|
133
134
|
`uploadFile` is the browser-safe direct-byte path for a Web `Blob` or `File`. It accepts zero-byte input, hashes the empty input correctly, accepts the server-mediated zero-byte mode, skips part transfer, and completes normally. Nonempty input is incrementally hashed in slices no larger than 32 MiB and is never materialized as a complete `ArrayBuffer`, Blob copy, base64 string, or SDK request body. The fixed policy permits at most 10,000 parts and 312.5 GiB.
|
|
134
135
|
|
|
135
|
-
Each nonempty slice is sent directly to the exact descriptor URL. The
|
|
136
|
+
Each nonempty slice is sent directly to the exact descriptor URL. The SDK computes MD5 with the maintained Noble public API on the same bounded slice as SHA-256. Requests include only descriptor-required headers and use `credentials: "omit"`, `cache: "no-store"`, `redirect: "error"`, and `referrerPolicy: "no-referrer"`. Archive CORS must allow `content-md5` and expose `ETag`; no provider SHA response header is required, and ETags are never interpreted as hashes. If a Content-MD5 response header is exposed, it must match the request. Drive credentials, cookies and file metadata never enter the archive request.
|
|
136
137
|
|
|
137
|
-
Repeating `uploadFile` with the same creation and completion
|
|
138
|
+
Repeating `uploadFile` with the same creation and completion keys explicitly resumes the retained session when replay remains available. Status reads are bounded to 100 pages of 100 parts. The SDK checks session identity, policy, lifecycle, revisions and checksums, skips confirmed parts and never re-uploads a part merely because its callback response was lost. `completing`, `provider-completed` and `verifying` resume completion; failed/aborted/recovery-required states do not pretend to resume. After receiving pending, using its upload ID with low-level status/complete avoids re-hashing the source. Both normal and empty uploads may return pending, and progress observers can receive the `verifying` phase.
|
|
138
139
|
|
|
139
140
|
There is no automatic network or provider retry. If a part-record callback response may have been lost, the SDK performs one bounded status reconciliation before either accepting the confirmed part or recording the same provider evidence once more; it never blindly re-uploads the bytes. If a completion response may have been lost, one status reconciliation returns success only when `ready` is proven. Other transient failures preserve the session for an explicit repeat until server expiry.
|
|
140
141
|
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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, at as UploadFilePhase, c as CurrentWorkspace, ct as UploadPartDescriptor, d as DriveClient, dt as UploadStatus, et as UpdateItemInput, f as DriveClientConfig, ft as WorkspaceItemSearchItem, it as UploadFileInput, j as ManagedDownloadDescriptor, l as DeleteItemInput, lt as UploadPartResult, m as DriveCredentialProvider, n as CompleteUploadInput, nt as UploadCompletion, o as CreateUploadInput, ot as UploadFileProgress, pt as WorkspaceItemSearchPage, q as ReadyUpload, r as CreateDownloadInput, rt as UploadConfirmedPart, s as CreateUploadPartDescriptorInput, st as UploadFileProgressCallback, t as AbortUploadInput, u as DownloadItemResult, ut as UploadSession, w as GetCurrentWorkspaceInput, z as PendingUpload } from "./contract.js";
|
|
2
2
|
//#region src/client.d.ts
|
|
3
3
|
declare function createDriveClient(config: DriveClientConfig): DriveClient;
|
|
4
4
|
//#endregion
|
|
5
|
-
export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, type DeleteItemInput, type DownloadItemResult, type DriveClient, type DriveClientConfig, type DriveCredentialProvider, 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 UploadFileInput, type UploadFilePhase, type UploadFileProgress, type UploadFileProgressCallback, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveClient };
|
|
5
|
+
export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, type DeleteItemInput, type DownloadItemResult, type DriveClient, type DriveClientConfig, type DriveCredentialProvider, 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 ReadyUpload, type RecordUploadPartInput, type RestoreItemInput, type RestoreItemVersionInput, type SearchWorkspaceItemsInput, type TrashItemInput, type UpdateItemInput, type UploadCompletion, type UploadConfirmedPart, type UploadFileInput, type UploadFilePhase, type UploadFileProgress, type UploadFileProgressCallback, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveClient };
|
package/dist/client.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/contract.d.ts
CHANGED
|
@@ -3759,7 +3759,7 @@ interface operations {
|
|
|
3759
3759
|
expiresAtEpochMilliseconds: number;
|
|
3760
3760
|
itemId: string;
|
|
3761
3761
|
/** @enum {string} */
|
|
3762
|
-
lifecycle: "initiating" | "recovery-required" | "uploading" | "completing" | "provider-completed" | "ready" | "aborting" | "aborted";
|
|
3762
|
+
lifecycle: "initiating" | "recovery-required" | "uploading" | "completing" | "provider-completed" | "verifying" | "failed" | "ready" | "aborting" | "aborted";
|
|
3763
3763
|
/** @enum {string} */
|
|
3764
3764
|
mode: "presigned-multipart" | "server-mediated-zero-byte";
|
|
3765
3765
|
nextAfterPartNumber: number | null;
|
|
@@ -3772,7 +3772,7 @@ interface operations {
|
|
|
3772
3772
|
};
|
|
3773
3773
|
ready: {
|
|
3774
3774
|
byteLength: number;
|
|
3775
|
-
/** @description Caller-declared whole-file SHA-256
|
|
3775
|
+
/** @description Caller-declared whole-file SHA-256. Portable profiles independently verify file bytes before publication; legacy profiles retain provider-checksum semantics. */
|
|
3776
3776
|
callerDeclaredContentDigest: string;
|
|
3777
3777
|
displayFilename: string;
|
|
3778
3778
|
itemId: string;
|
|
@@ -3784,6 +3784,13 @@ interface operations {
|
|
|
3784
3784
|
} | null;
|
|
3785
3785
|
revision: number;
|
|
3786
3786
|
uploadId: string;
|
|
3787
|
+
verification?: {
|
|
3788
|
+
revision: number;
|
|
3789
|
+
/** @enum {string} */
|
|
3790
|
+
state: "pending" | "verified" | "failed";
|
|
3791
|
+
totalByteLength: number;
|
|
3792
|
+
verifiedByteLength: number;
|
|
3793
|
+
};
|
|
3787
3794
|
versionId: string;
|
|
3788
3795
|
};
|
|
3789
3796
|
};
|
|
@@ -4058,7 +4065,7 @@ interface operations {
|
|
|
4058
4065
|
content: {
|
|
4059
4066
|
"application/json": {
|
|
4060
4067
|
byteLength: number;
|
|
4061
|
-
/** @description Caller-declared whole-file SHA-256
|
|
4068
|
+
/** @description Caller-declared whole-file SHA-256. Portable profiles independently verify file bytes before publication; legacy profiles retain provider-checksum semantics. */
|
|
4062
4069
|
callerDeclaredContentDigest: string;
|
|
4063
4070
|
displayFilename: string;
|
|
4064
4071
|
itemId: string;
|
|
@@ -4070,6 +4077,24 @@ interface operations {
|
|
|
4070
4077
|
};
|
|
4071
4078
|
};
|
|
4072
4079
|
};
|
|
4080
|
+
/** @description Archive verification is pending; retry completion with the same key. */
|
|
4081
|
+
202: {
|
|
4082
|
+
headers: {
|
|
4083
|
+
[name: string]: unknown;
|
|
4084
|
+
};
|
|
4085
|
+
content: {
|
|
4086
|
+
"application/json": {
|
|
4087
|
+
itemId: string;
|
|
4088
|
+
/** @enum {string} */
|
|
4089
|
+
state: "verifying";
|
|
4090
|
+
totalByteLength: number;
|
|
4091
|
+
uploadId: string;
|
|
4092
|
+
verificationRevision: number;
|
|
4093
|
+
verifiedByteLength: number;
|
|
4094
|
+
versionId: string;
|
|
4095
|
+
};
|
|
4096
|
+
};
|
|
4097
|
+
};
|
|
4073
4098
|
/** @description Authentication is required. */
|
|
4074
4099
|
401: {
|
|
4075
4100
|
headers: {
|
|
@@ -4221,6 +4246,7 @@ interface operations {
|
|
|
4221
4246
|
content: {
|
|
4222
4247
|
"application/json": {
|
|
4223
4248
|
checksumSha256: string;
|
|
4249
|
+
contentMd5: string;
|
|
4224
4250
|
partNumber: number;
|
|
4225
4251
|
};
|
|
4226
4252
|
};
|
|
@@ -4236,7 +4262,7 @@ interface operations {
|
|
|
4236
4262
|
expectedByteLength: number;
|
|
4237
4263
|
expiresAtEpochMilliseconds: number;
|
|
4238
4264
|
headers: {
|
|
4239
|
-
"
|
|
4265
|
+
"content-md5": string;
|
|
4240
4266
|
};
|
|
4241
4267
|
/** @enum {string} */
|
|
4242
4268
|
method: "PUT";
|
|
@@ -4594,6 +4620,8 @@ type UploadPartDescriptor = Readonly<Omit<JsonResponse<"createUploadPartDescript
|
|
|
4594
4620
|
}>;
|
|
4595
4621
|
type UploadPartResult = Readonly<JsonResponse<"recordUploadPart", 200>>;
|
|
4596
4622
|
type ReadyUpload = Readonly<JsonResponse<"completeUpload", 200>>;
|
|
4623
|
+
type PendingUpload = Readonly<JsonResponse<"completeUpload", 202>>;
|
|
4624
|
+
type UploadCompletion = ReadyUpload | PendingUpload;
|
|
4597
4625
|
type ManagedLifecycleItem = Readonly<JsonResponse<"updateItem", 200>>;
|
|
4598
4626
|
type GeneratedManagedItemMetadata = JsonResponse<"getItem", 200>;
|
|
4599
4627
|
type ManagedItemMetadata = Readonly<Omit<GeneratedManagedItemMetadata, "currentVersion"> & {
|
|
@@ -4620,10 +4648,11 @@ type ManagedDownloadDescriptor = Readonly<Omit<JsonResponse<"createDownload", 20
|
|
|
4620
4648
|
type ManagedDownloadRestorePending = Readonly<JsonResponse<"createDownload", 202>>;
|
|
4621
4649
|
type GeneratedUploadStatus = JsonResponse<"getUploadStatus", 200>;
|
|
4622
4650
|
type UploadConfirmedPart = Readonly<GeneratedUploadStatus["confirmedParts"][number]>;
|
|
4623
|
-
type UploadStatus = Readonly<Omit<GeneratedUploadStatus, "confirmedParts" | "partPolicy" | "ready"> & {
|
|
4651
|
+
type UploadStatus = Readonly<Omit<GeneratedUploadStatus, "confirmedParts" | "partPolicy" | "ready" | "verification"> & {
|
|
4624
4652
|
readonly confirmedParts: readonly UploadConfirmedPart[];
|
|
4625
4653
|
readonly partPolicy: Readonly<GeneratedUploadStatus["partPolicy"]>;
|
|
4626
4654
|
readonly ready: ReadyUpload | null;
|
|
4655
|
+
readonly verification?: Readonly<NonNullable<GeneratedUploadStatus["verification"]>>;
|
|
4627
4656
|
}>;
|
|
4628
4657
|
type ProtectionClassification = CreateUploadBody["protectionClassification"];
|
|
4629
4658
|
type PermissionAction = CreatePermissionBody["actions"][number];
|
|
@@ -4763,7 +4792,7 @@ type CreateDownloadInput = Readonly<CreateDownloadPath> & Readonly<CreateDownloa
|
|
|
4763
4792
|
readonly signal?: AbortSignal;
|
|
4764
4793
|
};
|
|
4765
4794
|
type DownloadItemResult = Response | DriveOperationResult<ManagedDownloadRestorePending, 202> | DriveOperationResult<undefined, 304>;
|
|
4766
|
-
type UploadFilePhase = "preparing" | "uploading" | "completing";
|
|
4795
|
+
type UploadFilePhase = "preparing" | "uploading" | "completing" | "verifying";
|
|
4767
4796
|
interface UploadFileProgress {
|
|
4768
4797
|
readonly phase: UploadFilePhase;
|
|
4769
4798
|
readonly confirmedByteLength: number;
|
|
@@ -4811,12 +4840,12 @@ interface DriveOperations {
|
|
|
4811
4840
|
getUploadStatus(input: GetUploadStatusInput): Promise<DriveOperationResult<UploadStatus, 200>>;
|
|
4812
4841
|
createUploadPartDescriptor(input: CreateUploadPartDescriptorInput): Promise<DriveOperationResult<UploadPartDescriptor, 200>>;
|
|
4813
4842
|
recordUploadPart(input: RecordUploadPartInput): Promise<DriveOperationResult<UploadPartResult, 200>>;
|
|
4814
|
-
completeUpload(input: CompleteUploadInput): Promise<DriveOperationResult<
|
|
4843
|
+
completeUpload(input: CompleteUploadInput): Promise<DriveOperationResult<UploadCompletion, 200 | 202>>;
|
|
4815
4844
|
abortUpload(input: AbortUploadInput): Promise<DriveOperationResult<undefined, 204>>;
|
|
4816
4845
|
}
|
|
4817
4846
|
interface DriveServerClient extends DriveOperations {}
|
|
4818
4847
|
interface DriveClient extends DriveOperations {
|
|
4819
|
-
uploadFile(input: UploadFileInput): Promise<DriveOperationResult<
|
|
4848
|
+
uploadFile(input: UploadFileInput): Promise<DriveOperationResult<UploadCompletion, 200 | 202>>;
|
|
4820
4849
|
}
|
|
4821
4850
|
//#endregion
|
|
4822
|
-
export {
|
|
4851
|
+
export { TrashItemInput as $, ListItemVersionsInput as A, PermissionAction as B, FolderPage as C, GetUploadStatusInput as D, GetItemVersionInput as E, ManagedItemVersionPage as F, ProtectionClassification as G, PermissionGrantee as H, ManagedItemVersionResource as I, RecordUploadPartInput as J, ReadEffectiveItemPermissionsInput as K, ManagedItemVersionRestoreResult as L, ManagedDownloadRestorePending as M, ManagedItemMetadata as N, ListFolderChildrenInput as O, ManagedItemVersion as P, SearchWorkspaceItemsInput as Q, ManagedLifecycleItem as R, FolderItem as S, GetItemInput as T, PermissionMutation as U, PermissionGrant as V, PermissionPage as W, RestoreItemVersionInput as X, RestoreItemInput as Y, RevokeItemPermissionInput as Z, DriveResponseValidators as _, CreateItemPermissionInput as a, UploadFilePhase as at, EffectivePermissionAction as b, CurrentWorkspace as c, UploadPartDescriptor as ct, DriveClient as d, UploadStatus as dt, UpdateItemInput as et, DriveClientConfig as f, WorkspaceItemSearchItem as ft, DriveOperations as g, DriveOperationResult as h, CreateFolderInput as i, UploadFileInput as it, ManagedDownloadDescriptor as j, ListItemPermissionsInput as k, DeleteItemInput as l, UploadPartResult as lt, DriveCredentialProvider as m, operations as mt, CompleteUploadInput as n, UploadCompletion as nt, CreateUploadInput as o, UploadFileProgress as ot, DriveCredentialContext as p, WorkspaceItemSearchPage as pt, ReadyUpload as q, CreateDownloadInput as r, UploadConfirmedPart as rt, CreateUploadPartDescriptorInput as s, UploadFileProgressCallback as st, AbortUploadInput as t, UpdateItemPermissionInput as tt, DownloadItemResult as u, UploadSession as ut, DriveServerClient as v, GetCurrentWorkspaceInput as w, EffectivePermissionResponse as x, DriveServerClientConfig as y, PendingUpload as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as TrashItemInput, A as ListItemVersionsInput, B as PermissionAction, C as FolderPage, D as GetUploadStatusInput, E as GetItemVersionInput, F as ManagedItemVersionPage, G as ProtectionClassification, H as PermissionGrantee, I as ManagedItemVersionResource, J as RecordUploadPartInput, K as ReadEffectiveItemPermissionsInput, 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, U as PermissionMutation, V as PermissionGrant, X as RestoreItemVersionInput, Y as RestoreItemInput, Z as RevokeItemPermissionInput, _ as DriveResponseValidators, a as CreateItemPermissionInput, at as UploadFilePhase, b as EffectivePermissionAction, c as CurrentWorkspace, ct as UploadPartDescriptor, d as DriveClient, dt as UploadStatus, et as UpdateItemInput, f as DriveClientConfig, ft as WorkspaceItemSearchItem, g as DriveOperations, h as DriveOperationResult, i as CreateFolderInput, it as UploadFileInput, j as ManagedDownloadDescriptor, k as ListItemPermissionsInput, l as DeleteItemInput, lt as UploadPartResult, m as DriveCredentialProvider, n as CompleteUploadInput, nt as UploadCompletion, o as CreateUploadInput, ot as UploadFileProgress, pt as WorkspaceItemSearchPage, q as ReadyUpload, r as CreateDownloadInput, rt as UploadConfirmedPart, s as CreateUploadPartDescriptorInput, st as UploadFileProgressCallback, t as AbortUploadInput, tt as UpdateItemPermissionInput, u as DownloadItemResult, ut as UploadSession, w as GetCurrentWorkspaceInput, z as PendingUpload } from "./contract.js";
|
|
2
2
|
import { createDriveClient } from "./client.js";
|
|
3
3
|
import { DRIVE_API_ERROR_CODES, DRIVE_API_ERROR_MESSAGES, DriveApiErrorCode, DriveError, DriveErrorCode, DriveSdkErrorCode } from "./core.js";
|
|
4
|
-
export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateFolderInput, type CreateItemPermissionInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, DRIVE_API_ERROR_CODES, DRIVE_API_ERROR_MESSAGES, type DeleteItemInput, type DownloadItemResult, type DriveApiErrorCode, type DriveClient, type DriveClientConfig, type DriveCredentialProvider, DriveError, type DriveErrorCode, type DriveOperationResult, type DriveOperations, type DriveResponseValidators, type DriveSdkErrorCode, type EffectivePermissionAction, type FolderItem, type FolderPage, type GetCurrentWorkspaceInput, type GetItemInput, type GetItemVersionInput, type GetUploadStatusInput, type ListFolderChildrenInput, type ListItemPermissionsInput, type ListItemVersionsInput, type ManagedDownloadDescriptor, type ManagedDownloadRestorePending, type ManagedItemMetadata, type ManagedItemVersion, type ManagedItemVersionPage, type ManagedItemVersionResource, type ManagedItemVersionRestoreResult, type ManagedLifecycleItem, type PermissionAction, type PermissionGrant, type PermissionGrantee, type PermissionMutation, type ProtectionClassification, type ReadEffectiveItemPermissionsInput, type ReadyUpload, type RecordUploadPartInput, type RestoreItemInput, type RestoreItemVersionInput, type RevokeItemPermissionInput, type SearchWorkspaceItemsInput, type TrashItemInput, type UpdateItemInput, type UpdateItemPermissionInput, type UploadConfirmedPart, type UploadFileInput, type UploadFilePhase, type UploadFileProgress, type UploadFileProgressCallback, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveClient };
|
|
4
|
+
export { type AbortUploadInput, type CompleteUploadInput, type CreateDownloadInput, type CreateFolderInput, type CreateItemPermissionInput, type CreateUploadInput, type CreateUploadPartDescriptorInput, type CurrentWorkspace, DRIVE_API_ERROR_CODES, DRIVE_API_ERROR_MESSAGES, type DeleteItemInput, type DownloadItemResult, type DriveApiErrorCode, type DriveClient, type DriveClientConfig, type DriveCredentialProvider, DriveError, type DriveErrorCode, type DriveOperationResult, type DriveOperations, type DriveResponseValidators, type DriveSdkErrorCode, type EffectivePermissionAction, type FolderItem, type FolderPage, type GetCurrentWorkspaceInput, type GetItemInput, type GetItemVersionInput, type GetUploadStatusInput, type ListFolderChildrenInput, type ListItemPermissionsInput, type ListItemVersionsInput, type ManagedDownloadDescriptor, type ManagedDownloadRestorePending, type ManagedItemMetadata, type ManagedItemVersion, type ManagedItemVersionPage, type ManagedItemVersionResource, type ManagedItemVersionRestoreResult, type ManagedLifecycleItem, type PendingUpload, type PermissionAction, type PermissionGrant, type PermissionGrantee, type PermissionMutation, type ProtectionClassification, type ReadEffectiveItemPermissionsInput, type ReadyUpload, type RecordUploadPartInput, type RestoreItemInput, type RestoreItemVersionInput, type RevokeItemPermissionInput, type SearchWorkspaceItemsInput, type TrashItemInput, type UpdateItemInput, type UpdateItemPermissionInput, type UploadCompletion, type UploadConfirmedPart, type UploadFileInput, type UploadFilePhase, type UploadFileProgress, type UploadFileProgressCallback, type UploadPartDescriptor, type UploadPartResult, type UploadSession, type UploadStatus, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, createDriveClient };
|
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,4 +1,4 @@
|
|
|
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
2
|
//#region src/internal/provisioning.d.ts
|
|
3
3
|
type Operation = operations["provisionManagedWorkspace"];
|
|
4
4
|
type ProvisionWorkspaceCommand = Operation["requestBody"]["content"]["application/json"];
|
|
@@ -20,4 +20,4 @@ declare function createDriveProvisioningClient(config: DriveProvisioningClientCo
|
|
|
20
20
|
//#region src/server.d.ts
|
|
21
21
|
declare function createDriveServerClient(config: DriveServerClientConfig): DriveServerClient;
|
|
22
22
|
//#endregion
|
|
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 ProtectionClassification, type ProvisionWorkspaceCommand, type ProvisionWorkspaceResult, 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, createDriveProvisioningClient, 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);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
export { AbortUploadInput, CompleteUploadInput, CreateDownloadInput, CreateFolderInput, CreateItemPermissionInput, CreateUploadInput, CreateUploadPartDescriptorInput, CurrentWorkspace, DeleteItemInput, DownloadItemResult, DriveClient, DriveClientConfig, DriveCredentialContext, DriveCredentialProvider, DriveOperationResult, DriveOperations, DriveResponseValidators, DriveServerClient, DriveServerClientConfig, EffectivePermissionAction, EffectivePermissionResponse, FolderItem, FolderPage, GetCurrentWorkspaceInput, GetItemInput, GetItemVersionInput, GetUploadStatusInput, ListFolderChildrenInput, ListItemPermissionsInput, ListItemVersionsInput, ManagedDownloadDescriptor, ManagedDownloadRestorePending, ManagedItemMetadata, ManagedItemVersion, ManagedItemVersionPage, ManagedItemVersionResource, ManagedItemVersionRestoreResult, ManagedLifecycleItem, PermissionAction, PermissionGrant, PermissionGrantee, PermissionMutation, PermissionPage, ProtectionClassification, ReadEffectiveItemPermissionsInput, ReadyUpload, RecordUploadPartInput, RestoreItemInput, RestoreItemVersionInput, RevokeItemPermissionInput, SearchWorkspaceItemsInput, TrashItemInput, UpdateItemInput, UpdateItemPermissionInput, UploadConfirmedPart, UploadFileInput, UploadFilePhase, UploadFileProgress, UploadFileProgressCallback, UploadPartDescriptor, UploadPartResult, UploadSession, UploadStatus, WorkspaceItemSearchItem, WorkspaceItemSearchPage };
|
|
1
|
+
import { $ as TrashItemInput, A as ListItemVersionsInput, B as PermissionAction, C as FolderPage, D as GetUploadStatusInput, E as GetItemVersionInput, F as ManagedItemVersionPage, G as ProtectionClassification, H as PermissionGrantee, I as ManagedItemVersionResource, J as RecordUploadPartInput, K as ReadEffectiveItemPermissionsInput, 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, U as PermissionMutation, V as PermissionGrant, W as PermissionPage, X as RestoreItemVersionInput, Y as RestoreItemInput, Z as RevokeItemPermissionInput, _ as DriveResponseValidators, a as CreateItemPermissionInput, at as UploadFilePhase, b as EffectivePermissionAction, c as CurrentWorkspace, ct as UploadPartDescriptor, d as DriveClient, dt as UploadStatus, et as UpdateItemInput, f as DriveClientConfig, ft as WorkspaceItemSearchItem, g as DriveOperations, h as DriveOperationResult, i as CreateFolderInput, it as UploadFileInput, j as ManagedDownloadDescriptor, k as ListItemPermissionsInput, l as DeleteItemInput, lt as UploadPartResult, m as DriveCredentialProvider, n as CompleteUploadInput, nt as UploadCompletion, o as CreateUploadInput, ot as UploadFileProgress, p as DriveCredentialContext, pt as WorkspaceItemSearchPage, q as ReadyUpload, r as CreateDownloadInput, rt as UploadConfirmedPart, s as CreateUploadPartDescriptorInput, st as UploadFileProgressCallback, t as AbortUploadInput, tt as UpdateItemPermissionInput, u as DownloadItemResult, ut as UploadSession, v as DriveServerClient, w as GetCurrentWorkspaceInput, x as EffectivePermissionResponse, y as DriveServerClientConfig, z as PendingUpload } from "./contract.js";
|
|
2
|
+
export { AbortUploadInput, CompleteUploadInput, CreateDownloadInput, CreateFolderInput, CreateItemPermissionInput, CreateUploadInput, CreateUploadPartDescriptorInput, CurrentWorkspace, DeleteItemInput, DownloadItemResult, DriveClient, DriveClientConfig, DriveCredentialContext, DriveCredentialProvider, DriveOperationResult, DriveOperations, DriveResponseValidators, DriveServerClient, DriveServerClientConfig, EffectivePermissionAction, EffectivePermissionResponse, FolderItem, FolderPage, GetCurrentWorkspaceInput, GetItemInput, GetItemVersionInput, GetUploadStatusInput, ListFolderChildrenInput, ListItemPermissionsInput, ListItemVersionsInput, ManagedDownloadDescriptor, ManagedDownloadRestorePending, ManagedItemMetadata, ManagedItemVersion, ManagedItemVersionPage, ManagedItemVersionResource, ManagedItemVersionRestoreResult, ManagedLifecycleItem, PendingUpload, PermissionAction, PermissionGrant, PermissionGrantee, PermissionMutation, PermissionPage, ProtectionClassification, ReadEffectiveItemPermissionsInput, ReadyUpload, RecordUploadPartInput, RestoreItemInput, RestoreItemVersionInput, RevokeItemPermissionInput, SearchWorkspaceItemsInput, TrashItemInput, UpdateItemInput, UpdateItemPermissionInput, UploadCompletion, UploadConfirmedPart, UploadFileInput, UploadFilePhase, UploadFileProgress, UploadFileProgressCallback, UploadPartDescriptor, UploadPartResult, UploadSession, UploadStatus, WorkspaceItemSearchItem, WorkspaceItemSearchPage };
|