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