@finueva/drive 0.3.0 → 0.5.1
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 +21 -0
- package/README.md +45 -10
- package/dist/client.d.ts +2 -2
- package/dist/client.js +738 -6
- package/dist/contract.d.ts +2212 -336
- package/dist/core.d.ts +2 -1
- package/dist/core.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +738 -6
- package/dist/server.d.ts +2 -2
- package/dist/server.js +738 -6
- package/dist/types.d.ts +2 -2
- package/package.json +2 -1
package/dist/server.js
CHANGED
|
@@ -8,6 +8,7 @@ const DRIVE_API_ERROR_CODES = Object.freeze([
|
|
|
8
8
|
"invalid_pagination_cursor",
|
|
9
9
|
"invalid_idempotency_key",
|
|
10
10
|
"precondition_failed",
|
|
11
|
+
"range_not_satisfiable",
|
|
11
12
|
"idempotency_conflict",
|
|
12
13
|
"quota_exceeded",
|
|
13
14
|
"upload_recovery_required",
|
|
@@ -23,6 +24,7 @@ const DRIVE_API_ERROR_MESSAGES = Object.freeze({
|
|
|
23
24
|
invalid_pagination_cursor: "The pagination cursor is invalid.",
|
|
24
25
|
invalid_idempotency_key: "The idempotency key is invalid.",
|
|
25
26
|
precondition_failed: "The request precondition failed.",
|
|
27
|
+
range_not_satisfiable: "The requested byte range is not satisfiable.",
|
|
26
28
|
idempotency_conflict: "The idempotency key conflicts with an earlier request.",
|
|
27
29
|
quota_exceeded: "The workspace storage quota would be exceeded.",
|
|
28
30
|
upload_recovery_required: "The upload requires recovery before it can continue.",
|
|
@@ -61,6 +63,7 @@ const REQUEST_ID = /^[A-Za-z0-9_-]{16,128}$/;
|
|
|
61
63
|
const COLLECTION_ETAG = /^"drive\.permission-collection\.v1\.(0|[1-9][0-9]*)"$/;
|
|
62
64
|
const GRANT_ETAG$1 = /^"drive\.permission-grant\.v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)"$/;
|
|
63
65
|
const LIST_ETAG$1 = /^"drive\.permission-list\.v1\.[0-9a-f]{64}"$/;
|
|
66
|
+
const ITEM_ETAG = /^"drive\.item\.v1\.(0|[1-9][0-9]*)"$/;
|
|
64
67
|
async function parseResponse(response, operationSignal, preconditionStatus, successStatuses, guard, allowsQuotaExceeded, allowedErrorCodes) {
|
|
65
68
|
const requestId = safeRequestId(response.headers.get("x-request-id"));
|
|
66
69
|
if (requestId === null) {
|
|
@@ -68,6 +71,24 @@ async function parseResponse(response, operationSignal, preconditionStatus, succ
|
|
|
68
71
|
throw new DriveError("invalid_response", { status: response.status });
|
|
69
72
|
}
|
|
70
73
|
if (!successStatuses.includes(response.status)) throw await normalizeError(response, requestId, operationSignal, preconditionStatus, allowsQuotaExceeded, allowedErrorCodes);
|
|
74
|
+
if (response.status === 304) {
|
|
75
|
+
const contentLength = response.headers.get("content-length");
|
|
76
|
+
const etag = response.headers.get("etag");
|
|
77
|
+
const status = response.status;
|
|
78
|
+
if (response.body !== null || contentLength !== null && contentLength !== "0" || response.headers.has("content-type") || etag === null || !/^"[\x21\x23-\x7e]{1,1022}"$/.test(etag) || !guard(void 0, status, response.headers)) {
|
|
79
|
+
cancelResponse(response);
|
|
80
|
+
throw new DriveError("invalid_response", {
|
|
81
|
+
status,
|
|
82
|
+
requestId
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return Object.freeze({
|
|
86
|
+
data: void 0,
|
|
87
|
+
status,
|
|
88
|
+
requestId,
|
|
89
|
+
validators: Object.freeze({ etag })
|
|
90
|
+
});
|
|
91
|
+
}
|
|
71
92
|
const { value } = await parseBoundedJson(response, SUCCESS_BODY_LIMIT, response.status, requestId, operationSignal);
|
|
72
93
|
const status = response.status;
|
|
73
94
|
if (!guard(value, status, response.headers)) throw new DriveError("invalid_response", {
|
|
@@ -116,6 +137,12 @@ function parseGrantEtag(value) {
|
|
|
116
137
|
const grantRevision = Number(match[2]);
|
|
117
138
|
return Number.isSafeInteger(collectionRevision) && Number.isSafeInteger(grantRevision) ? [collectionRevision, grantRevision] : void 0;
|
|
118
139
|
}
|
|
140
|
+
function parseItemEtag(value) {
|
|
141
|
+
const match = ITEM_ETAG.exec(value);
|
|
142
|
+
if (!match) return void 0;
|
|
143
|
+
const revision = Number(match[1]);
|
|
144
|
+
return Number.isSafeInteger(revision) ? revision : void 0;
|
|
145
|
+
}
|
|
119
146
|
async function normalizeError(response, headerRequestId, signal, preconditionStatus, allowsQuotaExceeded, allowedErrorCodes) {
|
|
120
147
|
let parsed;
|
|
121
148
|
try {
|
|
@@ -159,6 +186,7 @@ function errorStatusMatches(code, status, preconditionStatus, allowsQuotaExceede
|
|
|
159
186
|
invalid_pagination_cursor: [422],
|
|
160
187
|
invalid_idempotency_key: [422],
|
|
161
188
|
precondition_failed: preconditionStatus === null ? [] : [preconditionStatus],
|
|
189
|
+
range_not_satisfiable: [416],
|
|
162
190
|
idempotency_conflict: [409],
|
|
163
191
|
quota_exceeded: [409],
|
|
164
192
|
upload_recovery_required: [409],
|
|
@@ -256,7 +284,7 @@ function readValidators(headers) {
|
|
|
256
284
|
const permissionCollectionEtag = headers.get("drive-permission-collection-etag");
|
|
257
285
|
const permissionGrantEtag = headers.get("drive-permission-grant-etag");
|
|
258
286
|
return Object.freeze({
|
|
259
|
-
...etag !== null && LIST_ETAG$1.test(etag) ? { etag } : {},
|
|
287
|
+
...etag !== null && (LIST_ETAG$1.test(etag) || parseItemEtag(etag) !== void 0) ? { etag } : {},
|
|
260
288
|
...permissionCollectionEtag !== null && parseCollectionEtag(permissionCollectionEtag) !== void 0 ? { permissionCollectionEtag } : {},
|
|
261
289
|
...permissionGrantEtag !== null && parseGrantEtag(permissionGrantEtag) !== void 0 ? { permissionGrantEtag } : {}
|
|
262
290
|
});
|
|
@@ -272,7 +300,8 @@ const WORKSPACE_ID$1 = /^drive\.workspace\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-
|
|
|
272
300
|
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}$/;
|
|
273
301
|
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}$/;
|
|
274
302
|
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}$/;
|
|
303
|
+
const VERSION_ID$1 = /^drive\.version\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
304
|
+
const RETRIEVAL_ID = /^drive\.retrieval\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
276
305
|
const CURSOR$1 = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
|
|
277
306
|
const AUTH_ID$1 = /^[A-Za-z0-9_-]{1,128}$/;
|
|
278
307
|
const GRANT_ETAG = /^"drive\.permission-grant\.v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)"$/;
|
|
@@ -297,6 +326,7 @@ const EFFECTIVE_ACTIONS = Object.freeze([
|
|
|
297
326
|
const MAX_UPLOAD_BYTE_LENGTH$1 = 33554432e4;
|
|
298
327
|
const UPLOAD_PART_BYTE_LENGTH$1 = 32 * 1024 * 1024;
|
|
299
328
|
const CONTENT_DIGEST$1 = /^sha256:[0-9a-f]{64}$/;
|
|
329
|
+
const UTF8 = new TextEncoder();
|
|
300
330
|
function isCurrentWorkspace(value) {
|
|
301
331
|
if (!isExactRecord(value, [
|
|
302
332
|
"workspaceId",
|
|
@@ -307,6 +337,61 @@ function isCurrentWorkspace(value) {
|
|
|
307
337
|
const reference = value.workspaceReference;
|
|
308
338
|
return isExactRecord(reference, ["type", "userId"]) && reference.type === "personal" && typeof reference.userId === "string" && AUTH_ID$1.test(reference.userId) || isExactRecord(reference, ["type", "organizationId"]) && reference.type === "organization" && typeof reference.organizationId === "string" && AUTH_ID$1.test(reference.organizationId);
|
|
309
339
|
}
|
|
340
|
+
function isManagedDownloadDescriptor(value) {
|
|
341
|
+
if (!isExactRecord(value, [
|
|
342
|
+
"mode",
|
|
343
|
+
"method",
|
|
344
|
+
"url",
|
|
345
|
+
"headers",
|
|
346
|
+
"expiresAtEpochMilliseconds",
|
|
347
|
+
"response"
|
|
348
|
+
]) || value.mode !== "presigned-single" || value.method !== "GET" && value.method !== "HEAD" || typeof value.url !== "string" || !isSafeCapabilityUrl(value.url) || !isSafeInteger$1(value.expiresAtEpochMilliseconds) || !isExactRecord(value.headers, ["if-match"]) && !isExactRecord(value.headers, ["if-match", "range"]) || typeof value.headers["if-match"] !== "string" || !isStrongEtag(value.headers["if-match"]) || value.headers.range !== void 0 && (typeof value.headers.range !== "string" || !/^bytes=(?:0|[1-9][0-9]*)-(?:0|[1-9][0-9]*)$/.test(value.headers.range)) || !isExactRecord(value.response, [
|
|
349
|
+
"status",
|
|
350
|
+
"versionId",
|
|
351
|
+
"byteLength",
|
|
352
|
+
"contentLength",
|
|
353
|
+
"contentType",
|
|
354
|
+
"contentDisposition",
|
|
355
|
+
"etag",
|
|
356
|
+
"acceptRanges",
|
|
357
|
+
"contentRange"
|
|
358
|
+
]) || value.response.status !== 200 && value.response.status !== 206 || typeof value.response.versionId !== "string" || !VERSION_ID$1.test(value.response.versionId) || !isSafeInteger$1(value.response.byteLength) || !isSafeInteger$1(value.response.contentLength) || typeof value.response.contentType !== "string" || !/^[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?\/[a-z0-9](?:[a-z0-9!#$&^_.+-]{0,125}[a-z0-9])?$/.test(value.response.contentType) || typeof value.response.contentDisposition !== "string" || value.response.contentDisposition.length > 2048 || !/^[\x20-\x7e]+$/.test(value.response.contentDisposition) || value.response.etag !== value.headers["if-match"] || value.response.acceptRanges !== "bytes" || value.response.contentRange !== null && typeof value.response.contentRange !== "string") return false;
|
|
359
|
+
if (!downloadDescriptorIsCoherent(value)) return false;
|
|
360
|
+
Object.freeze(value.headers);
|
|
361
|
+
Object.freeze(value.response);
|
|
362
|
+
Object.freeze(value);
|
|
363
|
+
return true;
|
|
364
|
+
}
|
|
365
|
+
function downloadDescriptorIsCoherent(value) {
|
|
366
|
+
const response = value.response;
|
|
367
|
+
if (response.contentLength > response.byteLength || value.method === "HEAD" && response.status !== 200 || !response.contentDisposition.startsWith("attachment; filename=\"")) return false;
|
|
368
|
+
if (response.status === 200) return value.headers.range === void 0 && response.contentRange === null && response.contentLength === response.byteLength;
|
|
369
|
+
if (value.method !== "GET" || value.headers.range === void 0 || response.contentRange === null) return false;
|
|
370
|
+
const range = /^bytes=(0|[1-9][0-9]*)-(0|[1-9][0-9]*)$/.exec(value.headers.range);
|
|
371
|
+
const contentRange = /^bytes (0|[1-9][0-9]*)-(0|[1-9][0-9]*)\/(0|[1-9][0-9]*)$/.exec(response.contentRange);
|
|
372
|
+
if (!range || !contentRange) return false;
|
|
373
|
+
const start = Number(range[1]);
|
|
374
|
+
const end = Number(range[2]);
|
|
375
|
+
const contentStart = Number(contentRange[1]);
|
|
376
|
+
const contentEnd = Number(contentRange[2]);
|
|
377
|
+
const byteLength = Number(contentRange[3]);
|
|
378
|
+
return [
|
|
379
|
+
start,
|
|
380
|
+
end,
|
|
381
|
+
contentStart,
|
|
382
|
+
contentEnd,
|
|
383
|
+
byteLength
|
|
384
|
+
].every(isSafeInteger$1) && start === contentStart && end === contentEnd && byteLength === response.byteLength && start <= end && end < byteLength && response.contentLength === end - start + 1;
|
|
385
|
+
}
|
|
386
|
+
function isManagedDownloadRestorePending(value) {
|
|
387
|
+
return isExactRecord(value, [
|
|
388
|
+
"mode",
|
|
389
|
+
"operationId",
|
|
390
|
+
"versionId",
|
|
391
|
+
"state",
|
|
392
|
+
"pollAfterSeconds"
|
|
393
|
+
]) && value.mode === "restore-pending" && typeof value.operationId === "string" && RETRIEVAL_ID.test(value.operationId) && typeof value.versionId === "string" && VERSION_ID$1.test(value.versionId) && (value.state === "pending" || value.state === "restoring") && isSafeInteger$1(value.pollAfterSeconds) && value.pollAfterSeconds >= 1 && value.pollAfterSeconds <= 60;
|
|
394
|
+
}
|
|
310
395
|
function isFolderPage(value, workspaceId, parentItemId) {
|
|
311
396
|
if (!(isExactRecord(value, ["items", "nextCursor"]) && Array.isArray(value.items) && value.items.length <= 50 && value.items.every(isFolderItem) && (value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length <= 699 && CURSOR$1.test(value.nextCursor)))) return false;
|
|
312
397
|
return value.items.every((item) => item.workspaceId === workspaceId && item.parentItemId === parentItemId) && isStrictlyOrdered(value.items, (item) => item.itemId);
|
|
@@ -323,6 +408,101 @@ function isFolderItem(value) {
|
|
|
323
408
|
"revision"
|
|
324
409
|
]) && typeof value.workspaceId === "string" && WORKSPACE_ID$1.test(value.workspaceId) && typeof value.volumeId === "string" && VOLUME_ID.test(value.volumeId) && typeof value.itemId === "string" && ITEM_ID$1.test(value.itemId) && typeof value.parentItemId === "string" && ITEM_ID$1.test(value.parentItemId) && (value.kind === "file" || value.kind === "folder") && isSafeFilename$1(value.name) && (value.visibility === "workspace" || value.visibility === "restricted") && isSafeInteger$1(value.revision);
|
|
325
410
|
}
|
|
411
|
+
function isManagedLifecycleItem(value, workspaceId, itemId, expectedState) {
|
|
412
|
+
if (!isExactRecord(value, [
|
|
413
|
+
"workspaceId",
|
|
414
|
+
"volumeId",
|
|
415
|
+
"itemId",
|
|
416
|
+
"parentItemId",
|
|
417
|
+
"kind",
|
|
418
|
+
"name",
|
|
419
|
+
"state",
|
|
420
|
+
"revision",
|
|
421
|
+
"purgeAfterEpochMilliseconds"
|
|
422
|
+
]) || value.workspaceId !== workspaceId || value.itemId !== itemId || typeof value.volumeId !== "string" || !VOLUME_ID.test(value.volumeId) || typeof value.parentItemId !== "string" || !ITEM_ID$1.test(value.parentItemId) || value.kind !== "file" && value.kind !== "folder" || !isSafeFilename$1(value.name) || value.state !== expectedState || !isSafeInteger$1(value.revision) || (value.state === "active" ? value.purgeAfterEpochMilliseconds !== null : !isSafeInteger$1(value.purgeAfterEpochMilliseconds))) return false;
|
|
423
|
+
Object.freeze(value);
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
function isManagedItemMetadata(value, workspaceId, itemId) {
|
|
427
|
+
if (!isExactRecord(value, [
|
|
428
|
+
"workspaceId",
|
|
429
|
+
"itemId",
|
|
430
|
+
"parentId",
|
|
431
|
+
"type",
|
|
432
|
+
"name",
|
|
433
|
+
"lifecycleState",
|
|
434
|
+
"revision",
|
|
435
|
+
"currentVersion"
|
|
436
|
+
]) || value.workspaceId !== workspaceId || value.itemId !== itemId || !(value.parentId === null || typeof value.parentId === "string" && ITEM_ID$1.test(value.parentId)) || value.type !== "file" && value.type !== "folder" || !isSafeFilename$1(value.name) || value.lifecycleState !== "active" || !isSafeInteger$1(value.revision) || (value.type === "folder" ? value.currentVersion !== null : !isCurrentVersionMetadata(value.currentVersion))) return false;
|
|
437
|
+
if (value.currentVersion !== null) Object.freeze(value.currentVersion);
|
|
438
|
+
Object.freeze(value);
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
function isWorkspaceItemSearchPage(value, workspaceId, query, limit) {
|
|
442
|
+
if (!isExactRecord(value, ["items", "nextCursor"]) || !Array.isArray(value.items) || value.items.length > limit || !value.items.every((item) => isWorkspaceItemSearchItem(item, workspaceId, query)) || !(value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length <= 699 && CURSOR$1.test(value.nextCursor)) || value.items.length === 0 && value.nextCursor !== null || new Set(value.items.map((item) => item.itemId)).size !== value.items.length || !isWorkspaceItemSearchOrder(value.items)) return false;
|
|
443
|
+
for (const item of value.items) {
|
|
444
|
+
if (item.currentVersion !== null) Object.freeze(item.currentVersion);
|
|
445
|
+
Object.freeze(item);
|
|
446
|
+
}
|
|
447
|
+
Object.freeze(value.items);
|
|
448
|
+
Object.freeze(value);
|
|
449
|
+
return true;
|
|
450
|
+
}
|
|
451
|
+
function itemEtagMatchesRevision(headers, revision) {
|
|
452
|
+
const etag = headers.get("etag");
|
|
453
|
+
return etag !== null && parseItemEtag(etag) === revision;
|
|
454
|
+
}
|
|
455
|
+
function isCurrentVersionMetadata(value) {
|
|
456
|
+
return isExactRecord(value, [
|
|
457
|
+
"versionId",
|
|
458
|
+
"state",
|
|
459
|
+
"byteLength",
|
|
460
|
+
"mediaType",
|
|
461
|
+
"protectionClassification"
|
|
462
|
+
]) && typeof value.versionId === "string" && VERSION_ID$1.test(value.versionId) && value.state === "current" && isSafeInteger$1(value.byteLength) && isMediaType$1(value.mediaType) && (value.protectionClassification === "ordinary" || value.protectionClassification === "opaque-encrypted");
|
|
463
|
+
}
|
|
464
|
+
function isWorkspaceItemSearchItem(value, workspaceId, query) {
|
|
465
|
+
return isExactRecord(value, [
|
|
466
|
+
"workspaceId",
|
|
467
|
+
"volumeId",
|
|
468
|
+
"provider",
|
|
469
|
+
"itemId",
|
|
470
|
+
"parentId",
|
|
471
|
+
"type",
|
|
472
|
+
"name",
|
|
473
|
+
"lifecycleState",
|
|
474
|
+
"revision",
|
|
475
|
+
"currentVersion"
|
|
476
|
+
]) && value.workspaceId === workspaceId && typeof value.volumeId === "string" && VOLUME_ID.test(value.volumeId) && value.provider === "managed" && typeof value.itemId === "string" && ITEM_ID$1.test(value.itemId) && (value.parentId === null || typeof value.parentId === "string" && ITEM_ID$1.test(value.parentId)) && (value.type === "file" || value.type === "folder") && isSafeFilename$1(value.name) && value.name.startsWith(query) && value.lifecycleState === "active" && isSafeInteger$1(value.revision) && (value.type === "folder" ? value.currentVersion === null : isCurrentVersionMetadata(value.currentVersion));
|
|
477
|
+
}
|
|
478
|
+
function isWorkspaceItemSearchOrder(items) {
|
|
479
|
+
for (let index = 1; index < items.length; index += 1) {
|
|
480
|
+
const previous = items[index - 1];
|
|
481
|
+
const current = items[index];
|
|
482
|
+
const nameOrder = compareBinary(previous.name, current.name);
|
|
483
|
+
if (nameOrder > 0 || nameOrder === 0 && previous.itemId >= current.itemId) return false;
|
|
484
|
+
}
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
function compareBinary(left, right) {
|
|
488
|
+
const leftBytes = UTF8.encode(left);
|
|
489
|
+
const rightBytes = UTF8.encode(right);
|
|
490
|
+
const length = Math.min(leftBytes.length, rightBytes.length);
|
|
491
|
+
for (let index = 0; index < length; index += 1) if (leftBytes[index] !== rightBytes[index]) return leftBytes[index] - rightBytes[index];
|
|
492
|
+
return leftBytes.length - rightBytes.length;
|
|
493
|
+
}
|
|
494
|
+
function isManagedItemVersionPage(value, limit) {
|
|
495
|
+
if (!isExactRecord(value, ["items", "nextCursor"]) || !Array.isArray(value.items) || value.items.length > limit || !value.items.every(isManagedItemVersion) || !(value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length <= 699 && CURSOR$1.test(value.nextCursor)) || value.nextCursor !== null && value.items.length === 0 || !isStrictlyOrdered(value.items, (version) => version.versionId)) return false;
|
|
496
|
+
for (const version of value.items) Object.freeze(version);
|
|
497
|
+
Object.freeze(value.items);
|
|
498
|
+
Object.freeze(value);
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
function isManagedItemVersionRestoreResult(value, versionId) {
|
|
502
|
+
if (!isExactRecord(value, ["itemRevision", "currentVersionId"]) || !isSafeInteger$1(value.itemRevision) || value.currentVersionId !== versionId) return false;
|
|
503
|
+
Object.freeze(value);
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
326
506
|
function isPermissionPage(value, headers, targetItemId) {
|
|
327
507
|
if (!(isExactRecord(value, [
|
|
328
508
|
"items",
|
|
@@ -387,7 +567,7 @@ function isUploadSession(value, expectedByteLength) {
|
|
|
387
567
|
"partCount",
|
|
388
568
|
"revision",
|
|
389
569
|
"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$1 || !isSafeInteger$1(value.partCount) || value.partCount > 1e4 || value.partCount !== Math.ceil(expectedByteLength / UPLOAD_PART_BYTE_LENGTH$1) || (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;
|
|
570
|
+
]) || 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" || value.partByteLength !== UPLOAD_PART_BYTE_LENGTH$1 || !isSafeInteger$1(value.partCount) || value.partCount > 1e4 || value.partCount !== Math.ceil(expectedByteLength / UPLOAD_PART_BYTE_LENGTH$1) || (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
571
|
Object.freeze(value);
|
|
392
572
|
return true;
|
|
393
573
|
}
|
|
@@ -404,7 +584,7 @@ function isUploadStatus(value, afterPartNumber, limit) {
|
|
|
404
584
|
"nextAfterPartNumber",
|
|
405
585
|
"expiresAtEpochMilliseconds",
|
|
406
586
|
"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" || ![
|
|
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" || ![
|
|
408
588
|
"initiating",
|
|
409
589
|
"recovery-required",
|
|
410
590
|
"uploading",
|
|
@@ -458,13 +638,47 @@ function isReadyUpload(value, expected) {
|
|
|
458
638
|
"displayFilename",
|
|
459
639
|
"mediaType",
|
|
460
640
|
"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;
|
|
641
|
+
]) || typeof value.itemId !== "string" || !ITEM_ID$1.test(value.itemId) || typeof value.versionId !== "string" || !VERSION_ID$1.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
642
|
Object.freeze(value);
|
|
463
643
|
return true;
|
|
464
644
|
}
|
|
465
645
|
function isPartChecksum$1(value) {
|
|
466
646
|
return typeof value === "string" && /^[A-Za-z0-9+/]{42}[AEIMQUYcgkosw048]=$/.test(value);
|
|
467
647
|
}
|
|
648
|
+
function isManagedItemVersion(value) {
|
|
649
|
+
const valid = isExactRecord(value, managedItemVersionKeys) && managedItemVersionFieldsAreValid(value);
|
|
650
|
+
if (valid) Object.freeze(value);
|
|
651
|
+
return valid;
|
|
652
|
+
}
|
|
653
|
+
function isManagedItemVersionResource(value, workspaceId, itemId, versionId) {
|
|
654
|
+
const valid = isExactRecord(value, [
|
|
655
|
+
...managedItemVersionKeys,
|
|
656
|
+
"workspaceId",
|
|
657
|
+
"itemId"
|
|
658
|
+
]) && value.workspaceId === workspaceId && value.itemId === itemId && value.versionId === versionId && managedItemVersionFieldsAreValid(value);
|
|
659
|
+
if (valid) Object.freeze(value);
|
|
660
|
+
return valid;
|
|
661
|
+
}
|
|
662
|
+
const managedItemVersionKeys = Object.freeze([
|
|
663
|
+
"versionId",
|
|
664
|
+
"state",
|
|
665
|
+
"revision",
|
|
666
|
+
"byteLength",
|
|
667
|
+
"contentDigest",
|
|
668
|
+
"mediaType",
|
|
669
|
+
"displayFilename",
|
|
670
|
+
"protectionClassification",
|
|
671
|
+
"archiveState"
|
|
672
|
+
]);
|
|
673
|
+
function managedItemVersionFieldsAreValid(value) {
|
|
674
|
+
return typeof value.versionId === "string" && VERSION_ID$1.test(value.versionId) && (value.state === "current" || value.state === "superseded") && isSafeInteger$1(value.revision) && isSafeInteger$1(value.byteLength) && typeof value.contentDigest === "string" && CONTENT_DIGEST$1.test(value.contentDigest) && isMediaType$1(value.mediaType) && isSafeFilename$1(value.displayFilename) && (value.protectionClassification === "ordinary" || value.protectionClassification === "opaque-encrypted") && [
|
|
675
|
+
"available",
|
|
676
|
+
"cold",
|
|
677
|
+
"restoring",
|
|
678
|
+
"unavailable",
|
|
679
|
+
"corrupt"
|
|
680
|
+
].includes(String(value.archiveState));
|
|
681
|
+
}
|
|
468
682
|
function mutationValidatorsAreCoherent(headers) {
|
|
469
683
|
const collection = headers.get("drive-permission-collection-etag");
|
|
470
684
|
const grant = headers.get("drive-permission-grant-etag");
|
|
@@ -551,6 +765,22 @@ function isStrictlyOrdered(values, key) {
|
|
|
551
765
|
function isSafeInteger$1(value) {
|
|
552
766
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
553
767
|
}
|
|
768
|
+
function isStrongEtag(value) {
|
|
769
|
+
return /^"[\x21\x23-\x7e]{1,1022}"$/.test(value);
|
|
770
|
+
}
|
|
771
|
+
function isSafeCapabilityUrl(value) {
|
|
772
|
+
try {
|
|
773
|
+
const url = new URL(value);
|
|
774
|
+
const localHttp = url.protocol === "http:" && [
|
|
775
|
+
"localhost",
|
|
776
|
+
"127.0.0.1",
|
|
777
|
+
"[::1]"
|
|
778
|
+
].includes(url.hostname);
|
|
779
|
+
return (url.protocol === "https:" || localHttp) && !url.username && !url.password && !url.hash;
|
|
780
|
+
} catch {
|
|
781
|
+
return false;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
554
784
|
function isExactRecord(value, keys) {
|
|
555
785
|
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
556
786
|
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
@@ -561,6 +791,7 @@ const ITEM_ID = /^drive\.item\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-
|
|
|
561
791
|
const WORKSPACE_ID = /^drive\.workspace\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
562
792
|
const GRANT_ID = /^drive\.grant\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
563
793
|
const UPLOAD_ID = /^drive\.upload\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
794
|
+
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}$/;
|
|
564
795
|
const CURSOR = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
|
|
565
796
|
const AUTH_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
566
797
|
const PERMISSION_ACTIONS = Object.freeze([
|
|
@@ -592,6 +823,71 @@ function validateResourceInput(value) {
|
|
|
592
823
|
...signal === void 0 ? {} : { signal }
|
|
593
824
|
};
|
|
594
825
|
}
|
|
826
|
+
function validateItemVersionInput(value) {
|
|
827
|
+
const input = captureRecord(value, [
|
|
828
|
+
"workspaceId",
|
|
829
|
+
"itemId",
|
|
830
|
+
"versionId"
|
|
831
|
+
], ["signal"]);
|
|
832
|
+
const resource = validateResourceInput({
|
|
833
|
+
workspaceId: input.workspaceId,
|
|
834
|
+
itemId: input.itemId,
|
|
835
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
836
|
+
});
|
|
837
|
+
if (typeof input.versionId !== "string" || !VERSION_ID.test(input.versionId)) throw new DriveError("invalid_input");
|
|
838
|
+
return {
|
|
839
|
+
...resource,
|
|
840
|
+
versionId: input.versionId
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
function validateCreateDownloadInput(value) {
|
|
844
|
+
const input = captureRecord(value, [
|
|
845
|
+
"workspaceId",
|
|
846
|
+
"itemId",
|
|
847
|
+
"idempotencyKey"
|
|
848
|
+
], [
|
|
849
|
+
"versionId",
|
|
850
|
+
"method",
|
|
851
|
+
"range",
|
|
852
|
+
"ifMatch",
|
|
853
|
+
"ifNoneMatch",
|
|
854
|
+
"ifRange",
|
|
855
|
+
"signal"
|
|
856
|
+
]);
|
|
857
|
+
const resource = validateResourceInput({
|
|
858
|
+
workspaceId: input.workspaceId,
|
|
859
|
+
itemId: input.itemId,
|
|
860
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
861
|
+
});
|
|
862
|
+
const method = input.method ?? "GET";
|
|
863
|
+
if (!isIdempotencyKey(input.idempotencyKey) || input.versionId !== void 0 && (typeof input.versionId !== "string" || !VERSION_ID.test(input.versionId)) || method !== "GET" && method !== "HEAD" || input.range !== void 0 && (typeof input.range !== "string" || input.range.length > 128 || !/^bytes=(?:[0-9]+-[0-9]*|-[0-9]+)$/.test(input.range)) || !isOptionalHeaderValue(input.ifMatch) || !isOptionalHeaderValue(input.ifNoneMatch) || !isOptionalHeaderValue(input.ifRange)) throw new DriveError("invalid_input");
|
|
864
|
+
return {
|
|
865
|
+
...resource,
|
|
866
|
+
idempotencyKey: input.idempotencyKey,
|
|
867
|
+
method,
|
|
868
|
+
...input.versionId === void 0 ? {} : { versionId: input.versionId },
|
|
869
|
+
...input.range === void 0 ? {} : { range: input.range },
|
|
870
|
+
...input.ifMatch === void 0 ? {} : { ifMatch: input.ifMatch },
|
|
871
|
+
...input.ifNoneMatch === void 0 ? {} : { ifNoneMatch: input.ifNoneMatch },
|
|
872
|
+
...input.ifRange === void 0 ? {} : { ifRange: input.ifRange }
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function validateSearchWorkspaceItemsInput(value) {
|
|
876
|
+
const input = captureRecord(value, ["workspaceId", "query"], [
|
|
877
|
+
"limit",
|
|
878
|
+
"cursor",
|
|
879
|
+
"signal"
|
|
880
|
+
]);
|
|
881
|
+
const signal = validateSignal(input.signal);
|
|
882
|
+
if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || !isSearchQuery(input.query) || input.limit !== void 0 && (!isSafeInteger(input.limit) || input.limit < 1 || input.limit > 50) || input.cursor !== void 0 && (typeof input.cursor !== "string" || input.cursor.length > 699 || !CURSOR.test(input.cursor))) throw new DriveError("invalid_input");
|
|
883
|
+
return {
|
|
884
|
+
workspaceId: input.workspaceId,
|
|
885
|
+
query: input.query,
|
|
886
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
887
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor },
|
|
888
|
+
...signal === void 0 ? {} : { signal }
|
|
889
|
+
};
|
|
890
|
+
}
|
|
595
891
|
function validatePageInput(value) {
|
|
596
892
|
const input = captureRecord(value, ["workspaceId", "itemId"], [
|
|
597
893
|
"signal",
|
|
@@ -631,6 +927,69 @@ function validateCreateFolderInput(value) {
|
|
|
631
927
|
idempotencyKey: input.idempotencyKey
|
|
632
928
|
};
|
|
633
929
|
}
|
|
930
|
+
function validateUpdateItemInput(value) {
|
|
931
|
+
const input = captureRecord(value, [
|
|
932
|
+
"workspaceId",
|
|
933
|
+
"itemId",
|
|
934
|
+
"name",
|
|
935
|
+
"parentItemId",
|
|
936
|
+
"idempotencyKey",
|
|
937
|
+
"ifMatch"
|
|
938
|
+
], ["signal"]);
|
|
939
|
+
const mutation = validateLifecycleMutationInput({
|
|
940
|
+
workspaceId: input.workspaceId,
|
|
941
|
+
itemId: input.itemId,
|
|
942
|
+
idempotencyKey: input.idempotencyKey,
|
|
943
|
+
ifMatch: input.ifMatch,
|
|
944
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
945
|
+
});
|
|
946
|
+
if (!isSafeFilename(input.name) || typeof input.parentItemId !== "string" || !ITEM_ID.test(input.parentItemId)) throw new DriveError("invalid_input");
|
|
947
|
+
return {
|
|
948
|
+
...mutation,
|
|
949
|
+
name: input.name,
|
|
950
|
+
parentItemId: input.parentItemId
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
function validateLifecycleMutationInput(value) {
|
|
954
|
+
const input = captureRecord(value, [
|
|
955
|
+
"workspaceId",
|
|
956
|
+
"itemId",
|
|
957
|
+
"idempotencyKey",
|
|
958
|
+
"ifMatch"
|
|
959
|
+
], ["signal"]);
|
|
960
|
+
const resource = validateResourceInput({
|
|
961
|
+
workspaceId: input.workspaceId,
|
|
962
|
+
itemId: input.itemId,
|
|
963
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
964
|
+
});
|
|
965
|
+
if (!isIdempotencyKey(input.idempotencyKey) || typeof input.ifMatch !== "string" || parseItemEtag(input.ifMatch) === void 0) throw new DriveError("invalid_input");
|
|
966
|
+
return {
|
|
967
|
+
...resource,
|
|
968
|
+
idempotencyKey: input.idempotencyKey,
|
|
969
|
+
ifMatch: input.ifMatch
|
|
970
|
+
};
|
|
971
|
+
}
|
|
972
|
+
function validateRestoreItemVersionInput(value) {
|
|
973
|
+
const input = captureRecord(value, [
|
|
974
|
+
"workspaceId",
|
|
975
|
+
"itemId",
|
|
976
|
+
"versionId",
|
|
977
|
+
"idempotencyKey",
|
|
978
|
+
"ifMatch"
|
|
979
|
+
], ["signal"]);
|
|
980
|
+
const mutation = validateLifecycleMutationInput({
|
|
981
|
+
workspaceId: input.workspaceId,
|
|
982
|
+
itemId: input.itemId,
|
|
983
|
+
idempotencyKey: input.idempotencyKey,
|
|
984
|
+
ifMatch: input.ifMatch,
|
|
985
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
986
|
+
});
|
|
987
|
+
if (typeof input.versionId !== "string" || !VERSION_ID.test(input.versionId)) throw new DriveError("invalid_input");
|
|
988
|
+
return {
|
|
989
|
+
...mutation,
|
|
990
|
+
versionId: input.versionId
|
|
991
|
+
};
|
|
992
|
+
}
|
|
634
993
|
function validateCreatePermissionInput(value) {
|
|
635
994
|
const input = captureRecord(value, [
|
|
636
995
|
"workspaceId",
|
|
@@ -906,6 +1265,24 @@ function isEtag(value) {
|
|
|
906
1265
|
function isMediaType(value) {
|
|
907
1266
|
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);
|
|
908
1267
|
}
|
|
1268
|
+
function isSearchQuery(value) {
|
|
1269
|
+
if (typeof value !== "string" || value.length === 0) return false;
|
|
1270
|
+
try {
|
|
1271
|
+
if (value.normalize("NFC") !== value) return false;
|
|
1272
|
+
let codePoints = 0;
|
|
1273
|
+
let bytes = 0;
|
|
1274
|
+
for (const character of value) {
|
|
1275
|
+
const point = character.codePointAt(0);
|
|
1276
|
+
if (point === void 0 || point <= 31 || point >= 127 && point <= 159 || point === 8232 || point === 8233 || point >= 55296 && point <= 57343) return false;
|
|
1277
|
+
codePoints += 1;
|
|
1278
|
+
bytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
1279
|
+
if (codePoints > 64 || bytes > 255) return false;
|
|
1280
|
+
}
|
|
1281
|
+
return true;
|
|
1282
|
+
} catch {
|
|
1283
|
+
return false;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
909
1286
|
function isExpiry(value) {
|
|
910
1287
|
return value === null || isSafeInteger(value);
|
|
911
1288
|
}
|
|
@@ -937,6 +1314,12 @@ function filenameIsReserved(value) {
|
|
|
937
1314
|
function isSafeInteger(value) {
|
|
938
1315
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
939
1316
|
}
|
|
1317
|
+
function isOptionalHeaderValue(value) {
|
|
1318
|
+
return value === void 0 || typeof value === "string" && value.length <= 8192 && !value.split("").some((character) => {
|
|
1319
|
+
const code = character.charCodeAt(0);
|
|
1320
|
+
return code <= 31 || code === 127;
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
940
1323
|
//#endregion
|
|
941
1324
|
//#region ../../node_modules/.pnpm/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
|
|
942
1325
|
const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
@@ -1355,7 +1738,7 @@ function createClientRuntime(config) {
|
|
|
1355
1738
|
try {
|
|
1356
1739
|
runtime = Object.freeze({
|
|
1357
1740
|
baseUrl: parseBaseUrl(config.baseUrl),
|
|
1358
|
-
fetchImplementation: config.fetch ?? globalThis.fetch,
|
|
1741
|
+
fetchImplementation: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
1359
1742
|
getCredential: config.getCredential,
|
|
1360
1743
|
timeoutMilliseconds: parseTimeoutMilliseconds(config.timeoutMilliseconds)
|
|
1361
1744
|
});
|
|
@@ -1480,6 +1863,25 @@ const CURRENT_WORKSPACE_ERROR_CODES = Object.freeze([
|
|
|
1480
1863
|
"invalid_request",
|
|
1481
1864
|
"service_unavailable"
|
|
1482
1865
|
]);
|
|
1866
|
+
const GET_ITEM_ERROR_CODES = Object.freeze([
|
|
1867
|
+
"authentication_required",
|
|
1868
|
+
"identity_authority_unavailable",
|
|
1869
|
+
"permission_denied",
|
|
1870
|
+
"resource_not_found",
|
|
1871
|
+
"invalid_request",
|
|
1872
|
+
"precondition_failed",
|
|
1873
|
+
"service_unavailable"
|
|
1874
|
+
]);
|
|
1875
|
+
const SEARCH_WORKSPACE_ITEMS_ERROR_CODES = Object.freeze([
|
|
1876
|
+
"authentication_required",
|
|
1877
|
+
"identity_authority_unavailable",
|
|
1878
|
+
"permission_denied",
|
|
1879
|
+
"resource_not_found",
|
|
1880
|
+
"invalid_request",
|
|
1881
|
+
"invalid_pagination_cursor",
|
|
1882
|
+
"precondition_failed",
|
|
1883
|
+
"service_unavailable"
|
|
1884
|
+
]);
|
|
1483
1885
|
const TRANSFER_ERROR_CODES = Object.freeze([
|
|
1484
1886
|
"authentication_required",
|
|
1485
1887
|
"identity_authority_unavailable",
|
|
@@ -1505,14 +1907,57 @@ const CREATE_UPLOAD_ERROR_CODES = Object.freeze([
|
|
|
1505
1907
|
"quota_exceeded"
|
|
1506
1908
|
]);
|
|
1507
1909
|
const COMPLETE_UPLOAD_ERROR_CODES = Object.freeze([...TRANSFER_ERROR_CODES, "invalid_idempotency_key"]);
|
|
1910
|
+
const LIFECYCLE_MUTATION_ERROR_CODES = Object.freeze([
|
|
1911
|
+
"authentication_required",
|
|
1912
|
+
"identity_authority_unavailable",
|
|
1913
|
+
"permission_denied",
|
|
1914
|
+
"resource_not_found",
|
|
1915
|
+
"invalid_request",
|
|
1916
|
+
"invalid_idempotency_key",
|
|
1917
|
+
"idempotency_conflict",
|
|
1918
|
+
"precondition_failed",
|
|
1919
|
+
"service_unavailable"
|
|
1920
|
+
]);
|
|
1921
|
+
const LIST_ITEM_VERSIONS_ERROR_CODES = Object.freeze([
|
|
1922
|
+
"authentication_required",
|
|
1923
|
+
"identity_authority_unavailable",
|
|
1924
|
+
"permission_denied",
|
|
1925
|
+
"resource_not_found",
|
|
1926
|
+
"invalid_request",
|
|
1927
|
+
"precondition_failed",
|
|
1928
|
+
"service_unavailable"
|
|
1929
|
+
]);
|
|
1930
|
+
const DOWNLOAD_ERROR_CODES = Object.freeze([
|
|
1931
|
+
"authentication_required",
|
|
1932
|
+
"identity_authority_unavailable",
|
|
1933
|
+
"permission_denied",
|
|
1934
|
+
"resource_not_found",
|
|
1935
|
+
"invalid_request",
|
|
1936
|
+
"invalid_idempotency_key",
|
|
1937
|
+
"idempotency_conflict",
|
|
1938
|
+
"precondition_failed",
|
|
1939
|
+
"range_not_satisfiable",
|
|
1940
|
+
"service_unavailable"
|
|
1941
|
+
]);
|
|
1508
1942
|
function createDriveClientInternal(config) {
|
|
1509
1943
|
return createDriveOperations(createClientRuntime(config));
|
|
1510
1944
|
}
|
|
1511
1945
|
function createDriveOperations(runtime) {
|
|
1512
1946
|
return Object.freeze({
|
|
1513
1947
|
getCurrentWorkspace: (input) => getCurrentWorkspace(runtime, input),
|
|
1948
|
+
getItem: (input) => getItem(runtime, input),
|
|
1949
|
+
searchWorkspaceItems: (input) => searchWorkspaceItems(runtime, input),
|
|
1514
1950
|
listFolderChildren: (input) => listFolderChildren(runtime, input),
|
|
1515
1951
|
createFolder: (input) => createFolder(runtime, input),
|
|
1952
|
+
updateItem: (input) => updateItem(runtime, input),
|
|
1953
|
+
trashItem: (input) => trashItem(runtime, input),
|
|
1954
|
+
restoreItem: (input) => restoreItem(runtime, input),
|
|
1955
|
+
deleteItem: (input) => deleteItem(runtime, input),
|
|
1956
|
+
listItemVersions: (input) => listItemVersions(runtime, input),
|
|
1957
|
+
getItemVersion: (input) => getItemVersion(runtime, input),
|
|
1958
|
+
restoreItemVersion: (input) => restoreItemVersion(runtime, input),
|
|
1959
|
+
createDownload: (input) => createDownload(runtime, input),
|
|
1960
|
+
downloadItem: (input) => downloadItem(runtime, input),
|
|
1516
1961
|
listItemPermissions: (input) => listItemPermissions(runtime, input),
|
|
1517
1962
|
readEffectiveItemPermissions: (input) => readEffectiveItemPermissions(runtime, input),
|
|
1518
1963
|
createItemPermission: (input) => createItemPermission(runtime, input),
|
|
@@ -1526,12 +1971,205 @@ function createDriveOperations(runtime) {
|
|
|
1526
1971
|
abortUpload: (input) => abortUpload(runtime, input)
|
|
1527
1972
|
});
|
|
1528
1973
|
}
|
|
1974
|
+
async function createDownload(runtime, input) {
|
|
1975
|
+
const validated = validateCreateDownloadInput(input);
|
|
1976
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/downloads", {
|
|
1977
|
+
...operationOptions("createDownload", { params: {
|
|
1978
|
+
path: {
|
|
1979
|
+
workspaceId: validated.workspaceId,
|
|
1980
|
+
itemId: validated.itemId
|
|
1981
|
+
},
|
|
1982
|
+
query: validated.versionId === void 0 ? {} : { versionId: validated.versionId },
|
|
1983
|
+
header: {
|
|
1984
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
1985
|
+
"Download-Method": validated.method,
|
|
1986
|
+
...validated.range === void 0 ? {} : { Range: validated.range },
|
|
1987
|
+
...validated.ifMatch === void 0 ? {} : { "If-Match": validated.ifMatch },
|
|
1988
|
+
...validated.ifNoneMatch === void 0 ? {} : { "If-None-Match": validated.ifNoneMatch },
|
|
1989
|
+
...validated.ifRange === void 0 ? {} : { "If-Range": validated.ifRange }
|
|
1990
|
+
}
|
|
1991
|
+
} }),
|
|
1992
|
+
...requestOptions
|
|
1993
|
+
}), [
|
|
1994
|
+
200,
|
|
1995
|
+
202,
|
|
1996
|
+
304
|
|
1997
|
+
], (value, status) => status === 200 ? isManagedDownloadDescriptor(value) : status === 202 ? isManagedDownloadRestorePending(value) : value === void 0, false, DOWNLOAD_ERROR_CODES);
|
|
1998
|
+
}
|
|
1999
|
+
async function downloadItem(runtime, input) {
|
|
2000
|
+
const validated = validateCreateDownloadInput(input);
|
|
2001
|
+
const created = await createDownload(runtime, input);
|
|
2002
|
+
if (created.status === 202 || created.status === 304) return created;
|
|
2003
|
+
const descriptor = created.data;
|
|
2004
|
+
if (descriptor.expiresAtEpochMilliseconds <= Date.now()) throw new DriveError("invalid_response");
|
|
2005
|
+
const operation = createOperationSignal(validated.signal, runtime.timeoutMilliseconds);
|
|
2006
|
+
try {
|
|
2007
|
+
const response = await raceWithAbort(runtime.fetchImplementation(directDownloadRequest(descriptor, operation.signal)), operation.signal);
|
|
2008
|
+
if (!responseMatchesDownloadDescriptor(response, descriptor)) {
|
|
2009
|
+
await response.body?.cancel().catch(() => void 0);
|
|
2010
|
+
throw new DriveError("invalid_response");
|
|
2011
|
+
}
|
|
2012
|
+
const responseHeaders = downloadResponseHeaders(descriptor);
|
|
2013
|
+
if (descriptor.method === "HEAD") {
|
|
2014
|
+
await response.body?.cancel().catch(() => void 0);
|
|
2015
|
+
operation.dispose();
|
|
2016
|
+
return new Response(null, {
|
|
2017
|
+
status: response.status,
|
|
2018
|
+
headers: responseHeaders
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
if (!response.body) {
|
|
2022
|
+
operation.dispose();
|
|
2023
|
+
if (descriptor.response.contentLength !== 0) throw new DriveError("invalid_response");
|
|
2024
|
+
return new Response(null, {
|
|
2025
|
+
status: response.status,
|
|
2026
|
+
headers: responseHeaders
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
operation.dispose();
|
|
2030
|
+
return new Response(streamWithOperationLifetime(response.body, descriptor.response.contentLength, validated.signal), {
|
|
2031
|
+
status: response.status,
|
|
2032
|
+
headers: responseHeaders
|
|
2033
|
+
});
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
operation.dispose();
|
|
2036
|
+
if (operation.didTimeout()) throw new DriveError("timeout");
|
|
2037
|
+
if (error instanceof DriveError) throw error;
|
|
2038
|
+
throw operation.signal.aborted ? new DriveError(operation.didTimeout() ? "timeout" : "aborted") : new DriveError("network_error");
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
function downloadResponseHeaders(descriptor) {
|
|
2042
|
+
const expected = descriptor.response;
|
|
2043
|
+
const headers = new Headers();
|
|
2044
|
+
headers.set("accept-ranges", expected.acceptRanges);
|
|
2045
|
+
headers.set("content-disposition", expected.contentDisposition);
|
|
2046
|
+
headers.set("content-length", String(expected.contentLength));
|
|
2047
|
+
headers.set("content-type", expected.contentType);
|
|
2048
|
+
headers.set("etag", expected.etag);
|
|
2049
|
+
if (expected.contentRange === null) headers.delete("content-range");
|
|
2050
|
+
else headers.set("content-range", expected.contentRange);
|
|
2051
|
+
return headers;
|
|
2052
|
+
}
|
|
2053
|
+
function directDownloadRequest(descriptor, signal) {
|
|
2054
|
+
const base = {
|
|
2055
|
+
method: descriptor.method,
|
|
2056
|
+
headers: descriptor.headers,
|
|
2057
|
+
redirect: "manual",
|
|
2058
|
+
signal
|
|
2059
|
+
};
|
|
2060
|
+
try {
|
|
2061
|
+
return new Request(descriptor.url, {
|
|
2062
|
+
...base,
|
|
2063
|
+
cache: "no-store",
|
|
2064
|
+
credentials: "omit",
|
|
2065
|
+
referrerPolicy: "no-referrer"
|
|
2066
|
+
});
|
|
2067
|
+
} catch {
|
|
2068
|
+
try {
|
|
2069
|
+
return new Request(descriptor.url, {
|
|
2070
|
+
...base,
|
|
2071
|
+
credentials: "omit",
|
|
2072
|
+
referrerPolicy: "no-referrer"
|
|
2073
|
+
});
|
|
2074
|
+
} catch {
|
|
2075
|
+
return new Request(descriptor.url, {
|
|
2076
|
+
...base,
|
|
2077
|
+
credentials: "omit"
|
|
2078
|
+
});
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
function responseMatchesDownloadDescriptor(response, descriptor) {
|
|
2083
|
+
const expected = descriptor.response;
|
|
2084
|
+
const encoding = response.headers.get("content-encoding");
|
|
2085
|
+
return response.status === expected.status && response.headers.get("etag") === expected.etag && response.headers.get("content-length") === String(expected.contentLength) && (encoding === null || encoding === "identity") && (expected.contentRange === null ? response.headers.get("content-range") === null : response.headers.get("content-range") === expected.contentRange);
|
|
2086
|
+
}
|
|
2087
|
+
function streamWithOperationLifetime(source, expectedLength, signal) {
|
|
2088
|
+
const reader = source.getReader();
|
|
2089
|
+
let receivedLength = 0;
|
|
2090
|
+
let finished = false;
|
|
2091
|
+
let removeAbort = () => {};
|
|
2092
|
+
return new ReadableStream({
|
|
2093
|
+
start(controller) {
|
|
2094
|
+
if (!signal) return;
|
|
2095
|
+
const onAbort = () => {
|
|
2096
|
+
if (finished) return;
|
|
2097
|
+
finished = true;
|
|
2098
|
+
removeAbort();
|
|
2099
|
+
reader.cancel().catch(() => void 0);
|
|
2100
|
+
controller.error(new DriveError("aborted"));
|
|
2101
|
+
};
|
|
2102
|
+
if (signal.aborted) onAbort();
|
|
2103
|
+
else {
|
|
2104
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2105
|
+
removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
async pull(controller) {
|
|
2109
|
+
if (finished) return;
|
|
2110
|
+
try {
|
|
2111
|
+
const chunk = await reader.read();
|
|
2112
|
+
if (finished) return;
|
|
2113
|
+
if (chunk.done) {
|
|
2114
|
+
finished = true;
|
|
2115
|
+
removeAbort();
|
|
2116
|
+
reader.releaseLock();
|
|
2117
|
+
if (receivedLength === expectedLength) controller.close();
|
|
2118
|
+
else controller.error(new DriveError("invalid_response"));
|
|
2119
|
+
} else {
|
|
2120
|
+
receivedLength += chunk.value.byteLength;
|
|
2121
|
+
if (!Number.isSafeInteger(receivedLength) || receivedLength > expectedLength) {
|
|
2122
|
+
finished = true;
|
|
2123
|
+
removeAbort();
|
|
2124
|
+
await reader.cancel().catch(() => void 0);
|
|
2125
|
+
controller.error(new DriveError("invalid_response"));
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
controller.enqueue(chunk.value);
|
|
2129
|
+
}
|
|
2130
|
+
} catch (error) {
|
|
2131
|
+
if (finished) return;
|
|
2132
|
+
finished = true;
|
|
2133
|
+
removeAbort();
|
|
2134
|
+
await reader.cancel().catch(() => void 0);
|
|
2135
|
+
controller.error(error instanceof DriveError ? error : signal?.aborted ? new DriveError("aborted") : new DriveError("network_error"));
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
async cancel(reason) {
|
|
2139
|
+
if (finished) return;
|
|
2140
|
+
finished = true;
|
|
2141
|
+
removeAbort();
|
|
2142
|
+
await reader.cancel(reason).catch(() => void 0);
|
|
2143
|
+
}
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
1529
2146
|
async function getCurrentWorkspace(runtime, input) {
|
|
1530
2147
|
return execute(runtime, validateCurrentWorkspaceInput(input).signal, null, (api, requestOptions) => api.GET("/api/v1/workspaces/current", {
|
|
1531
2148
|
...operationOptions("getCurrentWorkspace", { params: {} }),
|
|
1532
2149
|
...requestOptions
|
|
1533
2150
|
}), [200], isCurrentWorkspace, false, CURRENT_WORKSPACE_ERROR_CODES);
|
|
1534
2151
|
}
|
|
2152
|
+
async function getItem(runtime, input) {
|
|
2153
|
+
const validated = validateResourceInput(input);
|
|
2154
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}", {
|
|
2155
|
+
...operationOptions("getItem", { params: { path: resourcePath(validated) } }),
|
|
2156
|
+
...requestOptions
|
|
2157
|
+
}), [200], (value, _status, headers) => isManagedItemMetadata(value, validated.workspaceId, validated.itemId) && itemEtagMatchesRevision(headers, value.revision), false, GET_ITEM_ERROR_CODES);
|
|
2158
|
+
}
|
|
2159
|
+
async function searchWorkspaceItems(runtime, input) {
|
|
2160
|
+
const validated = validateSearchWorkspaceItemsInput(input);
|
|
2161
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/search", {
|
|
2162
|
+
...operationOptions("searchWorkspaceItems", { params: {
|
|
2163
|
+
path: { workspaceId: validated.workspaceId },
|
|
2164
|
+
query: {
|
|
2165
|
+
query: validated.query,
|
|
2166
|
+
...validated.limit === void 0 ? {} : { limit: validated.limit },
|
|
2167
|
+
...validated.cursor === void 0 ? {} : { cursor: validated.cursor }
|
|
2168
|
+
}
|
|
2169
|
+
} }),
|
|
2170
|
+
...requestOptions
|
|
2171
|
+
}), [200], (value) => isWorkspaceItemSearchPage(value, validated.workspaceId, validated.query, validated.limit ?? 50), false, SEARCH_WORKSPACE_ITEMS_ERROR_CODES);
|
|
2172
|
+
}
|
|
1535
2173
|
async function listFolderChildren(runtime, input) {
|
|
1536
2174
|
const validated = validatePageInput(input);
|
|
1537
2175
|
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/children", {
|
|
@@ -1555,6 +2193,100 @@ async function createFolder(runtime, input) {
|
|
|
1555
2193
|
...requestOptions
|
|
1556
2194
|
}), [200, 201], (value) => isFolderItem(value) && value.workspaceId === validated.workspaceId && value.parentItemId === validated.itemId && value.kind === "folder" && value.name === validated.name);
|
|
1557
2195
|
}
|
|
2196
|
+
async function updateItem(runtime, input) {
|
|
2197
|
+
const validated = validateUpdateItemInput(input);
|
|
2198
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.PATCH("/api/v1/workspaces/{workspaceId}/items/{itemId}", {
|
|
2199
|
+
...operationOptions("updateItem", {
|
|
2200
|
+
params: {
|
|
2201
|
+
path: resourcePath(validated),
|
|
2202
|
+
header: {
|
|
2203
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
2204
|
+
"If-Match": validated.ifMatch
|
|
2205
|
+
}
|
|
2206
|
+
},
|
|
2207
|
+
body: {
|
|
2208
|
+
name: validated.name,
|
|
2209
|
+
parentItemId: validated.parentItemId
|
|
2210
|
+
}
|
|
2211
|
+
}),
|
|
2212
|
+
...requestOptions
|
|
2213
|
+
}), [200], (value, _status, headers) => isManagedLifecycleItem(value, validated.workspaceId, validated.itemId, "active") && value.name === validated.name && value.parentItemId === validated.parentItemId && itemEtagMatchesRevision(headers, value.revision), false, LIFECYCLE_MUTATION_ERROR_CODES);
|
|
2214
|
+
}
|
|
2215
|
+
async function trashItem(runtime, input) {
|
|
2216
|
+
const validated = validateLifecycleMutationInput(input);
|
|
2217
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/trash", {
|
|
2218
|
+
...operationOptions("trashItem", { params: {
|
|
2219
|
+
path: resourcePath(validated),
|
|
2220
|
+
header: {
|
|
2221
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
2222
|
+
"If-Match": validated.ifMatch
|
|
2223
|
+
}
|
|
2224
|
+
} }),
|
|
2225
|
+
...requestOptions
|
|
2226
|
+
}), [200], (value, _status, headers) => isManagedLifecycleItem(value, validated.workspaceId, validated.itemId, "trashed") && itemEtagMatchesRevision(headers, value.revision), false, LIFECYCLE_MUTATION_ERROR_CODES);
|
|
2227
|
+
}
|
|
2228
|
+
async function restoreItem(runtime, input) {
|
|
2229
|
+
const validated = validateLifecycleMutationInput(input);
|
|
2230
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/restore", {
|
|
2231
|
+
...operationOptions("restoreItem", { params: {
|
|
2232
|
+
path: resourcePath(validated),
|
|
2233
|
+
header: {
|
|
2234
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
2235
|
+
"If-Match": validated.ifMatch
|
|
2236
|
+
}
|
|
2237
|
+
} }),
|
|
2238
|
+
...requestOptions
|
|
2239
|
+
}), [200], (value, _status, headers) => isManagedLifecycleItem(value, validated.workspaceId, validated.itemId, "active") && itemEtagMatchesRevision(headers, value.revision), false, LIFECYCLE_MUTATION_ERROR_CODES);
|
|
2240
|
+
}
|
|
2241
|
+
async function deleteItem(runtime, input) {
|
|
2242
|
+
const validated = validateLifecycleMutationInput(input);
|
|
2243
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.DELETE("/api/v1/workspaces/{workspaceId}/items/{itemId}", {
|
|
2244
|
+
...operationOptions("deleteItem", { params: {
|
|
2245
|
+
path: resourcePath(validated),
|
|
2246
|
+
header: {
|
|
2247
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
2248
|
+
"If-Match": validated.ifMatch
|
|
2249
|
+
}
|
|
2250
|
+
} }),
|
|
2251
|
+
...requestOptions
|
|
2252
|
+
}), [200, 202], (value, _status, headers) => isManagedLifecycleItem(value, validated.workspaceId, validated.itemId, "deleting") && itemEtagMatchesRevision(headers, value.revision), false, LIFECYCLE_MUTATION_ERROR_CODES);
|
|
2253
|
+
}
|
|
2254
|
+
async function listItemVersions(runtime, input) {
|
|
2255
|
+
const validated = validatePageInput(input);
|
|
2256
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/versions", {
|
|
2257
|
+
...operationOptions("listItemVersions", { params: {
|
|
2258
|
+
path: resourcePath(validated),
|
|
2259
|
+
query: pageQuery(validated)
|
|
2260
|
+
} }),
|
|
2261
|
+
...requestOptions
|
|
2262
|
+
}), [200], (value) => isManagedItemVersionPage(value, validated.limit ?? 50), false, LIST_ITEM_VERSIONS_ERROR_CODES);
|
|
2263
|
+
}
|
|
2264
|
+
async function getItemVersion(runtime, input) {
|
|
2265
|
+
const validated = validateItemVersionInput(input);
|
|
2266
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/versions/{versionId}", {
|
|
2267
|
+
...operationOptions("getItemVersion", { params: { path: {
|
|
2268
|
+
...resourcePath(validated),
|
|
2269
|
+
versionId: validated.versionId
|
|
2270
|
+
} } }),
|
|
2271
|
+
...requestOptions
|
|
2272
|
+
}), [200], (value) => isManagedItemVersionResource(value, validated.workspaceId, validated.itemId, validated.versionId), false, LIST_ITEM_VERSIONS_ERROR_CODES);
|
|
2273
|
+
}
|
|
2274
|
+
async function restoreItemVersion(runtime, input) {
|
|
2275
|
+
const validated = validateRestoreItemVersionInput(input);
|
|
2276
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/versions/{versionId}/restore", {
|
|
2277
|
+
...operationOptions("restoreItemVersion", { params: {
|
|
2278
|
+
path: {
|
|
2279
|
+
...resourcePath(validated),
|
|
2280
|
+
versionId: validated.versionId
|
|
2281
|
+
},
|
|
2282
|
+
header: {
|
|
2283
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
2284
|
+
"If-Match": validated.ifMatch
|
|
2285
|
+
}
|
|
2286
|
+
} }),
|
|
2287
|
+
...requestOptions
|
|
2288
|
+
}), [200], (value, _status, headers) => isManagedItemVersionRestoreResult(value, validated.versionId) && itemEtagMatchesRevision(headers, value.itemRevision), false, LIFECYCLE_MUTATION_ERROR_CODES);
|
|
2289
|
+
}
|
|
1558
2290
|
async function listItemPermissions(runtime, input) {
|
|
1559
2291
|
const validated = validatePageInput(input);
|
|
1560
2292
|
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions", {
|