@finueva/drive 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +33 -6
- package/dist/client.d.ts +2 -2
- package/dist/client.js +324 -20
- package/dist/contract.d.ts +514 -9
- package/dist/index.d.ts +2 -2
- package/dist/index.js +324 -20
- package/dist/server.d.ts +2 -2
- package/dist/server.js +195 -12
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -327,6 +327,101 @@ const MAX_UPLOAD_BYTE_LENGTH$1 = 33554432e4;
|
|
|
327
327
|
const UPLOAD_PART_BYTE_LENGTH$2 = 32 * 1024 * 1024;
|
|
328
328
|
const CONTENT_DIGEST$1 = /^sha256:[0-9a-f]{64}$/;
|
|
329
329
|
const UTF8 = new TextEncoder();
|
|
330
|
+
function isWorkspaceUsage(value) {
|
|
331
|
+
if (!isExactRecord(value, [
|
|
332
|
+
"workspaceId",
|
|
333
|
+
"provider",
|
|
334
|
+
"usedBytes",
|
|
335
|
+
"reservedBytes",
|
|
336
|
+
"limitBytes",
|
|
337
|
+
"availableBytes",
|
|
338
|
+
"accounting",
|
|
339
|
+
"reservedBytesIncludeUnresolvedUploads",
|
|
340
|
+
"unresolvedReservedBytes",
|
|
341
|
+
"warnings"
|
|
342
|
+
]) || typeof value.workspaceId !== "string" || !WORKSPACE_ID$1.test(value.workspaceId) || value.provider !== "managed" || value.accounting !== "current-versions-and-reservations" || value.reservedBytesIncludeUnresolvedUploads !== true || !Array.isArray(value.warnings) || value.warnings.length > 1 || value.warnings.some((warning) => warning !== "unresolved-archive-ownership") || ![
|
|
343
|
+
value.usedBytes,
|
|
344
|
+
value.reservedBytes,
|
|
345
|
+
value.limitBytes,
|
|
346
|
+
value.availableBytes,
|
|
347
|
+
value.unresolvedReservedBytes
|
|
348
|
+
].every((bytes) => typeof bytes === "string" && /^(0|[1-9][0-9]{0,18})$/.test(bytes))) return false;
|
|
349
|
+
const available = BigInt(value.limitBytes) - BigInt(value.usedBytes) - BigInt(value.reservedBytes);
|
|
350
|
+
const valid = BigInt(value.availableBytes) === (available > 0n ? available : 0n) && BigInt(value.unresolvedReservedBytes) <= BigInt(value.reservedBytes) && (value.unresolvedReservedBytes === "0" || value.warnings.length === 1);
|
|
351
|
+
if (valid) Object.freeze(value.warnings);
|
|
352
|
+
return valid;
|
|
353
|
+
}
|
|
354
|
+
function isWorkspaceDiscoveryPage(value) {
|
|
355
|
+
if (!isExactRecord(value, ["items", "nextCursor"]) || !Array.isArray(value.items) || value.items.length > 50 || !(value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length > 0 && value.nextCursor.length <= 2048 && /^[A-Za-z0-9_.-]+$/.test(value.nextCursor)) || value.items.length === 0 && value.nextCursor !== null) return false;
|
|
356
|
+
const ids = new Set();
|
|
357
|
+
const valid = value.items.every((item) => {
|
|
358
|
+
if (!isExactRecord(item, [
|
|
359
|
+
"workspaceId",
|
|
360
|
+
"itemId",
|
|
361
|
+
"parentId",
|
|
362
|
+
"type",
|
|
363
|
+
"name",
|
|
364
|
+
"lifecycleState",
|
|
365
|
+
"revision",
|
|
366
|
+
"currentVersion",
|
|
367
|
+
"volumeId",
|
|
368
|
+
"provider",
|
|
369
|
+
"createdAtEpochMilliseconds",
|
|
370
|
+
"modifiedAtEpochMilliseconds",
|
|
371
|
+
"creatorUserId",
|
|
372
|
+
"etag",
|
|
373
|
+
"trashedAtEpochMilliseconds",
|
|
374
|
+
"purgeAfterEpochMilliseconds"
|
|
375
|
+
]) || item.lifecycleState !== "active" && item.lifecycleState !== "trashed" || typeof item.volumeId !== "string" || !VOLUME_ID.test(item.volumeId) || item.provider !== "managed" || item.creatorUserId !== null && (typeof item.creatorUserId !== "string" || !AUTH_ID$1.test(item.creatorUserId)) || ![
|
|
376
|
+
item.createdAtEpochMilliseconds,
|
|
377
|
+
item.modifiedAtEpochMilliseconds,
|
|
378
|
+
item.trashedAtEpochMilliseconds,
|
|
379
|
+
item.purgeAfterEpochMilliseconds
|
|
380
|
+
].every((date) => date === null || isSafeInteger$1(date))) return false;
|
|
381
|
+
const metadata = {
|
|
382
|
+
workspaceId: item.workspaceId,
|
|
383
|
+
itemId: item.itemId,
|
|
384
|
+
parentId: item.parentId,
|
|
385
|
+
type: item.type,
|
|
386
|
+
name: item.name,
|
|
387
|
+
lifecycleState: "active",
|
|
388
|
+
revision: item.revision,
|
|
389
|
+
currentVersion: item.currentVersion
|
|
390
|
+
};
|
|
391
|
+
if (typeof metadata.workspaceId !== "string" || !WORKSPACE_ID$1.test(metadata.workspaceId) || typeof metadata.itemId !== "string" || !ITEM_ID$1.test(metadata.itemId) || metadata.parentId === null || metadata.parentId === metadata.itemId || !isManagedItemMetadata(metadata, metadata.workspaceId, metadata.itemId) || item.etag !== `"drive.item.v1.${metadata.revision}"` || ids.has(metadata.itemId)) return false;
|
|
392
|
+
if (item.lifecycleState === "active" ? item.trashedAtEpochMilliseconds !== null || item.purgeAfterEpochMilliseconds !== null : !isSafeInteger$1(item.trashedAtEpochMilliseconds) || !isSafeInteger$1(item.purgeAfterEpochMilliseconds) || item.purgeAfterEpochMilliseconds <= item.trashedAtEpochMilliseconds) return false;
|
|
393
|
+
ids.add(metadata.itemId);
|
|
394
|
+
return true;
|
|
395
|
+
});
|
|
396
|
+
if (valid) {
|
|
397
|
+
for (const item of value.items) Object.freeze(item);
|
|
398
|
+
Object.freeze(value.items);
|
|
399
|
+
Object.freeze(value);
|
|
400
|
+
}
|
|
401
|
+
return valid;
|
|
402
|
+
}
|
|
403
|
+
function isCurrentWorkspaceSources(value) {
|
|
404
|
+
if (!isExactRecord(value, [
|
|
405
|
+
"workspace",
|
|
406
|
+
"volumes",
|
|
407
|
+
"knownProviders",
|
|
408
|
+
"externalConnectionsSupported"
|
|
409
|
+
]) || !isCurrentWorkspace(value.workspace) || !Array.isArray(value.volumes) || value.volumes.length !== 1 || !Array.isArray(value.knownProviders) || value.externalConnectionsSupported !== false) return false;
|
|
410
|
+
const volume = value.volumes[0];
|
|
411
|
+
const providers = [
|
|
412
|
+
"managed",
|
|
413
|
+
"google-drive",
|
|
414
|
+
"onedrive",
|
|
415
|
+
"dropbox",
|
|
416
|
+
"s3-compatible"
|
|
417
|
+
];
|
|
418
|
+
return isExactRecord(volume, [
|
|
419
|
+
"volumeId",
|
|
420
|
+
"rootItemId",
|
|
421
|
+
"provider",
|
|
422
|
+
"name"
|
|
423
|
+
]) && volume.volumeId === value.workspace.rootVolumeId && volume.rootItemId === value.workspace.rootItemId && volume.provider === "managed" && volume.name === "Files" && value.knownProviders.length === providers.length && value.knownProviders.every((provider, index) => provider === providers[index]);
|
|
424
|
+
}
|
|
330
425
|
function isCurrentWorkspace(value) {
|
|
331
426
|
if (!isExactRecord(value, [
|
|
332
427
|
"workspaceId",
|
|
@@ -584,12 +679,14 @@ function isUploadStatus(value, afterPartNumber, limit) {
|
|
|
584
679
|
"nextAfterPartNumber",
|
|
585
680
|
"expiresAtEpochMilliseconds",
|
|
586
681
|
"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" || ![
|
|
682
|
+
], ["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
683
|
"initiating",
|
|
589
684
|
"recovery-required",
|
|
590
685
|
"uploading",
|
|
591
686
|
"completing",
|
|
592
687
|
"provider-completed",
|
|
688
|
+
"verifying",
|
|
689
|
+
"failed",
|
|
593
690
|
"ready",
|
|
594
691
|
"aborting",
|
|
595
692
|
"aborted"
|
|
@@ -599,18 +696,38 @@ function isUploadStatus(value, afterPartNumber, limit) {
|
|
|
599
696
|
"maxParts"
|
|
600
697
|
]) || 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
698
|
let previousPartNumber = afterPartNumber;
|
|
699
|
+
if (value.verification !== void 0) {
|
|
700
|
+
const progress = value.verification;
|
|
701
|
+
if (!isExactRecord(progress, [
|
|
702
|
+
"state",
|
|
703
|
+
"verifiedByteLength",
|
|
704
|
+
"totalByteLength",
|
|
705
|
+
"revision"
|
|
706
|
+
]) || ![
|
|
707
|
+
"pending",
|
|
708
|
+
"verified",
|
|
709
|
+
"failed"
|
|
710
|
+
].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;
|
|
711
|
+
Object.freeze(progress);
|
|
712
|
+
}
|
|
713
|
+
if (["verifying", "failed"].includes(String(value.lifecycle)) && value.verification === void 0) return false;
|
|
602
714
|
for (const part of value.confirmedParts) {
|
|
603
715
|
if (!isExactRecord(part, ["partNumber", "checksumSha256"]) || !isSafeInteger$1(part.partNumber) || part.partNumber <= previousPartNumber || part.partNumber > value.partPolicy.partCount || !isPartChecksum$1(part.checksumSha256)) return false;
|
|
604
716
|
previousPartNumber = part.partNumber;
|
|
605
717
|
}
|
|
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
|
|
718
|
+
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, [
|
|
719
|
+
"state",
|
|
720
|
+
"verifiedByteLength",
|
|
721
|
+
"totalByteLength",
|
|
722
|
+
"revision"
|
|
723
|
+
]) || value.verification.state !== "verified" || value.verification.totalByteLength !== value.ready.byteLength)) return false;
|
|
607
724
|
Object.freeze(value.partPolicy);
|
|
608
725
|
for (const part of value.confirmedParts) Object.freeze(part);
|
|
609
726
|
Object.freeze(value.confirmedParts);
|
|
610
727
|
Object.freeze(value);
|
|
611
728
|
return true;
|
|
612
729
|
}
|
|
613
|
-
function isUploadPartDescriptor(value, expectedPartNumber,
|
|
730
|
+
function isUploadPartDescriptor(value, expectedPartNumber, allowInsecureHttp, contentMd5) {
|
|
614
731
|
if (!isExactRecord(value, [
|
|
615
732
|
"url",
|
|
616
733
|
"method",
|
|
@@ -618,7 +735,7 @@ function isUploadPartDescriptor(value, expectedPartNumber, checksumSha256, allow
|
|
|
618
735
|
"partNumber",
|
|
619
736
|
"expectedByteLength",
|
|
620
737
|
"expiresAtEpochMilliseconds"
|
|
621
|
-
]) || !isSignedTransferUrl(value.url, allowInsecureHttp) || value.method !== "PUT" || !isExactRecord(value.headers, ["
|
|
738
|
+
]) || !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
739
|
Object.freeze(value.headers);
|
|
623
740
|
Object.freeze(value);
|
|
624
741
|
return true;
|
|
@@ -642,6 +759,19 @@ function isReadyUpload(value, expected) {
|
|
|
642
759
|
Object.freeze(value);
|
|
643
760
|
return true;
|
|
644
761
|
}
|
|
762
|
+
function isPendingUpload(value, uploadId) {
|
|
763
|
+
if (!isExactRecord(value, [
|
|
764
|
+
"itemId",
|
|
765
|
+
"versionId",
|
|
766
|
+
"uploadId",
|
|
767
|
+
"state",
|
|
768
|
+
"verifiedByteLength",
|
|
769
|
+
"totalByteLength",
|
|
770
|
+
"verificationRevision"
|
|
771
|
+
]) || 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;
|
|
772
|
+
Object.freeze(value);
|
|
773
|
+
return true;
|
|
774
|
+
}
|
|
645
775
|
function isPartChecksum$1(value) {
|
|
646
776
|
return typeof value === "string" && /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(value);
|
|
647
777
|
}
|
|
@@ -781,9 +911,9 @@ function isSafeCapabilityUrl(value) {
|
|
|
781
911
|
return false;
|
|
782
912
|
}
|
|
783
913
|
}
|
|
784
|
-
function isExactRecord(value, keys) {
|
|
914
|
+
function isExactRecord(value, keys, optional = []) {
|
|
785
915
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
786
|
-
return Object.keys(value).
|
|
916
|
+
return Object.keys(value).every((key) => keys.includes(key) || optional.includes(key)) && keys.every((key) => Object.hasOwn(value, key));
|
|
787
917
|
}
|
|
788
918
|
//#endregion
|
|
789
919
|
//#region src/internal/client/request.ts
|
|
@@ -811,6 +941,29 @@ function validateCurrentWorkspaceInput(value) {
|
|
|
811
941
|
const signal = validateSignal(captureRecord(value === void 0 ? {} : value, [], ["signal"]).signal);
|
|
812
942
|
return signal === void 0 ? {} : { signal };
|
|
813
943
|
}
|
|
944
|
+
function validateWorkspaceDiscoveryInput(value, list) {
|
|
945
|
+
const input = captureRecord(value, ["workspaceId"], list ? [
|
|
946
|
+
"signal",
|
|
947
|
+
"view",
|
|
948
|
+
"kind",
|
|
949
|
+
"creatorUserId",
|
|
950
|
+
"limit",
|
|
951
|
+
"cursor"
|
|
952
|
+
] : ["signal"]);
|
|
953
|
+
const signal = validateSignal(input.signal);
|
|
954
|
+
if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || input.view !== void 0 && input.view !== "recent" && input.view !== "shared" && input.view !== "trash" || input.kind !== void 0 && input.kind !== "file" && input.kind !== "folder" || input.creatorUserId !== void 0 && (typeof input.creatorUserId !== "string" || !AUTH_ID.test(input.creatorUserId)) || input.limit !== void 0 && (typeof input.limit !== "number" || !Number.isInteger(input.limit) || input.limit < 1 || input.limit > 50) || input.cursor !== void 0 && (typeof input.cursor !== "string" || input.cursor.length < 1 || input.cursor.length > 2048 || !/^[A-Za-z0-9_.-]+$/.test(input.cursor))) throw new DriveError("invalid_input");
|
|
955
|
+
return {
|
|
956
|
+
workspaceId: input.workspaceId,
|
|
957
|
+
signal,
|
|
958
|
+
query: {
|
|
959
|
+
...input.view === void 0 ? {} : { view: input.view },
|
|
960
|
+
...input.kind === void 0 ? {} : { kind: input.kind },
|
|
961
|
+
...input.creatorUserId === void 0 ? {} : { creatorUserId: input.creatorUserId },
|
|
962
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
963
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor }
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
}
|
|
814
967
|
function validateResourceInput(value) {
|
|
815
968
|
const input = captureRecord(value, ["workspaceId", "itemId"], ["signal"]);
|
|
816
969
|
const workspaceId = input.workspaceId;
|
|
@@ -1112,14 +1265,17 @@ function validateCreateUploadPartDescriptorInput(value) {
|
|
|
1112
1265
|
"workspaceId",
|
|
1113
1266
|
"uploadId",
|
|
1114
1267
|
"partNumber",
|
|
1115
|
-
"checksumSha256"
|
|
1268
|
+
"checksumSha256",
|
|
1269
|
+
"contentMd5"
|
|
1116
1270
|
], ["signal"]);
|
|
1117
1271
|
const upload = validateUploadPath(input.workspaceId, input.uploadId, input.signal);
|
|
1118
1272
|
if (!isPartNumber(input.partNumber) || !isPartChecksum(input.checksumSha256)) throw new DriveError("invalid_input");
|
|
1273
|
+
if (typeof input.contentMd5 !== "string" || !/^[A-Za-z0-9+/]{21}[AQgw]==$/.test(input.contentMd5)) throw new DriveError("invalid_input");
|
|
1119
1274
|
return {
|
|
1120
1275
|
...upload,
|
|
1121
1276
|
partNumber: input.partNumber,
|
|
1122
|
-
checksumSha256: input.checksumSha256
|
|
1277
|
+
checksumSha256: input.checksumSha256,
|
|
1278
|
+
contentMd5: input.contentMd5
|
|
1123
1279
|
};
|
|
1124
1280
|
}
|
|
1125
1281
|
function validateRecordUploadPartInput(value) {
|
|
@@ -1984,6 +2140,9 @@ const DOWNLOAD_ERROR_CODES = Object.freeze([
|
|
|
1984
2140
|
function createDriveOperations(runtime) {
|
|
1985
2141
|
return Object.freeze({
|
|
1986
2142
|
getCurrentWorkspace: (input) => getCurrentWorkspace(runtime, input),
|
|
2143
|
+
listWorkspaceItems: (input) => listWorkspaceItems(runtime, input),
|
|
2144
|
+
getWorkspaceUsage: (input) => getWorkspaceUsage(runtime, input),
|
|
2145
|
+
getCurrentWorkspaceSources: (input) => getCurrentWorkspaceSources(runtime, input),
|
|
1987
2146
|
getItem: (input) => getItem(runtime, input),
|
|
1988
2147
|
searchWorkspaceItems: (input) => searchWorkspaceItems(runtime, input),
|
|
1989
2148
|
listFolderChildren: (input) => listFolderChildren(runtime, input),
|
|
@@ -2182,6 +2341,29 @@ function streamWithOperationLifetime(source, expectedLength, signal) {
|
|
|
2182
2341
|
}
|
|
2183
2342
|
});
|
|
2184
2343
|
}
|
|
2344
|
+
async function getCurrentWorkspaceSources(runtime, input) {
|
|
2345
|
+
return execute(runtime, validateCurrentWorkspaceInput(input).signal, null, (api, requestOptions) => api.GET("/api/v1/workspaces/current/sources", {
|
|
2346
|
+
...operationOptions("getCurrentWorkspaceSources", { params: {} }),
|
|
2347
|
+
...requestOptions
|
|
2348
|
+
}), [200], isCurrentWorkspaceSources, false, CURRENT_WORKSPACE_ERROR_CODES);
|
|
2349
|
+
}
|
|
2350
|
+
async function listWorkspaceItems(runtime, input) {
|
|
2351
|
+
const validated = validateWorkspaceDiscoveryInput(input, true);
|
|
2352
|
+
return execute(runtime, validated.signal, null, (api, options) => api.GET("/api/v1/workspaces/{workspaceId}/items", {
|
|
2353
|
+
...operationOptions("listWorkspaceItems", { params: {
|
|
2354
|
+
path: { workspaceId: validated.workspaceId },
|
|
2355
|
+
query: validated.query
|
|
2356
|
+
} }),
|
|
2357
|
+
...options
|
|
2358
|
+
}), [200], (value) => isWorkspaceDiscoveryPage(value) && value.items.length <= (validated.query.limit ?? 25) && value.items.every((item, index, items) => item.workspaceId === validated.workspaceId && item.lifecycleState === (validated.query.view === "trash" ? "trashed" : "active") && ((validated.query.view ?? "recent") !== "recent" || item.modifiedAtEpochMilliseconds !== null) && (validated.query.kind === void 0 || item.type === validated.query.kind) && (validated.query.creatorUserId === void 0 || item.creatorUserId === validated.query.creatorUserId) && (index === 0 || ((validated.query.view ?? "recent") === "recent" ? items[index - 1].modifiedAtEpochMilliseconds > item.modifiedAtEpochMilliseconds || items[index - 1].modifiedAtEpochMilliseconds === item.modifiedAtEpochMilliseconds && items[index - 1].itemId < item.itemId : items[index - 1].itemId < item.itemId))), false, SEARCH_WORKSPACE_ITEMS_ERROR_CODES);
|
|
2359
|
+
}
|
|
2360
|
+
async function getWorkspaceUsage(runtime, input) {
|
|
2361
|
+
const validated = validateWorkspaceDiscoveryInput(input, false);
|
|
2362
|
+
return execute(runtime, validated.signal, null, (api, options) => api.GET("/api/v1/workspaces/{workspaceId}/usage", {
|
|
2363
|
+
...operationOptions("getWorkspaceUsage", { params: { path: { workspaceId: validated.workspaceId } } }),
|
|
2364
|
+
...options
|
|
2365
|
+
}), [200], (value) => isWorkspaceUsage(value) && value.workspaceId === validated.workspaceId, false, SEARCH_WORKSPACE_ITEMS_ERROR_CODES);
|
|
2366
|
+
}
|
|
2185
2367
|
async function getCurrentWorkspace(runtime, input) {
|
|
2186
2368
|
return execute(runtime, validateCurrentWorkspaceInput(input).signal, null, (api, requestOptions) => api.GET("/api/v1/workspaces/current", {
|
|
2187
2369
|
...operationOptions("getCurrentWorkspace", { params: {} }),
|
|
@@ -2437,7 +2619,7 @@ async function getUploadStatus(runtime, input) {
|
|
|
2437
2619
|
}
|
|
2438
2620
|
} }),
|
|
2439
2621
|
...requestOptions
|
|
2440
|
-
}), [200], (value) => isUploadStatus(value, afterPartNumber, limit), false, STATUS_ERROR_CODES);
|
|
2622
|
+
}), [200], (value) => isUploadStatus(value, afterPartNumber, limit) && value.uploadId === validated.uploadId, false, STATUS_ERROR_CODES);
|
|
2441
2623
|
}
|
|
2442
2624
|
async function createUploadPartDescriptor(runtime, input) {
|
|
2443
2625
|
const validated = validateCreateUploadPartDescriptorInput(input);
|
|
@@ -2449,11 +2631,12 @@ async function createUploadPartDescriptor(runtime, input) {
|
|
|
2449
2631
|
} },
|
|
2450
2632
|
body: {
|
|
2451
2633
|
partNumber: validated.partNumber,
|
|
2452
|
-
checksumSha256: validated.checksumSha256
|
|
2634
|
+
checksumSha256: validated.checksumSha256,
|
|
2635
|
+
contentMd5: validated.contentMd5
|
|
2453
2636
|
}
|
|
2454
2637
|
}),
|
|
2455
2638
|
...requestOptions
|
|
2456
|
-
}), [200], (value) => isUploadPartDescriptor(value, validated.partNumber,
|
|
2639
|
+
}), [200], (value) => isUploadPartDescriptor(value, validated.partNumber, new URL(runtime.baseUrl).protocol === "http:", validated.contentMd5), false, TRANSFER_ERROR_CODES);
|
|
2457
2640
|
}
|
|
2458
2641
|
async function recordUploadPart(runtime, input) {
|
|
2459
2642
|
const validated = validateRecordUploadPartInput(input);
|
|
@@ -2485,7 +2668,7 @@ async function completeUpload(runtime, input) {
|
|
|
2485
2668
|
header: { "Idempotency-Key": validated.idempotencyKey }
|
|
2486
2669
|
} }),
|
|
2487
2670
|
...requestOptions
|
|
2488
|
-
}), [200], (value) => isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
|
|
2671
|
+
}), [200, 202], (value, status) => status === 202 ? isPendingUpload(value, validated.uploadId) : isReadyUpload(value, { uploadId: validated.uploadId }), false, COMPLETE_UPLOAD_ERROR_CODES);
|
|
2489
2672
|
}
|
|
2490
2673
|
async function abortUpload(runtime, input) {
|
|
2491
2674
|
const validated = validateAbortUploadInput(input);
|
|
@@ -2549,6 +2732,9 @@ function createView(arr) {
|
|
|
2549
2732
|
function rotr(word, shift) {
|
|
2550
2733
|
return word << 32 - shift | word >>> shift;
|
|
2551
2734
|
}
|
|
2735
|
+
function rotl(word, shift) {
|
|
2736
|
+
return word << shift | word >>> 32 - shift >>> 0;
|
|
2737
|
+
}
|
|
2552
2738
|
const hasHexBuiltin = (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")();
|
|
2553
2739
|
const hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
2554
2740
|
function bytesToHex(bytes) {
|
|
@@ -2860,6 +3046,115 @@ var _SHA256 = class extends SHA2_32B {
|
|
|
2860
3046
|
};
|
|
2861
3047
|
const sha256 = createHasher(() => new _SHA256(), oidNist(1));
|
|
2862
3048
|
//#endregion
|
|
3049
|
+
//#region ../../node_modules/.pnpm/@noble+hashes@2.3.0/node_modules/@noble/hashes/legacy.js
|
|
3050
|
+
const SHA1_IV = Uint32Array.from([
|
|
3051
|
+
1732584193,
|
|
3052
|
+
4023233417,
|
|
3053
|
+
2562383102,
|
|
3054
|
+
271733878,
|
|
3055
|
+
3285377520
|
|
3056
|
+
]);
|
|
3057
|
+
const p32 = Math.pow(2, 32);
|
|
3058
|
+
const K = Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));
|
|
3059
|
+
const MD5_IV = SHA1_IV.slice(0, 4);
|
|
3060
|
+
const MD5_W = new Uint32Array(16);
|
|
3061
|
+
const MD5_SHIFTS = (() => {
|
|
3062
|
+
const S = [
|
|
3063
|
+
[
|
|
3064
|
+
7,
|
|
3065
|
+
12,
|
|
3066
|
+
17,
|
|
3067
|
+
22
|
|
3068
|
+
],
|
|
3069
|
+
[
|
|
3070
|
+
5,
|
|
3071
|
+
9,
|
|
3072
|
+
14,
|
|
3073
|
+
20
|
|
3074
|
+
],
|
|
3075
|
+
[
|
|
3076
|
+
4,
|
|
3077
|
+
11,
|
|
3078
|
+
16,
|
|
3079
|
+
23
|
|
3080
|
+
],
|
|
3081
|
+
[
|
|
3082
|
+
6,
|
|
3083
|
+
10,
|
|
3084
|
+
15,
|
|
3085
|
+
21
|
|
3086
|
+
]
|
|
3087
|
+
];
|
|
3088
|
+
return Uint8Array.from({ length: 64 }, (_, i) => S[Math.floor(i / 16)][i % 4]);
|
|
3089
|
+
})();
|
|
3090
|
+
var _MD5 = class extends HashMD {
|
|
3091
|
+
A = MD5_IV[0] | 0;
|
|
3092
|
+
B = MD5_IV[1] | 0;
|
|
3093
|
+
C = MD5_IV[2] | 0;
|
|
3094
|
+
D = MD5_IV[3] | 0;
|
|
3095
|
+
constructor() {
|
|
3096
|
+
super(64, 16, 8, true);
|
|
3097
|
+
}
|
|
3098
|
+
get() {
|
|
3099
|
+
const { A, B, C, D } = this;
|
|
3100
|
+
return [
|
|
3101
|
+
A,
|
|
3102
|
+
B,
|
|
3103
|
+
C,
|
|
3104
|
+
D
|
|
3105
|
+
];
|
|
3106
|
+
}
|
|
3107
|
+
set(A, B, C, D) {
|
|
3108
|
+
this.A = A | 0;
|
|
3109
|
+
this.B = B | 0;
|
|
3110
|
+
this.C = C | 0;
|
|
3111
|
+
this.D = D | 0;
|
|
3112
|
+
}
|
|
3113
|
+
_cloneInto(to) {
|
|
3114
|
+
(to ||= new this.constructor()).set(...this.get());
|
|
3115
|
+
return this._cloneIntoMeta(to);
|
|
3116
|
+
}
|
|
3117
|
+
process(view, offset) {
|
|
3118
|
+
for (let i = 0; i < 16; i++, offset += 4) MD5_W[i] = view.getUint32(offset, true);
|
|
3119
|
+
let { A, B, C, D } = this;
|
|
3120
|
+
for (let i = 0; i < 64; i++) {
|
|
3121
|
+
let F, g;
|
|
3122
|
+
if (i < 16) {
|
|
3123
|
+
F = Chi(B, C, D);
|
|
3124
|
+
g = i;
|
|
3125
|
+
} else if (i < 32) {
|
|
3126
|
+
F = Chi(D, B, C);
|
|
3127
|
+
g = (5 * i + 1) % 16;
|
|
3128
|
+
} else if (i < 48) {
|
|
3129
|
+
F = B ^ C ^ D;
|
|
3130
|
+
g = (3 * i + 5) % 16;
|
|
3131
|
+
} else {
|
|
3132
|
+
F = C ^ (B | ~D);
|
|
3133
|
+
g = 7 * i % 16;
|
|
3134
|
+
}
|
|
3135
|
+
F = F + A + K[i] + MD5_W[g];
|
|
3136
|
+
A = D;
|
|
3137
|
+
D = C;
|
|
3138
|
+
C = B;
|
|
3139
|
+
B = B + rotl(F, MD5_SHIFTS[i]);
|
|
3140
|
+
}
|
|
3141
|
+
A = A + this.A | 0;
|
|
3142
|
+
B = B + this.B | 0;
|
|
3143
|
+
C = C + this.C | 0;
|
|
3144
|
+
D = D + this.D | 0;
|
|
3145
|
+
this.set(A, B, C, D);
|
|
3146
|
+
}
|
|
3147
|
+
roundClean() {
|
|
3148
|
+
clean(MD5_W);
|
|
3149
|
+
}
|
|
3150
|
+
destroy() {
|
|
3151
|
+
this.destroyed = true;
|
|
3152
|
+
this.set(0, 0, 0, 0);
|
|
3153
|
+
clean(this.buffer);
|
|
3154
|
+
}
|
|
3155
|
+
};
|
|
3156
|
+
const md5 = createHasher(() => new _MD5());
|
|
3157
|
+
//#endregion
|
|
2863
3158
|
//#region src/internal/client/upload.ts
|
|
2864
3159
|
const UPLOAD_PART_BYTE_LENGTH = 32 * 1024 * 1024;
|
|
2865
3160
|
const STATUS_PAGE_LIMIT = 100;
|
|
@@ -2907,6 +3202,7 @@ async function uploadFileInternal(runtime, input, controls) {
|
|
|
2907
3202
|
uploadId: session.uploadId,
|
|
2908
3203
|
partNumber,
|
|
2909
3204
|
checksumSha256,
|
|
3205
|
+
contentMd5: digests.partMd5s[index],
|
|
2910
3206
|
...validated.signal === void 0 ? {} : { signal: validated.signal }
|
|
2911
3207
|
});
|
|
2912
3208
|
const descriptor = descriptorResult.data;
|
|
@@ -2914,14 +3210,16 @@ async function uploadFileInternal(runtime, input, controls) {
|
|
|
2914
3210
|
status: descriptorResult.status,
|
|
2915
3211
|
requestId: descriptorResult.requestId
|
|
2916
3212
|
});
|
|
2917
|
-
const etag = await putPart(runtime, descriptor, slicePart(validated.source, start, end, expectedByteLength),
|
|
3213
|
+
const etag = await putPart(runtime, descriptor, slicePart(validated.source, start, end, expectedByteLength), validated.signal);
|
|
2918
3214
|
revision = await recordPartWithReconciliation(controls, validated, session, partNumber, revision, expectedByteLength, etag, checksumSha256);
|
|
2919
3215
|
confirmedByteLength += expectedByteLength;
|
|
2920
3216
|
confirmedPartCount += 1;
|
|
2921
3217
|
emitProgress(validated.onProgress, "uploading", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
|
|
2922
3218
|
}
|
|
2923
3219
|
emitProgress(validated.onProgress, "completing", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
|
|
2924
|
-
|
|
3220
|
+
const completed = await completeWithReconciliation(controls, validated, session, digests);
|
|
3221
|
+
if (completed.data.state === "verifying") emitProgress(validated.onProgress, "verifying", confirmedByteLength, validated.byteLength, confirmedPartCount, totalPartCount);
|
|
3222
|
+
return completed;
|
|
2925
3223
|
} catch (error) {
|
|
2926
3224
|
if (validated.signal?.aborted && session) await bestEffortAbort(controls, validated.workspaceId, session.uploadId);
|
|
2927
3225
|
if (error instanceof DriveError) throw error;
|
|
@@ -2977,6 +3275,7 @@ async function readResumeState(controls, input, session, digests) {
|
|
|
2977
3275
|
if (session.mode === "presigned-multipart" && [
|
|
2978
3276
|
"completing",
|
|
2979
3277
|
"provider-completed",
|
|
3278
|
+
"verifying",
|
|
2980
3279
|
"ready"
|
|
2981
3280
|
].includes(baseline.lifecycle) && confirmedParts.size !== session.partCount) throw new DriveError("invalid_response");
|
|
2982
3281
|
failForTerminalStatus(baseline.lifecycle, baselineRequestId);
|
|
@@ -3033,7 +3332,8 @@ async function completeWithReconciliation(controls, input, session, digests) {
|
|
|
3033
3332
|
idempotencyKey: input.completionIdempotencyKey,
|
|
3034
3333
|
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
3035
3334
|
});
|
|
3036
|
-
assertReadyMatchesInput(completed.data, session, input, digests, completed.requestId);
|
|
3335
|
+
if (completed.data.state === "ready") assertReadyMatchesInput(completed.data, session, input, digests, completed.requestId);
|
|
3336
|
+
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
3337
|
return completed;
|
|
3038
3338
|
} catch (error) {
|
|
3039
3339
|
if (!isAmbiguousControlFailure(error) || input.signal?.aborted) throw error;
|
|
@@ -3054,6 +3354,7 @@ async function completeWithReconciliation(controls, input, session, digests) {
|
|
|
3054
3354
|
async function hashSource(source, byteLength, partCount, signal) {
|
|
3055
3355
|
const fullHash = sha256.create();
|
|
3056
3356
|
const partChecksums = [];
|
|
3357
|
+
const partMd5s = [];
|
|
3057
3358
|
for (let index = 0; index < partCount; index += 1) {
|
|
3058
3359
|
throwIfCallerAborted(signal);
|
|
3059
3360
|
const start = index * UPLOAD_PART_BYTE_LENGTH;
|
|
@@ -3070,13 +3371,15 @@ async function hashSource(source, byteLength, partCount, signal) {
|
|
|
3070
3371
|
const bytes = new Uint8Array(buffer);
|
|
3071
3372
|
fullHash.update(bytes);
|
|
3072
3373
|
partChecksums.push(toBase64(sha256(bytes)));
|
|
3374
|
+
partMd5s.push(toBase64(md5(bytes)));
|
|
3073
3375
|
}
|
|
3074
3376
|
return Object.freeze({
|
|
3075
3377
|
callerDeclaredContentDigest: `sha256:${bytesToHex(fullHash.digest())}`,
|
|
3076
|
-
partChecksums: Object.freeze(partChecksums)
|
|
3378
|
+
partChecksums: Object.freeze(partChecksums),
|
|
3379
|
+
partMd5s: Object.freeze(partMd5s)
|
|
3077
3380
|
});
|
|
3078
3381
|
}
|
|
3079
|
-
async function putPart(runtime, descriptor, part,
|
|
3382
|
+
async function putPart(runtime, descriptor, part, callerSignal) {
|
|
3080
3383
|
const remainingMilliseconds = descriptor.expiresAtEpochMilliseconds - Date.now();
|
|
3081
3384
|
if (remainingMilliseconds < 1) throw new DriveError("invalid_response");
|
|
3082
3385
|
const operation = createOperationSignal(callerSignal, Math.min(runtime.timeoutMilliseconds, remainingMilliseconds));
|
|
@@ -3094,8 +3397,9 @@ async function putPart(runtime, descriptor, part, checksumSha256, callerSignal)
|
|
|
3094
3397
|
}), operation.signal);
|
|
3095
3398
|
if (!(response instanceof Response)) throw new DriveError("invalid_response");
|
|
3096
3399
|
const etag = response.headers.get("etag");
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3400
|
+
const md5Response = response.headers.get("content-md5");
|
|
3401
|
+
const checksumMatches = md5Response === null || md5Response === descriptor.headers["content-md5"];
|
|
3402
|
+
if (response.status < 200 || response.status > 299 || !isEtag(etag) || !checksumMatches) throw new DriveError("invalid_response", { status: response.status });
|
|
3099
3403
|
return etag;
|
|
3100
3404
|
} catch (error) {
|
|
3101
3405
|
if (operation.didTimeout()) throw new DriveError("timeout");
|
|
@@ -3131,7 +3435,7 @@ function failForTerminalStatus(lifecycle, requestId) {
|
|
|
3131
3435
|
status: 409,
|
|
3132
3436
|
...requestId === void 0 ? {} : { requestId }
|
|
3133
3437
|
});
|
|
3134
|
-
if (lifecycle === "aborting" || lifecycle === "aborted") throw new DriveError("precondition_failed", {
|
|
3438
|
+
if (lifecycle === "aborting" || lifecycle === "aborted" || lifecycle === "failed") throw new DriveError("precondition_failed", {
|
|
3135
3439
|
status: 409,
|
|
3136
3440
|
...requestId === void 0 ? {} : { requestId }
|
|
3137
3441
|
});
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as RestoreItemVersionInput, A as ListFolderChildrenInput, B as ManagedItemVersionRestoreResult, C as FolderItem, D as GetItemVersionInput, E as GetItemInput, F as ManagedDownloadRestorePending, H as PendingUpload, I as ManagedItemMetadata, J as ProtectionClassification, L as ManagedItemVersion, M as ListItemVersionsInput, N as ListWorkspaceItemsInput, O as GetUploadStatusInput, P as ManagedDownloadDescriptor, Q as RestoreItemInput, R as ManagedItemVersionPage, T as GetCurrentWorkspaceInput, V as ManagedLifecycleItem, X as ReadyUpload, Z as RecordUploadPartInput, _t as WorkspaceItemSearchItem, at as UploadCompletion, b as DriveServerClientConfig, bt as operations, c as CurrentWorkspace, d as DownloadItemResult, dt as UploadPartDescriptor, ft as UploadPartResult, g as DriveOperationResult, gt as WorkspaceDiscoveryPage, h as DriveCredentialProvider, ht as WorkspaceDiscoveryItem, k as GetWorkspaceUsageInput, l as CurrentWorkspaceSources, mt as UploadStatus, n as CompleteUploadInput, nt as TrashItemInput, o as CreateUploadInput, ot as UploadConfirmedPart, pt as UploadSession, r as CreateDownloadInput, rt as UpdateItemInput, s as CreateUploadPartDescriptorInput, t as AbortUploadInput, tt as SearchWorkspaceItemsInput, u as DeleteItemInput, vt as WorkspaceItemSearchPage, w as FolderPage, y as DriveServerClient, yt as WorkspaceUsage, z as ManagedItemVersionResource } 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 CurrentWorkspaceSources, 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 GetWorkspaceUsageInput, type ListFolderChildrenInput, type ListItemVersionsInput, type ListWorkspaceItemsInput, 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 WorkspaceDiscoveryItem, type WorkspaceDiscoveryPage, type WorkspaceItemSearchItem, type WorkspaceItemSearchPage, type WorkspaceUsage, createDriveProvisioningClient, createDriveServerClient };
|