@finueva/drive 0.1.0 → 0.1.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 +6 -0
- package/README.md +1 -1
- package/dist/client.js +1156 -1093
- package/dist/contract.d.ts +254 -499
- package/dist/index.js +1156 -1093
- package/dist/server.js +1156 -1093
- package/package.json +6 -6
package/dist/client.js
CHANGED
|
@@ -1,483 +1,256 @@
|
|
|
1
|
-
//#region
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
//#region src/core.ts
|
|
2
|
+
const DRIVE_API_ERROR_CODES = Object.freeze([
|
|
3
|
+
"authentication_required",
|
|
4
|
+
"identity_authority_unavailable",
|
|
5
|
+
"permission_denied",
|
|
6
|
+
"resource_not_found",
|
|
7
|
+
"invalid_request",
|
|
8
|
+
"invalid_pagination_cursor",
|
|
9
|
+
"invalid_idempotency_key",
|
|
10
|
+
"precondition_failed",
|
|
11
|
+
"idempotency_conflict",
|
|
12
|
+
"quota_exceeded",
|
|
13
|
+
"service_unavailable",
|
|
14
|
+
"internal_error"
|
|
15
|
+
]);
|
|
16
|
+
const DRIVE_API_ERROR_MESSAGES = Object.freeze({
|
|
17
|
+
authentication_required: "Authentication is required.",
|
|
18
|
+
identity_authority_unavailable: "Authentication is temporarily unavailable.",
|
|
19
|
+
permission_denied: "The requested action is not permitted.",
|
|
20
|
+
resource_not_found: "The requested resource was not found.",
|
|
21
|
+
invalid_request: "The request is invalid.",
|
|
22
|
+
invalid_pagination_cursor: "The pagination cursor is invalid.",
|
|
23
|
+
invalid_idempotency_key: "The idempotency key is invalid.",
|
|
24
|
+
precondition_failed: "The request precondition failed.",
|
|
25
|
+
idempotency_conflict: "The idempotency key conflicts with an earlier request.",
|
|
26
|
+
quota_exceeded: "The workspace storage quota would be exceeded.",
|
|
27
|
+
service_unavailable: "The service is temporarily unavailable.",
|
|
28
|
+
internal_error: "The request could not be completed."
|
|
29
|
+
});
|
|
30
|
+
const SDK_MESSAGES = Object.freeze({
|
|
31
|
+
invalid_input: "The Drive SDK input is invalid.",
|
|
32
|
+
credential_unavailable: "A Drive credential could not be obtained.",
|
|
33
|
+
network_error: "The Drive request could not reach the service.",
|
|
34
|
+
timeout: "The Drive request timed out.",
|
|
35
|
+
aborted: "The Drive request was aborted.",
|
|
36
|
+
invalid_response: "Drive returned an invalid response."
|
|
37
|
+
});
|
|
38
|
+
var DriveError = class extends Error {
|
|
39
|
+
code;
|
|
40
|
+
status;
|
|
41
|
+
requestId;
|
|
42
|
+
details;
|
|
43
|
+
constructor(code, options = {}) {
|
|
44
|
+
super(code in DRIVE_API_ERROR_MESSAGES ? DRIVE_API_ERROR_MESSAGES[code] : SDK_MESSAGES[code]);
|
|
45
|
+
this.name = "DriveError";
|
|
46
|
+
this.code = code;
|
|
47
|
+
this.status = options.status ?? null;
|
|
48
|
+
this.requestId = options.requestId ?? null;
|
|
49
|
+
this.details = Object.freeze({});
|
|
50
|
+
}
|
|
5
51
|
};
|
|
6
|
-
|
|
7
|
-
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/internal/client/response.ts
|
|
54
|
+
const ERROR_BODY_LIMIT = 16 * 1024;
|
|
55
|
+
const SUCCESS_BODY_LIMIT = 256 * 1024;
|
|
56
|
+
const RESPONSE_CHUNK_LIMIT = 256;
|
|
57
|
+
const RESPONSE_DEADLINE_MILLISECONDS = 5e3;
|
|
58
|
+
const REQUEST_ID = /^[A-Za-z0-9_-]{16,128}$/;
|
|
59
|
+
const COLLECTION_ETAG = /^"drive\.permission-collection\.v1\.(0|[1-9][0-9]*)"$/;
|
|
60
|
+
const GRANT_ETAG$1 = /^"drive\.permission-grant\.v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)"$/;
|
|
61
|
+
const LIST_ETAG$1 = /^"drive\.permission-list\.v1\.[0-9a-f]{64}"$/;
|
|
62
|
+
async function parseResponse(response, operationSignal, preconditionStatus, successStatuses, guard, allowsQuotaExceeded) {
|
|
63
|
+
const requestId = safeRequestId(response.headers.get("x-request-id"));
|
|
64
|
+
if (requestId === null) {
|
|
65
|
+
cancelResponse(response);
|
|
66
|
+
throw new DriveError("invalid_response", { status: response.status });
|
|
67
|
+
}
|
|
68
|
+
if (!successStatuses.includes(response.status)) throw await normalizeError(response, requestId, operationSignal, preconditionStatus, allowsQuotaExceeded);
|
|
69
|
+
const { value } = await parseBoundedJson(response, SUCCESS_BODY_LIMIT, response.status, requestId, operationSignal);
|
|
70
|
+
const status = response.status;
|
|
71
|
+
if (!guard(value, status, response.headers)) throw new DriveError("invalid_response", {
|
|
72
|
+
status,
|
|
73
|
+
requestId
|
|
74
|
+
});
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
data: value,
|
|
77
|
+
status,
|
|
78
|
+
requestId,
|
|
79
|
+
validators: readValidators(response.headers)
|
|
80
|
+
});
|
|
8
81
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
82
|
+
function parseCollectionEtag(value) {
|
|
83
|
+
const match = COLLECTION_ETAG.exec(value);
|
|
84
|
+
if (!match) return void 0;
|
|
85
|
+
const revision = Number(match[1]);
|
|
86
|
+
return Number.isSafeInteger(revision) ? revision : void 0;
|
|
87
|
+
}
|
|
88
|
+
function parseGrantEtag(value) {
|
|
89
|
+
const match = GRANT_ETAG$1.exec(value);
|
|
90
|
+
if (!match) return void 0;
|
|
91
|
+
const collectionRevision = Number(match[1]);
|
|
92
|
+
const grantRevision = Number(match[2]);
|
|
93
|
+
return Number.isSafeInteger(collectionRevision) && Number.isSafeInteger(grantRevision) ? [collectionRevision, grantRevision] : void 0;
|
|
94
|
+
}
|
|
95
|
+
async function normalizeError(response, headerRequestId, signal, preconditionStatus, allowsQuotaExceeded) {
|
|
96
|
+
let parsed;
|
|
97
|
+
try {
|
|
98
|
+
parsed = await parseBoundedJson(response, ERROR_BODY_LIMIT, response.status, headerRequestId, signal);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
if (error instanceof DriveError && error.code === "aborted") return error;
|
|
101
|
+
return new DriveError("invalid_response", {
|
|
102
|
+
status: response.status,
|
|
103
|
+
requestId: headerRequestId
|
|
22
104
|
});
|
|
23
|
-
const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;
|
|
24
|
-
const serializedBody = body === void 0 ? void 0 : bodySerializer(body, mergeHeaders(baseHeaders, headers, params.header));
|
|
25
|
-
const finalHeaders = mergeHeaders(serializedBody === void 0 || serializedBody instanceof FormData ? {} : { "Content-Type": "application/json" }, baseHeaders, headers, params.header);
|
|
26
|
-
const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
|
|
27
|
-
const requestInit = {
|
|
28
|
-
redirect: "follow",
|
|
29
|
-
...baseOptions,
|
|
30
|
-
...init,
|
|
31
|
-
body: serializedBody,
|
|
32
|
-
headers: finalHeaders
|
|
33
|
-
};
|
|
34
|
-
let id;
|
|
35
|
-
let options;
|
|
36
|
-
let request = new Request(createFinalURL(schemaPath, {
|
|
37
|
-
baseUrl: finalBaseUrl,
|
|
38
|
-
params,
|
|
39
|
-
querySerializer,
|
|
40
|
-
pathSerializer
|
|
41
|
-
}), requestInit);
|
|
42
|
-
let response;
|
|
43
|
-
for (const key in init) if (!(key in request)) request[key] = init[key];
|
|
44
|
-
if (finalMiddlewares.length) {
|
|
45
|
-
id = randomID();
|
|
46
|
-
options = Object.freeze({
|
|
47
|
-
baseUrl: finalBaseUrl,
|
|
48
|
-
fetch,
|
|
49
|
-
parseAs,
|
|
50
|
-
querySerializer,
|
|
51
|
-
bodySerializer,
|
|
52
|
-
pathSerializer
|
|
53
|
-
});
|
|
54
|
-
for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequest === "function") {
|
|
55
|
-
const result = await m.onRequest({
|
|
56
|
-
request,
|
|
57
|
-
schemaPath,
|
|
58
|
-
params,
|
|
59
|
-
options,
|
|
60
|
-
id
|
|
61
|
-
});
|
|
62
|
-
if (result) if (result instanceof Request) request = result;
|
|
63
|
-
else if (result instanceof Response) {
|
|
64
|
-
response = result;
|
|
65
|
-
break;
|
|
66
|
-
} else throw new Error("onRequest: must return new Request() or Response() when modifying the request");
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (!response) {
|
|
70
|
-
try {
|
|
71
|
-
response = await fetch(request, requestInitExt);
|
|
72
|
-
} catch (error2) {
|
|
73
|
-
let errorAfterMiddleware = error2;
|
|
74
|
-
if (finalMiddlewares.length) for (let i = finalMiddlewares.length - 1; i >= 0; i--) {
|
|
75
|
-
const m = finalMiddlewares[i];
|
|
76
|
-
if (m && typeof m === "object" && typeof m.onError === "function") {
|
|
77
|
-
const result = await m.onError({
|
|
78
|
-
request,
|
|
79
|
-
error: errorAfterMiddleware,
|
|
80
|
-
schemaPath,
|
|
81
|
-
params,
|
|
82
|
-
options,
|
|
83
|
-
id
|
|
84
|
-
});
|
|
85
|
-
if (result) {
|
|
86
|
-
if (result instanceof Response) {
|
|
87
|
-
errorAfterMiddleware = void 0;
|
|
88
|
-
response = result;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
if (result instanceof Error) {
|
|
92
|
-
errorAfterMiddleware = result;
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
throw new Error("onError: must return new Response() or instance of Error");
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (errorAfterMiddleware) throw errorAfterMiddleware;
|
|
100
|
-
}
|
|
101
|
-
if (finalMiddlewares.length) for (let i = finalMiddlewares.length - 1; i >= 0; i--) {
|
|
102
|
-
const m = finalMiddlewares[i];
|
|
103
|
-
if (m && typeof m === "object" && typeof m.onResponse === "function") {
|
|
104
|
-
const result = await m.onResponse({
|
|
105
|
-
request,
|
|
106
|
-
response,
|
|
107
|
-
schemaPath,
|
|
108
|
-
params,
|
|
109
|
-
options,
|
|
110
|
-
id
|
|
111
|
-
});
|
|
112
|
-
if (result) {
|
|
113
|
-
if (!(result instanceof Response)) throw new Error("onResponse: must return new Response() when modifying the response");
|
|
114
|
-
response = result;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const contentLength = response.headers.get("Content-Length");
|
|
120
|
-
if (response.status === 204 || request.method === "HEAD" || contentLength === "0" && !response.headers.get("Transfer-Encoding")?.includes("chunked")) return response.ok ? {
|
|
121
|
-
data: void 0,
|
|
122
|
-
response
|
|
123
|
-
} : {
|
|
124
|
-
error: void 0,
|
|
125
|
-
response
|
|
126
|
-
};
|
|
127
|
-
if (response.ok) {
|
|
128
|
-
const getResponseData = async () => {
|
|
129
|
-
if (parseAs === "stream") return response.body;
|
|
130
|
-
if (parseAs === "json" && !contentLength) {
|
|
131
|
-
const raw = await response.text();
|
|
132
|
-
return raw ? JSON.parse(raw) : void 0;
|
|
133
|
-
}
|
|
134
|
-
return await response[parseAs]();
|
|
135
|
-
};
|
|
136
|
-
return {
|
|
137
|
-
data: await getResponseData(),
|
|
138
|
-
response
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
let error = await response.text();
|
|
142
|
-
try {
|
|
143
|
-
error = JSON.parse(error);
|
|
144
|
-
} catch {}
|
|
145
|
-
return {
|
|
146
|
-
error,
|
|
147
|
-
response
|
|
148
|
-
};
|
|
149
105
|
}
|
|
106
|
+
const value = parsed.value;
|
|
107
|
+
if (!isExactRecord$1(value, ["error"]) || !isExactRecord$1(value.error, [
|
|
108
|
+
"code",
|
|
109
|
+
"message",
|
|
110
|
+
"requestId",
|
|
111
|
+
"details"
|
|
112
|
+
])) return new DriveError("invalid_response", {
|
|
113
|
+
status: response.status,
|
|
114
|
+
requestId: headerRequestId
|
|
115
|
+
});
|
|
116
|
+
const envelope = value.error;
|
|
117
|
+
if (typeof envelope.code !== "string" || !DRIVE_API_ERROR_CODES.includes(envelope.code) || envelope.message !== DRIVE_API_ERROR_MESSAGES[envelope.code] || !REQUEST_ID.test(String(envelope.requestId)) || envelope.requestId !== headerRequestId || !isExactRecord$1(envelope.details, []) || !errorStatusMatches(envelope.code, response.status, preconditionStatus, allowsQuotaExceeded) || parsed.text !== JSON.stringify(value)) return new DriveError("invalid_response", {
|
|
118
|
+
status: response.status,
|
|
119
|
+
requestId: headerRequestId
|
|
120
|
+
});
|
|
121
|
+
return new DriveError(envelope.code, {
|
|
122
|
+
status: response.status,
|
|
123
|
+
requestId: envelope.requestId
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function errorStatusMatches(code, status, preconditionStatus, allowsQuotaExceeded) {
|
|
127
|
+
if (code === "quota_exceeded" && !allowsQuotaExceeded) return false;
|
|
150
128
|
return {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
...init,
|
|
196
|
-
method: "PATCH"
|
|
197
|
-
});
|
|
198
|
-
},
|
|
199
|
-
TRACE(url, init) {
|
|
200
|
-
return coreFetch(url, {
|
|
201
|
-
...init,
|
|
202
|
-
method: "TRACE"
|
|
129
|
+
authentication_required: [401],
|
|
130
|
+
identity_authority_unavailable: [503],
|
|
131
|
+
permission_denied: [403],
|
|
132
|
+
resource_not_found: [404],
|
|
133
|
+
invalid_request: [422],
|
|
134
|
+
invalid_pagination_cursor: [422],
|
|
135
|
+
invalid_idempotency_key: [422],
|
|
136
|
+
precondition_failed: [preconditionStatus],
|
|
137
|
+
idempotency_conflict: [409],
|
|
138
|
+
quota_exceeded: [409],
|
|
139
|
+
service_unavailable: [503],
|
|
140
|
+
internal_error: [500]
|
|
141
|
+
}[code].includes(status);
|
|
142
|
+
}
|
|
143
|
+
async function parseBoundedJson(response, maximumBytes, status, requestId, signal) {
|
|
144
|
+
if (!response.body) throw new DriveError("invalid_response", {
|
|
145
|
+
status,
|
|
146
|
+
requestId
|
|
147
|
+
});
|
|
148
|
+
const reader = response.body.getReader();
|
|
149
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
150
|
+
let size = 0;
|
|
151
|
+
let chunks = 0;
|
|
152
|
+
let text = "";
|
|
153
|
+
const contentLength = response.headers.get("content-length");
|
|
154
|
+
if (contentLength !== null && (!/^(?:0|[1-9][0-9]*)$/.test(contentLength) || Number(contentLength) > maximumBytes)) {
|
|
155
|
+
reader.cancel().catch(() => {});
|
|
156
|
+
throw new DriveError("invalid_response", {
|
|
157
|
+
status,
|
|
158
|
+
requestId
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const deadline = new AbortController();
|
|
162
|
+
const timeout = setTimeout(() => deadline.abort(), RESPONSE_DEADLINE_MILLISECONDS);
|
|
163
|
+
try {
|
|
164
|
+
while (true) {
|
|
165
|
+
if (signal?.aborted) throw new DriveError("aborted");
|
|
166
|
+
const { done, value } = await readResponseChunk(reader, signal, deadline.signal);
|
|
167
|
+
if (done) break;
|
|
168
|
+
chunks += 1;
|
|
169
|
+
size += value.byteLength;
|
|
170
|
+
if (chunks > RESPONSE_CHUNK_LIMIT || size > maximumBytes) throw new DriveError("invalid_response", {
|
|
171
|
+
status,
|
|
172
|
+
requestId
|
|
203
173
|
});
|
|
204
|
-
|
|
205
|
-
use(...middleware) {
|
|
206
|
-
for (const m of middleware) {
|
|
207
|
-
if (!m) continue;
|
|
208
|
-
if (typeof m !== "object" || !("onRequest" in m || "onResponse" in m || "onError" in m)) throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");
|
|
209
|
-
globalMiddlewares.push(m);
|
|
210
|
-
}
|
|
211
|
-
},
|
|
212
|
-
eject(...middleware) {
|
|
213
|
-
for (const m of middleware) {
|
|
214
|
-
const i = globalMiddlewares.indexOf(m);
|
|
215
|
-
if (i !== -1) globalMiddlewares.splice(i, 1);
|
|
216
|
-
}
|
|
174
|
+
text += decoder.decode(value, { stream: true });
|
|
217
175
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const values = [];
|
|
228
|
-
const joiner = {
|
|
229
|
-
simple: ",",
|
|
230
|
-
label: ".",
|
|
231
|
-
matrix: ";"
|
|
232
|
-
}[options.style] || "&";
|
|
233
|
-
if (options.style !== "deepObject" && options.explode === false) {
|
|
234
|
-
for (const k in value) values.push(k, options.allowReserved === true ? value[k] : encodeURIComponent(value[k]));
|
|
235
|
-
const final2 = values.join(",");
|
|
236
|
-
switch (options.style) {
|
|
237
|
-
case "form": return `${name}=${final2}`;
|
|
238
|
-
case "label": return `.${final2}`;
|
|
239
|
-
case "matrix": return `;${name}=${final2}`;
|
|
240
|
-
default: return final2;
|
|
176
|
+
text += decoder.decode();
|
|
177
|
+
return {
|
|
178
|
+
value: JSON.parse(text),
|
|
179
|
+
text
|
|
180
|
+
};
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (error instanceof DriveError) {
|
|
183
|
+
if (error.code === "aborted" || signal?.aborted) throw new DriveError("aborted");
|
|
184
|
+
throw error;
|
|
241
185
|
}
|
|
186
|
+
throw new DriveError("invalid_response", {
|
|
187
|
+
status,
|
|
188
|
+
requestId
|
|
189
|
+
});
|
|
190
|
+
} finally {
|
|
191
|
+
clearTimeout(timeout);
|
|
192
|
+
reader.cancel().catch(() => {});
|
|
242
193
|
}
|
|
243
|
-
for (const k in value) {
|
|
244
|
-
const finalName = options.style === "deepObject" ? `${name}[${k}]` : k;
|
|
245
|
-
values.push(serializePrimitiveParam(finalName, value[k], options));
|
|
246
|
-
}
|
|
247
|
-
const final = values.join(joiner);
|
|
248
|
-
return options.style === "label" || options.style === "matrix" ? `${joiner}${final}` : final;
|
|
249
194
|
}
|
|
250
|
-
function
|
|
251
|
-
if (
|
|
252
|
-
if (
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
195
|
+
async function readResponseChunk(reader, operationSignal, deadlineSignal) {
|
|
196
|
+
if (operationSignal?.aborted) throw new DriveError("aborted");
|
|
197
|
+
if (deadlineSignal.aborted) throw new DriveError("invalid_response");
|
|
198
|
+
let removeOperationAbort = () => {};
|
|
199
|
+
let removeDeadlineAbort = () => {};
|
|
200
|
+
const operationAbort = new Promise((_, reject) => {
|
|
201
|
+
if (!operationSignal) return;
|
|
202
|
+
const onAbort = () => reject(new DriveError("aborted"));
|
|
203
|
+
operationSignal.addEventListener("abort", onAbort, { once: true });
|
|
204
|
+
removeOperationAbort = () => operationSignal.removeEventListener("abort", onAbort);
|
|
205
|
+
});
|
|
206
|
+
const deadlineAbort = new Promise((_, reject) => {
|
|
207
|
+
const onAbort = () => reject(new DriveError("invalid_response"));
|
|
208
|
+
deadlineSignal.addEventListener("abort", onAbort, { once: true });
|
|
209
|
+
removeDeadlineAbort = () => deadlineSignal.removeEventListener("abort", onAbort);
|
|
210
|
+
});
|
|
211
|
+
try {
|
|
212
|
+
return await Promise.race([
|
|
213
|
+
reader.read(),
|
|
214
|
+
operationAbort,
|
|
215
|
+
deadlineAbort
|
|
216
|
+
]);
|
|
217
|
+
} finally {
|
|
218
|
+
removeOperationAbort();
|
|
219
|
+
removeDeadlineAbort();
|
|
265
220
|
}
|
|
266
|
-
const joiner = {
|
|
267
|
-
simple: ",",
|
|
268
|
-
label: ".",
|
|
269
|
-
matrix: ";"
|
|
270
|
-
}[options.style] || "&";
|
|
271
|
-
const values = [];
|
|
272
|
-
for (const v of value) if (options.style === "simple" || options.style === "label") values.push(options.allowReserved === true ? v : encodeURIComponent(v));
|
|
273
|
-
else values.push(serializePrimitiveParam(name, v, options));
|
|
274
|
-
return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
|
|
275
221
|
}
|
|
276
|
-
function
|
|
277
|
-
|
|
278
|
-
const search = [];
|
|
279
|
-
if (queryParams && typeof queryParams === "object") for (const name in queryParams) {
|
|
280
|
-
const value = queryParams[name];
|
|
281
|
-
if (value === void 0 || value === null) continue;
|
|
282
|
-
if (Array.isArray(value)) {
|
|
283
|
-
if (value.length === 0) continue;
|
|
284
|
-
search.push(serializeArrayParam(name, value, {
|
|
285
|
-
style: "form",
|
|
286
|
-
explode: true,
|
|
287
|
-
...options?.array,
|
|
288
|
-
allowReserved: options?.allowReserved || false
|
|
289
|
-
}));
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (typeof value === "object") {
|
|
293
|
-
search.push(serializeObjectParam(name, value, {
|
|
294
|
-
style: "deepObject",
|
|
295
|
-
explode: true,
|
|
296
|
-
...options?.object,
|
|
297
|
-
allowReserved: options?.allowReserved || false
|
|
298
|
-
}));
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
search.push(serializePrimitiveParam(name, value, options));
|
|
302
|
-
}
|
|
303
|
-
return search.join("&");
|
|
304
|
-
};
|
|
222
|
+
function cancelResponse(response) {
|
|
223
|
+
response.body?.cancel().catch(() => {});
|
|
305
224
|
}
|
|
306
|
-
function
|
|
307
|
-
|
|
308
|
-
for (const match of pathname.match(PATH_PARAM_RE) ?? []) {
|
|
309
|
-
let name = match.substring(1, match.length - 1);
|
|
310
|
-
let explode = false;
|
|
311
|
-
let style = "simple";
|
|
312
|
-
if (name.endsWith("*")) {
|
|
313
|
-
explode = true;
|
|
314
|
-
name = name.substring(0, name.length - 1);
|
|
315
|
-
}
|
|
316
|
-
if (name.startsWith(".")) {
|
|
317
|
-
style = "label";
|
|
318
|
-
name = name.substring(1);
|
|
319
|
-
} else if (name.startsWith(";")) {
|
|
320
|
-
style = "matrix";
|
|
321
|
-
name = name.substring(1);
|
|
322
|
-
}
|
|
323
|
-
if (!pathParams || pathParams[name] === void 0 || pathParams[name] === null) continue;
|
|
324
|
-
const value = pathParams[name];
|
|
325
|
-
if (Array.isArray(value)) {
|
|
326
|
-
nextURL = nextURL.replace(match, serializeArrayParam(name, value, {
|
|
327
|
-
style,
|
|
328
|
-
explode
|
|
329
|
-
}));
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
if (typeof value === "object") {
|
|
333
|
-
nextURL = nextURL.replace(match, serializeObjectParam(name, value, {
|
|
334
|
-
style,
|
|
335
|
-
explode
|
|
336
|
-
}));
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
if (style === "matrix") {
|
|
340
|
-
nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);
|
|
341
|
-
continue;
|
|
342
|
-
}
|
|
343
|
-
nextURL = nextURL.replace(match, style === "label" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));
|
|
344
|
-
}
|
|
345
|
-
return nextURL;
|
|
346
|
-
}
|
|
347
|
-
function defaultBodySerializer(body, headers) {
|
|
348
|
-
if (body instanceof FormData) return body;
|
|
349
|
-
if (headers) {
|
|
350
|
-
if ((headers.get instanceof Function ? headers.get("Content-Type") ?? headers.get("content-type") : headers["Content-Type"] ?? headers["content-type"]) === "application/x-www-form-urlencoded") return new URLSearchParams(body).toString();
|
|
351
|
-
}
|
|
352
|
-
return JSON.stringify(body);
|
|
353
|
-
}
|
|
354
|
-
function createFinalURL(pathname, options) {
|
|
355
|
-
let finalURL = `${options.baseUrl}${pathname}`;
|
|
356
|
-
if (options.params?.path) finalURL = options.pathSerializer(finalURL, options.params.path);
|
|
357
|
-
let search = options.querySerializer(options.params.query ?? {});
|
|
358
|
-
if (search.startsWith("?")) search = search.substring(1);
|
|
359
|
-
if (search) finalURL += `?${search}`;
|
|
360
|
-
return finalURL;
|
|
361
|
-
}
|
|
362
|
-
function mergeHeaders(...allHeaders) {
|
|
363
|
-
const finalHeaders = new Headers();
|
|
364
|
-
for (const h of allHeaders) {
|
|
365
|
-
if (!h || typeof h !== "object") continue;
|
|
366
|
-
const iterator = h instanceof Headers ? h.entries() : Object.entries(h);
|
|
367
|
-
for (const [k, v] of iterator) if (v === null) finalHeaders.delete(k);
|
|
368
|
-
else if (Array.isArray(v)) for (const v2 of v) finalHeaders.append(k, v2);
|
|
369
|
-
else if (v !== void 0) finalHeaders.set(k, v);
|
|
370
|
-
}
|
|
371
|
-
return finalHeaders;
|
|
372
|
-
}
|
|
373
|
-
function removeTrailingSlash(url) {
|
|
374
|
-
if (url.endsWith("/")) return url.substring(0, url.length - 1);
|
|
375
|
-
return url;
|
|
376
|
-
}
|
|
377
|
-
String.fromCharCode;
|
|
378
|
-
const TRAILING_SLASH_RE = /\/$|\/\?|\/#/;
|
|
379
|
-
const JOIN_LEADING_SLASH_RE = /^\.?\//;
|
|
380
|
-
function hasTrailingSlash(input = "", respectQueryAndFragment) {
|
|
381
|
-
if (!respectQueryAndFragment) return input.endsWith("/");
|
|
382
|
-
return TRAILING_SLASH_RE.test(input);
|
|
383
|
-
}
|
|
384
|
-
function withTrailingSlash(input = "", respectQueryAndFragment) {
|
|
385
|
-
if (!respectQueryAndFragment) return input.endsWith("/") ? input : input + "/";
|
|
386
|
-
if (hasTrailingSlash(input, true)) return input || "/";
|
|
387
|
-
let path = input;
|
|
388
|
-
let fragment = "";
|
|
389
|
-
const fragmentIndex = input.indexOf("#");
|
|
390
|
-
if (fragmentIndex !== -1) {
|
|
391
|
-
path = input.slice(0, fragmentIndex);
|
|
392
|
-
fragment = input.slice(fragmentIndex);
|
|
393
|
-
if (!path) return fragment;
|
|
394
|
-
}
|
|
395
|
-
const [s0, ...s] = path.split("?");
|
|
396
|
-
return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
|
|
225
|
+
function safeRequestId(value) {
|
|
226
|
+
return value !== null && REQUEST_ID.test(value) ? value : null;
|
|
397
227
|
}
|
|
398
|
-
function
|
|
399
|
-
|
|
228
|
+
function readValidators(headers) {
|
|
229
|
+
const etag = headers.get("etag");
|
|
230
|
+
const permissionCollectionEtag = headers.get("drive-permission-collection-etag");
|
|
231
|
+
const permissionGrantEtag = headers.get("drive-permission-grant-etag");
|
|
232
|
+
return Object.freeze({
|
|
233
|
+
...etag !== null && LIST_ETAG$1.test(etag) ? { etag } : {},
|
|
234
|
+
...permissionCollectionEtag !== null && parseCollectionEtag(permissionCollectionEtag) !== void 0 ? { permissionCollectionEtag } : {},
|
|
235
|
+
...permissionGrantEtag !== null && parseGrantEtag(permissionGrantEtag) !== void 0 ? { permissionGrantEtag } : {}
|
|
236
|
+
});
|
|
400
237
|
}
|
|
401
|
-
function
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
const _segment = segment.replace(JOIN_LEADING_SLASH_RE, "");
|
|
405
|
-
url = withTrailingSlash(url) + _segment;
|
|
406
|
-
} else url = segment;
|
|
407
|
-
return url;
|
|
238
|
+
function isExactRecord$1(value, keys) {
|
|
239
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
240
|
+
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
408
241
|
}
|
|
409
242
|
//#endregion
|
|
410
|
-
//#region src/
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
"invalid_idempotency_key",
|
|
419
|
-
"precondition_failed",
|
|
420
|
-
"idempotency_conflict",
|
|
421
|
-
"quota_exceeded",
|
|
422
|
-
"service_unavailable",
|
|
423
|
-
"internal_error"
|
|
424
|
-
]);
|
|
425
|
-
const DRIVE_API_ERROR_MESSAGES = Object.freeze({
|
|
426
|
-
authentication_required: "Authentication is required.",
|
|
427
|
-
identity_authority_unavailable: "Authentication is temporarily unavailable.",
|
|
428
|
-
permission_denied: "The requested action is not permitted.",
|
|
429
|
-
resource_not_found: "The requested resource was not found.",
|
|
430
|
-
invalid_request: "The request is invalid.",
|
|
431
|
-
invalid_pagination_cursor: "The pagination cursor is invalid.",
|
|
432
|
-
invalid_idempotency_key: "The idempotency key is invalid.",
|
|
433
|
-
precondition_failed: "The request precondition failed.",
|
|
434
|
-
idempotency_conflict: "The idempotency key conflicts with an earlier request.",
|
|
435
|
-
quota_exceeded: "The workspace storage quota would be exceeded.",
|
|
436
|
-
service_unavailable: "The service is temporarily unavailable.",
|
|
437
|
-
internal_error: "The request could not be completed."
|
|
438
|
-
});
|
|
439
|
-
const SDK_MESSAGES = Object.freeze({
|
|
440
|
-
invalid_input: "The Drive SDK input is invalid.",
|
|
441
|
-
credential_unavailable: "A Drive credential could not be obtained.",
|
|
442
|
-
network_error: "The Drive request could not reach the service.",
|
|
443
|
-
timeout: "The Drive request timed out.",
|
|
444
|
-
aborted: "The Drive request was aborted.",
|
|
445
|
-
invalid_response: "Drive returned an invalid response."
|
|
446
|
-
});
|
|
447
|
-
var DriveError = class extends Error {
|
|
448
|
-
code;
|
|
449
|
-
status;
|
|
450
|
-
requestId;
|
|
451
|
-
details;
|
|
452
|
-
constructor(code, options = {}) {
|
|
453
|
-
super(code in DRIVE_API_ERROR_MESSAGES ? DRIVE_API_ERROR_MESSAGES[code] : SDK_MESSAGES[code]);
|
|
454
|
-
this.name = "DriveError";
|
|
455
|
-
this.code = code;
|
|
456
|
-
this.status = options.status ?? null;
|
|
457
|
-
this.requestId = options.requestId ?? null;
|
|
458
|
-
this.details = Object.freeze({});
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
//#endregion
|
|
462
|
-
//#region src/internal/client.ts
|
|
463
|
-
const ERROR_BODY_LIMIT = 16 * 1024;
|
|
464
|
-
const SUCCESS_BODY_LIMIT = 256 * 1024;
|
|
465
|
-
const RESPONSE_CHUNK_LIMIT = 256;
|
|
466
|
-
const RESPONSE_DEADLINE_MILLISECONDS = 5e3;
|
|
467
|
-
const DEFAULT_REQUEST_TIMEOUT_MILLISECONDS = 3e4;
|
|
468
|
-
const MAX_REQUEST_TIMEOUT_MILLISECONDS = 12e4;
|
|
469
|
-
const REQUEST_ID = /^[A-Za-z0-9_-]{16,128}$/;
|
|
470
|
-
const COLLECTION_ETAG = /^"drive\.permission-collection\.v1\.(0|[1-9][0-9]*)"$/;
|
|
243
|
+
//#region src/internal/client/guards.ts
|
|
244
|
+
const ITEM_ID$1 = /^drive\.item\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
245
|
+
const WORKSPACE_ID$1 = /^drive\.workspace\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
246
|
+
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}$/;
|
|
247
|
+
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}$/;
|
|
248
|
+
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}$/;
|
|
249
|
+
const CURSOR$1 = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
|
|
250
|
+
const AUTH_ID$1 = /^[A-Za-z0-9_-]{1,128}$/;
|
|
471
251
|
const GRANT_ETAG = /^"drive\.permission-grant\.v1\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)"$/;
|
|
472
252
|
const LIST_ETAG = /^"drive\.permission-list\.v1\.[0-9a-f]{64}"$/;
|
|
473
|
-
const
|
|
474
|
-
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}$/;
|
|
475
|
-
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}$/;
|
|
476
|
-
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}$/;
|
|
477
|
-
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}$/;
|
|
478
|
-
const CURSOR = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
|
|
479
|
-
const AUTH_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
480
|
-
const PERMISSION_ACTIONS = Object.freeze([
|
|
253
|
+
const PERMISSION_ACTIONS$1 = Object.freeze([
|
|
481
254
|
"items:content:read",
|
|
482
255
|
"items:create",
|
|
483
256
|
"items:delete",
|
|
@@ -494,281 +267,186 @@ const EFFECTIVE_ACTIONS = Object.freeze([
|
|
|
494
267
|
"items:permissions:read",
|
|
495
268
|
"items:update"
|
|
496
269
|
]);
|
|
497
|
-
const
|
|
498
|
-
const MAX_UPLOAD_BYTE_LENGTH = 33554432e4;
|
|
270
|
+
const MAX_UPLOAD_BYTE_LENGTH$1 = 33554432e4;
|
|
499
271
|
const UPLOAD_QUOTA_EXPIRY_MILLISECONDS = 864e5;
|
|
500
|
-
function
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
runtime = Object.freeze({
|
|
504
|
-
baseUrl: parseBaseUrl(config.baseUrl),
|
|
505
|
-
fetchImplementation: config.fetch ?? globalThis.fetch,
|
|
506
|
-
getCredential: config.getCredential,
|
|
507
|
-
timeoutMilliseconds: parseTimeoutMilliseconds(config.timeoutMilliseconds)
|
|
508
|
-
});
|
|
509
|
-
} catch {
|
|
510
|
-
throw new DriveError("invalid_input");
|
|
511
|
-
}
|
|
512
|
-
if (typeof runtime.fetchImplementation !== "function" || typeof runtime.getCredential !== "function") throw new DriveError("invalid_input");
|
|
513
|
-
return Object.freeze({
|
|
514
|
-
listFolderChildren: (input) => listFolderChildren(runtime, input),
|
|
515
|
-
createFolder: (input) => createFolder(runtime, input),
|
|
516
|
-
listItemPermissions: (input) => listItemPermissions(runtime, input),
|
|
517
|
-
readEffectiveItemPermissions: (input) => readEffectiveItemPermissions(runtime, input),
|
|
518
|
-
createItemPermission: (input) => createItemPermission(runtime, input),
|
|
519
|
-
updateItemPermission: (input) => updateItemPermission(runtime, input),
|
|
520
|
-
revokeItemPermission: (input) => revokeItemPermission(runtime, input),
|
|
521
|
-
createUpload: (input) => createUpload(runtime, input),
|
|
522
|
-
abortUpload: (input) => abortUpload(runtime, input)
|
|
523
|
-
});
|
|
272
|
+
function isFolderPage(value, workspaceId, parentItemId) {
|
|
273
|
+
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;
|
|
274
|
+
return value.items.every((item) => item.workspaceId === workspaceId && item.parentItemId === parentItemId) && isStrictlyOrdered(value.items, (item) => item.itemId);
|
|
524
275
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
276
|
+
function isFolderItem(value) {
|
|
277
|
+
return isExactRecord(value, [
|
|
278
|
+
"workspaceId",
|
|
279
|
+
"volumeId",
|
|
280
|
+
"itemId",
|
|
281
|
+
"parentItemId",
|
|
282
|
+
"kind",
|
|
283
|
+
"name",
|
|
284
|
+
"visibility",
|
|
285
|
+
"revision"
|
|
286
|
+
]) && 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);
|
|
534
287
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
288
|
+
function isPermissionPage(value, headers, targetItemId) {
|
|
289
|
+
if (!(isExactRecord(value, [
|
|
290
|
+
"items",
|
|
291
|
+
"nextCursor",
|
|
292
|
+
"collectionRevision",
|
|
293
|
+
"collectionEtag"
|
|
294
|
+
]) && Array.isArray(value.items) && value.items.length <= 50 && value.items.every(isPermissionGrant) && (value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length <= 699 && CURSOR$1.test(value.nextCursor)) && isSafeInteger$1(value.collectionRevision) && typeof value.collectionEtag === "string" && parseCollectionEtag(value.collectionEtag) === value.collectionRevision)) return false;
|
|
295
|
+
const collectionHeader = headers.get("drive-permission-collection-etag");
|
|
296
|
+
const representationEtag = headers.get("etag");
|
|
297
|
+
const collectionRevision = value.collectionRevision;
|
|
298
|
+
if (!isSafeInteger$1(collectionRevision)) return false;
|
|
299
|
+
return collectionHeader === value.collectionEtag && representationEtag !== null && LIST_ETAG.test(representationEtag) && value.items.every((grant) => (grant.source === "direct" ? grant.sourceItemId === targetItemId : grant.sourceItemId !== targetItemId) && grant.etag === permissionGrantEtag(collectionRevision, grant.revision)) && isStrictlyOrdered(value.items, (grant) => `${grant.sourceItemId}\0${grant.grantId}`);
|
|
547
300
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
301
|
+
function isPermissionMutation(value, targetItemId, expectedGrantId) {
|
|
302
|
+
if (!isExactRecord(value, [
|
|
303
|
+
"outcome",
|
|
304
|
+
"grant",
|
|
305
|
+
"collectionRevision"
|
|
306
|
+
]) || value.outcome !== "committed" && value.outcome !== "replayed" || !isSafeInteger$1(value.collectionRevision)) return false;
|
|
307
|
+
const grant = value.grant;
|
|
308
|
+
return isExactRecord(grant, [
|
|
309
|
+
"source",
|
|
310
|
+
"sourceItemId",
|
|
311
|
+
"grantId",
|
|
312
|
+
"grantee",
|
|
313
|
+
"actions",
|
|
314
|
+
"availability",
|
|
315
|
+
"expiresAtEpochMilliseconds",
|
|
316
|
+
"revision"
|
|
317
|
+
]) && grant.source === "direct" && typeof grant.sourceItemId === "string" && grant.sourceItemId === targetItemId && typeof grant.grantId === "string" && GRANT_ID$1.test(grant.grantId) && (expectedGrantId === void 0 || grant.grantId === expectedGrantId) && isGrantee(grant.grantee) && isPermissionActions(grant.actions) && [
|
|
318
|
+
"active",
|
|
319
|
+
"expired",
|
|
320
|
+
"revoked"
|
|
321
|
+
].includes(String(grant.availability)) && (grant.expiresAtEpochMilliseconds === null || isSafeInteger$1(grant.expiresAtEpochMilliseconds)) && isSafeInteger$1(grant.revision);
|
|
557
322
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
body: {
|
|
577
|
-
grantee: validated.grantee,
|
|
578
|
-
actions: validated.actions,
|
|
579
|
-
expiresAtEpochMilliseconds: validated.expiresAtEpochMilliseconds
|
|
580
|
-
}
|
|
581
|
-
}),
|
|
582
|
-
...requestOptions
|
|
583
|
-
}), [200, 201], (value, status, headers) => isPermissionMutation(value, validated.itemId) && (status === 201 && value.outcome === "committed" || status === 200 && value.outcome === "replayed") && (status === 200 || value.grant.availability !== "revoked") && mutationValidatorsAreCoherent(headers));
|
|
323
|
+
function isEffectivePermissionResponse(value, targetItemId) {
|
|
324
|
+
if (!isExactRecord(value, ["actions"]) || !Array.isArray(value.actions) || value.actions.length !== 7) return false;
|
|
325
|
+
for (let index = 0; index < value.actions.length; index += 1) {
|
|
326
|
+
const action = value.actions[index];
|
|
327
|
+
if (action === void 0 || !isExactRecord(action, [
|
|
328
|
+
"action",
|
|
329
|
+
"allowed",
|
|
330
|
+
"basis",
|
|
331
|
+
"sourceItemId",
|
|
332
|
+
"grantId"
|
|
333
|
+
]) || action.action !== EFFECTIVE_ACTIONS[index] || typeof action.allowed !== "boolean" || !(action.basis === null || [
|
|
334
|
+
"workspace_visibility",
|
|
335
|
+
"restricted_administrator_bypass",
|
|
336
|
+
"direct_grant",
|
|
337
|
+
"inherited_grant"
|
|
338
|
+
].includes(String(action.basis))) || !(action.sourceItemId === null || typeof action.sourceItemId === "string" && ITEM_ID$1.test(action.sourceItemId)) || !(action.grantId === null || typeof action.grantId === "string" && GRANT_ID$1.test(action.grantId)) || !effectiveSourceIsCoherent(action, targetItemId)) return false;
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
584
341
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
header: {
|
|
598
|
-
"Idempotency-Key": validated.idempotencyKey,
|
|
599
|
-
"If-Match": validated.ifMatch
|
|
600
|
-
}
|
|
601
|
-
},
|
|
602
|
-
body
|
|
603
|
-
}),
|
|
604
|
-
...requestOptions
|
|
605
|
-
}), [200], (value, _status, headers) => isPermissionMutation(value, validated.itemId, validated.grantId) && value.grant.availability !== "revoked" && mutationValidatorsAreCoherent(headers));
|
|
342
|
+
function isUploadQuotaReservation(value) {
|
|
343
|
+
return isExactRecord(value, [
|
|
344
|
+
"workspaceId",
|
|
345
|
+
"uploadId",
|
|
346
|
+
"parentItemId",
|
|
347
|
+
"expectedByteLength",
|
|
348
|
+
"state",
|
|
349
|
+
"terminalReason",
|
|
350
|
+
"createdAtEpochMilliseconds",
|
|
351
|
+
"expiresAtEpochMilliseconds",
|
|
352
|
+
"terminalAtEpochMilliseconds"
|
|
353
|
+
]) && typeof value.workspaceId === "string" && WORKSPACE_ID$1.test(value.workspaceId) && typeof value.uploadId === "string" && UPLOAD_ID$1.test(value.uploadId) && typeof value.parentItemId === "string" && ITEM_ID$1.test(value.parentItemId) && typeof value.expectedByteLength === "number" && Number.isSafeInteger(value.expectedByteLength) && value.expectedByteLength >= 0 && value.expectedByteLength <= MAX_UPLOAD_BYTE_LENGTH$1 && (value.state === "reserved" || value.state === "converted" || value.state === "released") && (value.terminalReason === null || value.terminalReason === "completed" || value.terminalReason === "aborted" || value.terminalReason === "failed" || value.terminalReason === "expired") && isSafeInteger$1(value.createdAtEpochMilliseconds) && isSafeInteger$1(value.expiresAtEpochMilliseconds) && value.expiresAtEpochMilliseconds - value.createdAtEpochMilliseconds === UPLOAD_QUOTA_EXPIRY_MILLISECONDS && (value.terminalAtEpochMilliseconds === null || isSafeInteger$1(value.terminalAtEpochMilliseconds) && value.terminalAtEpochMilliseconds >= value.createdAtEpochMilliseconds);
|
|
606
354
|
}
|
|
607
|
-
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
header: {
|
|
616
|
-
"Idempotency-Key": validated.idempotencyKey,
|
|
617
|
-
"If-Match": validated.ifMatch
|
|
618
|
-
}
|
|
619
|
-
} }),
|
|
620
|
-
...requestOptions
|
|
621
|
-
}), [200], (value, _status, headers) => isPermissionMutation(value, validated.itemId, validated.grantId) && value.grant.availability === "revoked" && parseCollectionEtag(headers.get("drive-permission-collection-etag") ?? "") !== void 0 && headers.get("drive-permission-grant-etag") === null);
|
|
355
|
+
function mutationValidatorsAreCoherent(headers) {
|
|
356
|
+
const collection = headers.get("drive-permission-collection-etag");
|
|
357
|
+
const grant = headers.get("drive-permission-grant-etag");
|
|
358
|
+
const collectionRevision = collection === null ? void 0 : parseCollectionEtag(collection);
|
|
359
|
+
if (collectionRevision === void 0) return false;
|
|
360
|
+
if (grant === null) return true;
|
|
361
|
+
const currentGrant = parseGrantEtag(grant);
|
|
362
|
+
return currentGrant !== void 0 && currentGrant[0] === collectionRevision;
|
|
622
363
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
364
|
+
function isPermissionGrant(value) {
|
|
365
|
+
return isExactRecord(value, [
|
|
366
|
+
"source",
|
|
367
|
+
"sourceItemId",
|
|
368
|
+
"grantId",
|
|
369
|
+
"grantee",
|
|
370
|
+
"actions",
|
|
371
|
+
"availability",
|
|
372
|
+
"expiresAtEpochMilliseconds",
|
|
373
|
+
"revision",
|
|
374
|
+
"etag"
|
|
375
|
+
]) && (value.source === "direct" || value.source === "inherited") && typeof value.sourceItemId === "string" && ITEM_ID$1.test(value.sourceItemId) && typeof value.grantId === "string" && GRANT_ID$1.test(value.grantId) && isGrantee(value.grantee) && isPermissionActions(value.actions) && [
|
|
376
|
+
"active",
|
|
377
|
+
"expired",
|
|
378
|
+
"revoked"
|
|
379
|
+
].includes(String(value.availability)) && (value.expiresAtEpochMilliseconds === null || isSafeInteger$1(value.expiresAtEpochMilliseconds)) && isSafeInteger$1(value.revision) && typeof value.etag === "string" && GRANT_ETAG.test(value.etag);
|
|
638
380
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.DELETE("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}", {
|
|
642
|
-
...operationOptions("abortUpload", { params: { path: {
|
|
643
|
-
workspaceId: validated.workspaceId,
|
|
644
|
-
uploadId: validated.uploadId
|
|
645
|
-
} } }),
|
|
646
|
-
...requestOptions
|
|
647
|
-
}), [200], (value) => isUploadQuotaReservation(value) && value.workspaceId === validated.workspaceId && value.uploadId === validated.uploadId && value.state === "released" && value.terminalReason === "aborted" && value.terminalAtEpochMilliseconds !== null);
|
|
381
|
+
function isGrantee(value) {
|
|
382
|
+
return isExactRecord(value, ["type", "userId"]) && value.type === "user" && typeof value.userId === "string" && AUTH_ID$1.test(value.userId) || isExactRecord(value, ["type", "teamId"]) && value.type === "team" && typeof value.teamId === "string" && AUTH_ID$1.test(value.teamId);
|
|
648
383
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
try {
|
|
652
|
-
const operationSignal = operation.signal;
|
|
653
|
-
throwIfAborted(operationSignal);
|
|
654
|
-
const credential = await obtainCredential(runtime.getCredential, operationSignal);
|
|
655
|
-
let capturedResponse;
|
|
656
|
-
await send(createClient({
|
|
657
|
-
baseUrl: runtime.baseUrl,
|
|
658
|
-
fetch: async (request) => {
|
|
659
|
-
try {
|
|
660
|
-
const response = await raceWithAbort(runtime.fetchImplementation(request), operationSignal);
|
|
661
|
-
if (!(response instanceof Response)) throw new DriveError("invalid_response");
|
|
662
|
-
capturedResponse = response;
|
|
663
|
-
} catch (error) {
|
|
664
|
-
if (error instanceof DriveError) throw error;
|
|
665
|
-
throw operationSignal.aborted ? new DriveError("aborted") : new DriveError("network_error");
|
|
666
|
-
}
|
|
667
|
-
return new Response(null, { status: 204 });
|
|
668
|
-
}
|
|
669
|
-
}), {
|
|
670
|
-
cache: "no-store",
|
|
671
|
-
credentials: "omit",
|
|
672
|
-
headers: new Headers({ authorization: `Bearer ${credential}` }),
|
|
673
|
-
signal: operationSignal
|
|
674
|
-
});
|
|
675
|
-
if (!capturedResponse) throw new DriveError("network_error");
|
|
676
|
-
const response = capturedResponse;
|
|
677
|
-
const requestId = safeRequestId(response.headers.get("x-request-id"));
|
|
678
|
-
if (requestId === null) {
|
|
679
|
-
cancelResponse(response);
|
|
680
|
-
throw new DriveError("invalid_response", { status: response.status });
|
|
681
|
-
}
|
|
682
|
-
if (!successStatuses.includes(response.status)) throw await normalizeError(response, requestId, operationSignal, preconditionStatus, allowsQuotaExceeded);
|
|
683
|
-
const { value } = await parseBoundedJson(response, SUCCESS_BODY_LIMIT, response.status, requestId, operationSignal);
|
|
684
|
-
const status = response.status;
|
|
685
|
-
if (!guard(value, status, response.headers)) throw new DriveError("invalid_response", {
|
|
686
|
-
status,
|
|
687
|
-
requestId
|
|
688
|
-
});
|
|
689
|
-
return Object.freeze({
|
|
690
|
-
data: value,
|
|
691
|
-
status,
|
|
692
|
-
requestId,
|
|
693
|
-
validators: readValidators(response.headers)
|
|
694
|
-
});
|
|
695
|
-
} catch (error) {
|
|
696
|
-
if (operation.didTimeout()) throw new DriveError("timeout");
|
|
697
|
-
if (error instanceof DriveError) throw error;
|
|
698
|
-
throw operation.signal.aborted ? new DriveError("aborted") : new DriveError("network_error");
|
|
699
|
-
} finally {
|
|
700
|
-
operation.dispose();
|
|
701
|
-
}
|
|
384
|
+
function isPermissionActions(value) {
|
|
385
|
+
return Array.isArray(value) && value.length >= 1 && value.length <= 6 && new Set(value).size === value.length && value.every((action) => PERMISSION_ACTIONS$1.includes(action)) && value.every((action, index) => index === 0 || PERMISSION_ACTIONS$1.indexOf(action) > PERMISSION_ACTIONS$1.indexOf(value[index - 1]));
|
|
702
386
|
}
|
|
703
|
-
function
|
|
704
|
-
if (
|
|
705
|
-
if (
|
|
706
|
-
return
|
|
387
|
+
function effectiveSourceIsCoherent(action, targetItemId) {
|
|
388
|
+
if (!action.allowed) return action.basis === null && action.sourceItemId === null && action.grantId === null;
|
|
389
|
+
if (action.basis === "workspace_visibility" || action.basis === "restricted_administrator_bypass") return action.sourceItemId === null && action.grantId === null;
|
|
390
|
+
if (action.basis === "direct_grant") return action.sourceItemId === targetItemId && typeof action.grantId === "string";
|
|
391
|
+
if (action.basis === "inherited_grant") return typeof action.sourceItemId === "string" && action.sourceItemId !== targetItemId && typeof action.grantId === "string";
|
|
392
|
+
return false;
|
|
707
393
|
}
|
|
708
|
-
function
|
|
709
|
-
|
|
710
|
-
let timedOut = false;
|
|
711
|
-
const onAbort = () => controller.abort();
|
|
712
|
-
if (callerSignal?.aborted) controller.abort();
|
|
713
|
-
else callerSignal?.addEventListener("abort", onAbort, { once: true });
|
|
714
|
-
const timeout = setTimeout(() => {
|
|
715
|
-
timedOut = true;
|
|
716
|
-
controller.abort();
|
|
717
|
-
}, timeoutMilliseconds);
|
|
718
|
-
return {
|
|
719
|
-
signal: controller.signal,
|
|
720
|
-
didTimeout: () => timedOut,
|
|
721
|
-
dispose: () => {
|
|
722
|
-
clearTimeout(timeout);
|
|
723
|
-
callerSignal?.removeEventListener("abort", onAbort);
|
|
724
|
-
}
|
|
725
|
-
};
|
|
394
|
+
function permissionGrantEtag(collectionRevision, grantRevision) {
|
|
395
|
+
return `"drive.permission-grant.v1.${collectionRevision}.${grantRevision}"`;
|
|
726
396
|
}
|
|
727
|
-
function
|
|
728
|
-
if (typeof value !== "string"
|
|
729
|
-
let
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
397
|
+
function isSafeFilename$1(value) {
|
|
398
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 510 || value.normalize("NFC") !== value || value.endsWith(".") || value.endsWith(" ") || filenameIsReserved$1(value)) return false;
|
|
399
|
+
let codePoints = 0;
|
|
400
|
+
let bytes = 0;
|
|
401
|
+
for (const character of value) {
|
|
402
|
+
const point = character.codePointAt(0);
|
|
403
|
+
if (point === void 0 || point === 47 || point === 92 || point <= 31 || point >= 127 && point <= 159 || point === 8232 || point === 8233 || point >= 55296 && point <= 57343) return false;
|
|
404
|
+
codePoints += 1;
|
|
405
|
+
bytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
406
|
+
if (codePoints > 255 || bytes > 255) return false;
|
|
734
407
|
}
|
|
735
|
-
|
|
736
|
-
"localhost",
|
|
737
|
-
"127.0.0.1",
|
|
738
|
-
"[::1]"
|
|
739
|
-
].includes(url.hostname);
|
|
740
|
-
if (url.protocol !== "https:" && !localHttp || url.username || url.password || url.search || url.hash || !url.host) throw new TypeError("Drive base URL is invalid");
|
|
741
|
-
return joinURL(url.origin, url.pathname);
|
|
408
|
+
return true;
|
|
742
409
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
410
|
+
function filenameIsReserved$1(value) {
|
|
411
|
+
const base = value.split(".", 1)[0].toUpperCase();
|
|
412
|
+
return value === "." || value === ".." || [
|
|
413
|
+
"CON",
|
|
414
|
+
"PRN",
|
|
415
|
+
"AUX",
|
|
416
|
+
"NUL",
|
|
417
|
+
"CLOCK$",
|
|
418
|
+
"CONIN$",
|
|
419
|
+
"CONOUT$"
|
|
420
|
+
].includes(base) || /^COM[1-9]$/.test(base) || /^LPT[1-9]$/.test(base);
|
|
754
421
|
}
|
|
755
|
-
function
|
|
756
|
-
|
|
422
|
+
function isStrictlyOrdered(values, key) {
|
|
423
|
+
return values.every((value, index) => index === 0 || key(values[index - 1]) < key(value));
|
|
757
424
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
765
|
-
});
|
|
766
|
-
try {
|
|
767
|
-
return await Promise.race([promise, aborted]);
|
|
768
|
-
} finally {
|
|
769
|
-
removeAbort();
|
|
770
|
-
}
|
|
425
|
+
function isSafeInteger$1(value) {
|
|
426
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
427
|
+
}
|
|
428
|
+
function isExactRecord(value, keys) {
|
|
429
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
430
|
+
return Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
771
431
|
}
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/internal/client/request.ts
|
|
434
|
+
const ITEM_ID = /^drive\.item\.[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
435
|
+
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}$/;
|
|
436
|
+
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}$/;
|
|
437
|
+
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}$/;
|
|
438
|
+
const CURSOR = /^drive\.cursor\.v1\.[A-Za-z0-9_-]+$/;
|
|
439
|
+
const AUTH_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
|
440
|
+
const PERMISSION_ACTIONS = Object.freeze([
|
|
441
|
+
"items:content:read",
|
|
442
|
+
"items:create",
|
|
443
|
+
"items:delete",
|
|
444
|
+
"items:metadata:read",
|
|
445
|
+
"items:permissions:read",
|
|
446
|
+
"items:update"
|
|
447
|
+
]);
|
|
448
|
+
const IDEMPOTENCY_KEY = /^[A-Za-z0-9_-]{16,128}$/;
|
|
449
|
+
const MAX_UPLOAD_BYTE_LENGTH = 33554432e4;
|
|
772
450
|
function validateResourceInput(value) {
|
|
773
451
|
const input = captureRecord(value, ["workspaceId", "itemId"], ["signal"]);
|
|
774
452
|
const workspaceId = input.workspaceId;
|
|
@@ -915,418 +593,803 @@ function validateCreateUploadInput(value) {
|
|
|
915
593
|
...signal === void 0 ? {} : { signal }
|
|
916
594
|
};
|
|
917
595
|
}
|
|
918
|
-
function validateAbortUploadInput(value) {
|
|
919
|
-
const input = captureRecord(value, ["workspaceId", "uploadId"], ["signal"]);
|
|
920
|
-
const signal = validateSignal(input.signal);
|
|
921
|
-
if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.uploadId !== "string" || !UPLOAD_ID.test(input.uploadId)) throw new DriveError("invalid_input");
|
|
922
|
-
return {
|
|
923
|
-
workspaceId: input.workspaceId,
|
|
924
|
-
uploadId: input.uploadId,
|
|
925
|
-
...signal === void 0 ? {} : { signal }
|
|
926
|
-
};
|
|
596
|
+
function validateAbortUploadInput(value) {
|
|
597
|
+
const input = captureRecord(value, ["workspaceId", "uploadId"], ["signal"]);
|
|
598
|
+
const signal = validateSignal(input.signal);
|
|
599
|
+
if (typeof input.workspaceId !== "string" || !WORKSPACE_ID.test(input.workspaceId) || typeof input.uploadId !== "string" || !UPLOAD_ID.test(input.uploadId)) throw new DriveError("invalid_input");
|
|
600
|
+
return {
|
|
601
|
+
workspaceId: input.workspaceId,
|
|
602
|
+
uploadId: input.uploadId,
|
|
603
|
+
...signal === void 0 ? {} : { signal }
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function resourcePath(input) {
|
|
607
|
+
return {
|
|
608
|
+
workspaceId: input.workspaceId,
|
|
609
|
+
itemId: input.itemId
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
function pageQuery(input) {
|
|
613
|
+
return {
|
|
614
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
615
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor }
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function operationOptions(_operationId, options) {
|
|
619
|
+
return options;
|
|
620
|
+
}
|
|
621
|
+
function captureRecord(value, required, optional) {
|
|
622
|
+
try {
|
|
623
|
+
if (typeof value !== "object" && typeof value !== "function" || value === null || Array.isArray(value)) throw new DriveError("invalid_input");
|
|
624
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
625
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
626
|
+
const allowed = new Set([...required, ...optional]);
|
|
627
|
+
if (keys.some((key) => typeof key !== "string" || !allowed.has(key)) || required.some((key) => !Object.hasOwn(descriptors, key))) throw new DriveError("invalid_input");
|
|
628
|
+
const result = {};
|
|
629
|
+
for (const key of keys) {
|
|
630
|
+
if (typeof key !== "string") throw new DriveError("invalid_input");
|
|
631
|
+
const descriptor = descriptors[key];
|
|
632
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) throw new DriveError("invalid_input");
|
|
633
|
+
result[key] = descriptor.value;
|
|
634
|
+
}
|
|
635
|
+
return result;
|
|
636
|
+
} catch (error) {
|
|
637
|
+
if (error instanceof DriveError) throw error;
|
|
638
|
+
throw new DriveError("invalid_input");
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
function validateSignal(value) {
|
|
642
|
+
if (value === void 0) return void 0;
|
|
643
|
+
if (!(value instanceof AbortSignal)) throw new DriveError("invalid_input");
|
|
644
|
+
return value;
|
|
645
|
+
}
|
|
646
|
+
function validateGrantee(value) {
|
|
647
|
+
const type = captureRecord(value, ["type"], ["userId", "teamId"]);
|
|
648
|
+
if (type.type === "user") {
|
|
649
|
+
const user = captureRecord(value, ["type", "userId"], []);
|
|
650
|
+
if (typeof user.userId === "string" && AUTH_ID.test(user.userId)) return {
|
|
651
|
+
type: "user",
|
|
652
|
+
userId: user.userId
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (type.type === "team") {
|
|
656
|
+
const team = captureRecord(value, ["type", "teamId"], []);
|
|
657
|
+
if (typeof team.teamId === "string" && AUTH_ID.test(team.teamId)) return {
|
|
658
|
+
type: "team",
|
|
659
|
+
teamId: team.teamId
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
throw new DriveError("invalid_input");
|
|
663
|
+
}
|
|
664
|
+
function validateInputActions(value) {
|
|
665
|
+
const actions = captureArray(value);
|
|
666
|
+
if (actions.length < 1 || actions.length > PERMISSION_ACTIONS.length || new Set(actions).size !== actions.length || !actions.every((action) => PERMISSION_ACTIONS.includes(action))) throw new DriveError("invalid_input");
|
|
667
|
+
return actions;
|
|
668
|
+
}
|
|
669
|
+
function captureArray(value) {
|
|
670
|
+
try {
|
|
671
|
+
if (!Array.isArray(value)) throw new DriveError("invalid_input");
|
|
672
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
673
|
+
if (Reflect.ownKeys(descriptors).some((key) => typeof key !== "string")) throw new DriveError("invalid_input");
|
|
674
|
+
const result = [];
|
|
675
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
676
|
+
const descriptor = descriptors[String(index)];
|
|
677
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) throw new DriveError("invalid_input");
|
|
678
|
+
result.push(descriptor.value);
|
|
679
|
+
}
|
|
680
|
+
if (Reflect.ownKeys(descriptors).length !== value.length + 1) throw new DriveError("invalid_input");
|
|
681
|
+
return result;
|
|
682
|
+
} catch (error) {
|
|
683
|
+
if (error instanceof DriveError) throw error;
|
|
684
|
+
throw new DriveError("invalid_input");
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
function isIdempotencyKey(value) {
|
|
688
|
+
return typeof value === "string" && IDEMPOTENCY_KEY.test(value);
|
|
689
|
+
}
|
|
690
|
+
function isExpiry(value) {
|
|
691
|
+
return value === null || isSafeInteger(value);
|
|
692
|
+
}
|
|
693
|
+
function isSafeFilename(value) {
|
|
694
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 510 || value.normalize("NFC") !== value || value.endsWith(".") || value.endsWith(" ") || filenameIsReserved(value)) return false;
|
|
695
|
+
let codePoints = 0;
|
|
696
|
+
let bytes = 0;
|
|
697
|
+
for (const character of value) {
|
|
698
|
+
const point = character.codePointAt(0);
|
|
699
|
+
if (point === void 0 || point === 47 || point === 92 || point <= 31 || point >= 127 && point <= 159 || point === 8232 || point === 8233 || point >= 55296 && point <= 57343) return false;
|
|
700
|
+
codePoints += 1;
|
|
701
|
+
bytes += point <= 127 ? 1 : point <= 2047 ? 2 : point <= 65535 ? 3 : 4;
|
|
702
|
+
if (codePoints > 255 || bytes > 255) return false;
|
|
703
|
+
}
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
function filenameIsReserved(value) {
|
|
707
|
+
const base = value.split(".", 1)[0].toUpperCase();
|
|
708
|
+
return value === "." || value === ".." || [
|
|
709
|
+
"CON",
|
|
710
|
+
"PRN",
|
|
711
|
+
"AUX",
|
|
712
|
+
"NUL",
|
|
713
|
+
"CLOCK$",
|
|
714
|
+
"CONIN$",
|
|
715
|
+
"CONOUT$"
|
|
716
|
+
].includes(base) || /^COM[1-9]$/.test(base) || /^LPT[1-9]$/.test(base);
|
|
717
|
+
}
|
|
718
|
+
function isSafeInteger(value) {
|
|
719
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
720
|
+
}
|
|
721
|
+
//#endregion
|
|
722
|
+
//#region ../../node_modules/.pnpm/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
|
|
723
|
+
const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
724
|
+
const supportsRequestInitExt = () => {
|
|
725
|
+
return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
|
|
726
|
+
};
|
|
727
|
+
function randomID() {
|
|
728
|
+
return Math.random().toString(36).slice(2, 11);
|
|
729
|
+
}
|
|
730
|
+
function createClient(clientOptions) {
|
|
731
|
+
let { baseUrl = "", Request: CustomRequest = globalThis.Request, fetch: baseFetch = globalThis.fetch, querySerializer: globalQuerySerializer, bodySerializer: globalBodySerializer, pathSerializer: globalPathSerializer, headers: baseHeaders, requestInitExt = void 0, ...baseOptions } = { ...clientOptions };
|
|
732
|
+
requestInitExt = supportsRequestInitExt() ? requestInitExt : void 0;
|
|
733
|
+
baseUrl = removeTrailingSlash(baseUrl);
|
|
734
|
+
const globalMiddlewares = [];
|
|
735
|
+
async function coreFetch(schemaPath, fetchOptions) {
|
|
736
|
+
const { baseUrl: localBaseUrl, fetch = baseFetch, Request = CustomRequest, headers, params = {}, parseAs = "json", querySerializer: requestQuerySerializer, bodySerializer = globalBodySerializer ?? defaultBodySerializer, pathSerializer: requestPathSerializer, body, middleware: requestMiddlewares = [], ...init } = fetchOptions || {};
|
|
737
|
+
let finalBaseUrl = baseUrl;
|
|
738
|
+
if (localBaseUrl) finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;
|
|
739
|
+
let querySerializer = typeof globalQuerySerializer === "function" ? globalQuerySerializer : createQuerySerializer(globalQuerySerializer);
|
|
740
|
+
if (requestQuerySerializer) querySerializer = typeof requestQuerySerializer === "function" ? requestQuerySerializer : createQuerySerializer({
|
|
741
|
+
...typeof globalQuerySerializer === "object" ? globalQuerySerializer : {},
|
|
742
|
+
...requestQuerySerializer
|
|
743
|
+
});
|
|
744
|
+
const pathSerializer = requestPathSerializer || globalPathSerializer || defaultPathSerializer;
|
|
745
|
+
const serializedBody = body === void 0 ? void 0 : bodySerializer(body, mergeHeaders(baseHeaders, headers, params.header));
|
|
746
|
+
const finalHeaders = mergeHeaders(serializedBody === void 0 || serializedBody instanceof FormData ? {} : { "Content-Type": "application/json" }, baseHeaders, headers, params.header);
|
|
747
|
+
const finalMiddlewares = [...globalMiddlewares, ...requestMiddlewares];
|
|
748
|
+
const requestInit = {
|
|
749
|
+
redirect: "follow",
|
|
750
|
+
...baseOptions,
|
|
751
|
+
...init,
|
|
752
|
+
body: serializedBody,
|
|
753
|
+
headers: finalHeaders
|
|
754
|
+
};
|
|
755
|
+
let id;
|
|
756
|
+
let options;
|
|
757
|
+
let request = new Request(createFinalURL(schemaPath, {
|
|
758
|
+
baseUrl: finalBaseUrl,
|
|
759
|
+
params,
|
|
760
|
+
querySerializer,
|
|
761
|
+
pathSerializer
|
|
762
|
+
}), requestInit);
|
|
763
|
+
let response;
|
|
764
|
+
for (const key in init) if (!(key in request)) request[key] = init[key];
|
|
765
|
+
if (finalMiddlewares.length) {
|
|
766
|
+
id = randomID();
|
|
767
|
+
options = Object.freeze({
|
|
768
|
+
baseUrl: finalBaseUrl,
|
|
769
|
+
fetch,
|
|
770
|
+
parseAs,
|
|
771
|
+
querySerializer,
|
|
772
|
+
bodySerializer,
|
|
773
|
+
pathSerializer
|
|
774
|
+
});
|
|
775
|
+
for (const m of finalMiddlewares) if (m && typeof m === "object" && typeof m.onRequest === "function") {
|
|
776
|
+
const result = await m.onRequest({
|
|
777
|
+
request,
|
|
778
|
+
schemaPath,
|
|
779
|
+
params,
|
|
780
|
+
options,
|
|
781
|
+
id
|
|
782
|
+
});
|
|
783
|
+
if (result) if (result instanceof Request) request = result;
|
|
784
|
+
else if (result instanceof Response) {
|
|
785
|
+
response = result;
|
|
786
|
+
break;
|
|
787
|
+
} else throw new Error("onRequest: must return new Request() or Response() when modifying the request");
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (!response) {
|
|
791
|
+
try {
|
|
792
|
+
response = await fetch(request, requestInitExt);
|
|
793
|
+
} catch (error2) {
|
|
794
|
+
let errorAfterMiddleware = error2;
|
|
795
|
+
if (finalMiddlewares.length) for (let i = finalMiddlewares.length - 1; i >= 0; i--) {
|
|
796
|
+
const m = finalMiddlewares[i];
|
|
797
|
+
if (m && typeof m === "object" && typeof m.onError === "function") {
|
|
798
|
+
const result = await m.onError({
|
|
799
|
+
request,
|
|
800
|
+
error: errorAfterMiddleware,
|
|
801
|
+
schemaPath,
|
|
802
|
+
params,
|
|
803
|
+
options,
|
|
804
|
+
id
|
|
805
|
+
});
|
|
806
|
+
if (result) {
|
|
807
|
+
if (result instanceof Response) {
|
|
808
|
+
errorAfterMiddleware = void 0;
|
|
809
|
+
response = result;
|
|
810
|
+
break;
|
|
811
|
+
}
|
|
812
|
+
if (result instanceof Error) {
|
|
813
|
+
errorAfterMiddleware = result;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
throw new Error("onError: must return new Response() or instance of Error");
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
if (errorAfterMiddleware) throw errorAfterMiddleware;
|
|
821
|
+
}
|
|
822
|
+
if (finalMiddlewares.length) for (let i = finalMiddlewares.length - 1; i >= 0; i--) {
|
|
823
|
+
const m = finalMiddlewares[i];
|
|
824
|
+
if (m && typeof m === "object" && typeof m.onResponse === "function") {
|
|
825
|
+
const result = await m.onResponse({
|
|
826
|
+
request,
|
|
827
|
+
response,
|
|
828
|
+
schemaPath,
|
|
829
|
+
params,
|
|
830
|
+
options,
|
|
831
|
+
id
|
|
832
|
+
});
|
|
833
|
+
if (result) {
|
|
834
|
+
if (!(result instanceof Response)) throw new Error("onResponse: must return new Response() when modifying the response");
|
|
835
|
+
response = result;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
const contentLength = response.headers.get("Content-Length");
|
|
841
|
+
if (response.status === 204 || request.method === "HEAD" || contentLength === "0" && !response.headers.get("Transfer-Encoding")?.includes("chunked")) return response.ok ? {
|
|
842
|
+
data: void 0,
|
|
843
|
+
response
|
|
844
|
+
} : {
|
|
845
|
+
error: void 0,
|
|
846
|
+
response
|
|
847
|
+
};
|
|
848
|
+
if (response.ok) {
|
|
849
|
+
const getResponseData = async () => {
|
|
850
|
+
if (parseAs === "stream") return response.body;
|
|
851
|
+
if (parseAs === "json" && !contentLength) {
|
|
852
|
+
const raw = await response.text();
|
|
853
|
+
return raw ? JSON.parse(raw) : void 0;
|
|
854
|
+
}
|
|
855
|
+
return await response[parseAs]();
|
|
856
|
+
};
|
|
857
|
+
return {
|
|
858
|
+
data: await getResponseData(),
|
|
859
|
+
response
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
let error = await response.text();
|
|
863
|
+
try {
|
|
864
|
+
error = JSON.parse(error);
|
|
865
|
+
} catch {}
|
|
866
|
+
return {
|
|
867
|
+
error,
|
|
868
|
+
response
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
return {
|
|
872
|
+
request(method, url, init) {
|
|
873
|
+
return coreFetch(url, {
|
|
874
|
+
...init,
|
|
875
|
+
method: method.toUpperCase()
|
|
876
|
+
});
|
|
877
|
+
},
|
|
878
|
+
GET(url, init) {
|
|
879
|
+
return coreFetch(url, {
|
|
880
|
+
...init,
|
|
881
|
+
method: "GET"
|
|
882
|
+
});
|
|
883
|
+
},
|
|
884
|
+
PUT(url, init) {
|
|
885
|
+
return coreFetch(url, {
|
|
886
|
+
...init,
|
|
887
|
+
method: "PUT"
|
|
888
|
+
});
|
|
889
|
+
},
|
|
890
|
+
POST(url, init) {
|
|
891
|
+
return coreFetch(url, {
|
|
892
|
+
...init,
|
|
893
|
+
method: "POST"
|
|
894
|
+
});
|
|
895
|
+
},
|
|
896
|
+
DELETE(url, init) {
|
|
897
|
+
return coreFetch(url, {
|
|
898
|
+
...init,
|
|
899
|
+
method: "DELETE"
|
|
900
|
+
});
|
|
901
|
+
},
|
|
902
|
+
OPTIONS(url, init) {
|
|
903
|
+
return coreFetch(url, {
|
|
904
|
+
...init,
|
|
905
|
+
method: "OPTIONS"
|
|
906
|
+
});
|
|
907
|
+
},
|
|
908
|
+
HEAD(url, init) {
|
|
909
|
+
return coreFetch(url, {
|
|
910
|
+
...init,
|
|
911
|
+
method: "HEAD"
|
|
912
|
+
});
|
|
913
|
+
},
|
|
914
|
+
PATCH(url, init) {
|
|
915
|
+
return coreFetch(url, {
|
|
916
|
+
...init,
|
|
917
|
+
method: "PATCH"
|
|
918
|
+
});
|
|
919
|
+
},
|
|
920
|
+
TRACE(url, init) {
|
|
921
|
+
return coreFetch(url, {
|
|
922
|
+
...init,
|
|
923
|
+
method: "TRACE"
|
|
924
|
+
});
|
|
925
|
+
},
|
|
926
|
+
use(...middleware) {
|
|
927
|
+
for (const m of middleware) {
|
|
928
|
+
if (!m) continue;
|
|
929
|
+
if (typeof m !== "object" || !("onRequest" in m || "onResponse" in m || "onError" in m)) throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");
|
|
930
|
+
globalMiddlewares.push(m);
|
|
931
|
+
}
|
|
932
|
+
},
|
|
933
|
+
eject(...middleware) {
|
|
934
|
+
for (const m of middleware) {
|
|
935
|
+
const i = globalMiddlewares.indexOf(m);
|
|
936
|
+
if (i !== -1) globalMiddlewares.splice(i, 1);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
function serializePrimitiveParam(name, value, options) {
|
|
942
|
+
if (value === void 0 || value === null) return "";
|
|
943
|
+
if (typeof value === "object") throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
|
|
944
|
+
return `${name}=${options?.allowReserved === true ? value : encodeURIComponent(value)}`;
|
|
927
945
|
}
|
|
928
|
-
function
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
946
|
+
function serializeObjectParam(name, value, options) {
|
|
947
|
+
if (!value || typeof value !== "object") return "";
|
|
948
|
+
const values = [];
|
|
949
|
+
const joiner = {
|
|
950
|
+
simple: ",",
|
|
951
|
+
label: ".",
|
|
952
|
+
matrix: ";"
|
|
953
|
+
}[options.style] || "&";
|
|
954
|
+
if (options.style !== "deepObject" && options.explode === false) {
|
|
955
|
+
for (const k in value) values.push(k, options.allowReserved === true ? value[k] : encodeURIComponent(value[k]));
|
|
956
|
+
const final2 = values.join(",");
|
|
957
|
+
switch (options.style) {
|
|
958
|
+
case "form": return `${name}=${final2}`;
|
|
959
|
+
case "label": return `.${final2}`;
|
|
960
|
+
case "matrix": return `;${name}=${final2}`;
|
|
961
|
+
default: return final2;
|
|
941
962
|
}
|
|
942
|
-
return result;
|
|
943
|
-
} catch (error) {
|
|
944
|
-
if (error instanceof DriveError) throw error;
|
|
945
|
-
throw new DriveError("invalid_input");
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
function validateSignal(value) {
|
|
949
|
-
if (value === void 0) return void 0;
|
|
950
|
-
if (!(value instanceof AbortSignal)) throw new DriveError("invalid_input");
|
|
951
|
-
return value;
|
|
952
|
-
}
|
|
953
|
-
function validateGrantee(value) {
|
|
954
|
-
const type = captureRecord(value, ["type"], ["userId", "teamId"]);
|
|
955
|
-
if (type.type === "user") {
|
|
956
|
-
const user = captureRecord(value, ["type", "userId"], []);
|
|
957
|
-
if (typeof user.userId === "string" && AUTH_ID.test(user.userId)) return {
|
|
958
|
-
type: "user",
|
|
959
|
-
userId: user.userId
|
|
960
|
-
};
|
|
961
963
|
}
|
|
962
|
-
|
|
963
|
-
const
|
|
964
|
-
|
|
965
|
-
type: "team",
|
|
966
|
-
teamId: team.teamId
|
|
967
|
-
};
|
|
964
|
+
for (const k in value) {
|
|
965
|
+
const finalName = options.style === "deepObject" ? `${name}[${k}]` : k;
|
|
966
|
+
values.push(serializePrimitiveParam(finalName, value[k], options));
|
|
968
967
|
}
|
|
969
|
-
|
|
970
|
-
}
|
|
971
|
-
function validateInputActions(value) {
|
|
972
|
-
const actions = captureArray(value);
|
|
973
|
-
if (actions.length < 1 || actions.length > PERMISSION_ACTIONS.length || new Set(actions).size !== actions.length || !actions.every((action) => PERMISSION_ACTIONS.includes(action))) throw new DriveError("invalid_input");
|
|
974
|
-
return actions;
|
|
968
|
+
const final = values.join(joiner);
|
|
969
|
+
return options.style === "label" || options.style === "matrix" ? `${joiner}${final}` : final;
|
|
975
970
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
const
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
971
|
+
function serializeArrayParam(name, value, options) {
|
|
972
|
+
if (!Array.isArray(value)) return "";
|
|
973
|
+
if (options.explode === false) {
|
|
974
|
+
const joiner2 = {
|
|
975
|
+
form: ",",
|
|
976
|
+
spaceDelimited: "%20",
|
|
977
|
+
pipeDelimited: "|"
|
|
978
|
+
}[options.style] || ",";
|
|
979
|
+
const final = (options.allowReserved === true ? value : value.map((v) => encodeURIComponent(v))).join(joiner2);
|
|
980
|
+
switch (options.style) {
|
|
981
|
+
case "simple": return final;
|
|
982
|
+
case "label": return `.${final}`;
|
|
983
|
+
case "matrix": return `;${name}=${final}`;
|
|
984
|
+
default: return `${name}=${final}`;
|
|
986
985
|
}
|
|
987
|
-
if (Reflect.ownKeys(descriptors).length !== value.length + 1) throw new DriveError("invalid_input");
|
|
988
|
-
return result;
|
|
989
|
-
} catch (error) {
|
|
990
|
-
if (error instanceof DriveError) throw error;
|
|
991
|
-
throw new DriveError("invalid_input");
|
|
992
986
|
}
|
|
987
|
+
const joiner = {
|
|
988
|
+
simple: ",",
|
|
989
|
+
label: ".",
|
|
990
|
+
matrix: ";"
|
|
991
|
+
}[options.style] || "&";
|
|
992
|
+
const values = [];
|
|
993
|
+
for (const v of value) if (options.style === "simple" || options.style === "label") values.push(options.allowReserved === true ? v : encodeURIComponent(v));
|
|
994
|
+
else values.push(serializePrimitiveParam(name, v, options));
|
|
995
|
+
return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
|
|
993
996
|
}
|
|
994
|
-
function
|
|
995
|
-
return
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
997
|
+
function createQuerySerializer(options) {
|
|
998
|
+
return function querySerializer(queryParams) {
|
|
999
|
+
const search = [];
|
|
1000
|
+
if (queryParams && typeof queryParams === "object") for (const name in queryParams) {
|
|
1001
|
+
const value = queryParams[name];
|
|
1002
|
+
if (value === void 0 || value === null) continue;
|
|
1003
|
+
if (Array.isArray(value)) {
|
|
1004
|
+
if (value.length === 0) continue;
|
|
1005
|
+
search.push(serializeArrayParam(name, value, {
|
|
1006
|
+
style: "form",
|
|
1007
|
+
explode: true,
|
|
1008
|
+
...options?.array,
|
|
1009
|
+
allowReserved: options?.allowReserved || false
|
|
1010
|
+
}));
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (typeof value === "object") {
|
|
1014
|
+
search.push(serializeObjectParam(name, value, {
|
|
1015
|
+
style: "deepObject",
|
|
1016
|
+
explode: true,
|
|
1017
|
+
...options?.object,
|
|
1018
|
+
allowReserved: options?.allowReserved || false
|
|
1019
|
+
}));
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
search.push(serializePrimitiveParam(name, value, options));
|
|
1023
|
+
}
|
|
1024
|
+
return search.join("&");
|
|
1010
1025
|
};
|
|
1011
1026
|
}
|
|
1012
|
-
function
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
"code",
|
|
1029
|
-
"message",
|
|
1030
|
-
"requestId",
|
|
1031
|
-
"details"
|
|
1032
|
-
])) return new DriveError("invalid_response", {
|
|
1033
|
-
status: response.status,
|
|
1034
|
-
requestId: headerRequestId
|
|
1035
|
-
});
|
|
1036
|
-
const envelope = value.error;
|
|
1037
|
-
if (typeof envelope.code !== "string" || !DRIVE_API_ERROR_CODES.includes(envelope.code) || envelope.message !== DRIVE_API_ERROR_MESSAGES[envelope.code] || !REQUEST_ID.test(String(envelope.requestId)) || envelope.requestId !== headerRequestId || !isExactRecord(envelope.details, []) || !errorStatusMatches(envelope.code, response.status, preconditionStatus, allowsQuotaExceeded) || parsed.text !== JSON.stringify(value)) return new DriveError("invalid_response", {
|
|
1038
|
-
status: response.status,
|
|
1039
|
-
requestId: headerRequestId
|
|
1040
|
-
});
|
|
1041
|
-
return new DriveError(envelope.code, {
|
|
1042
|
-
status: response.status,
|
|
1043
|
-
requestId: envelope.requestId
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
function errorStatusMatches(code, status, preconditionStatus, allowsQuotaExceeded) {
|
|
1047
|
-
if (code === "quota_exceeded" && !allowsQuotaExceeded) return false;
|
|
1048
|
-
return {
|
|
1049
|
-
authentication_required: [401],
|
|
1050
|
-
identity_authority_unavailable: [503],
|
|
1051
|
-
permission_denied: [403],
|
|
1052
|
-
resource_not_found: [404],
|
|
1053
|
-
invalid_request: [422],
|
|
1054
|
-
invalid_pagination_cursor: [422],
|
|
1055
|
-
invalid_idempotency_key: [422],
|
|
1056
|
-
precondition_failed: [preconditionStatus],
|
|
1057
|
-
idempotency_conflict: [409],
|
|
1058
|
-
quota_exceeded: [409],
|
|
1059
|
-
service_unavailable: [503],
|
|
1060
|
-
internal_error: [500]
|
|
1061
|
-
}[code].includes(status);
|
|
1062
|
-
}
|
|
1063
|
-
async function parseBoundedJson(response, maximumBytes, status, requestId, signal) {
|
|
1064
|
-
if (!response.body) throw new DriveError("invalid_response", {
|
|
1065
|
-
status,
|
|
1066
|
-
requestId
|
|
1067
|
-
});
|
|
1068
|
-
const reader = response.body.getReader();
|
|
1069
|
-
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
1070
|
-
let size = 0;
|
|
1071
|
-
let chunks = 0;
|
|
1072
|
-
let text = "";
|
|
1073
|
-
const contentLength = response.headers.get("content-length");
|
|
1074
|
-
if (contentLength !== null && (!/^(?:0|[1-9][0-9]*)$/.test(contentLength) || Number(contentLength) > maximumBytes)) {
|
|
1075
|
-
reader.cancel().catch(() => {});
|
|
1076
|
-
throw new DriveError("invalid_response", {
|
|
1077
|
-
status,
|
|
1078
|
-
requestId
|
|
1079
|
-
});
|
|
1080
|
-
}
|
|
1081
|
-
const deadline = new AbortController();
|
|
1082
|
-
const timeout = setTimeout(() => deadline.abort(), RESPONSE_DEADLINE_MILLISECONDS);
|
|
1083
|
-
try {
|
|
1084
|
-
while (true) {
|
|
1085
|
-
if (signal?.aborted) throw new DriveError("aborted");
|
|
1086
|
-
const { done, value } = await readResponseChunk(reader, signal, deadline.signal);
|
|
1087
|
-
if (done) break;
|
|
1088
|
-
chunks += 1;
|
|
1089
|
-
size += value.byteLength;
|
|
1090
|
-
if (chunks > RESPONSE_CHUNK_LIMIT || size > maximumBytes) throw new DriveError("invalid_response", {
|
|
1091
|
-
status,
|
|
1092
|
-
requestId
|
|
1093
|
-
});
|
|
1094
|
-
text += decoder.decode(value, { stream: true });
|
|
1027
|
+
function defaultPathSerializer(pathname, pathParams) {
|
|
1028
|
+
let nextURL = pathname;
|
|
1029
|
+
for (const match of pathname.match(PATH_PARAM_RE) ?? []) {
|
|
1030
|
+
let name = match.substring(1, match.length - 1);
|
|
1031
|
+
let explode = false;
|
|
1032
|
+
let style = "simple";
|
|
1033
|
+
if (name.endsWith("*")) {
|
|
1034
|
+
explode = true;
|
|
1035
|
+
name = name.substring(0, name.length - 1);
|
|
1036
|
+
}
|
|
1037
|
+
if (name.startsWith(".")) {
|
|
1038
|
+
style = "label";
|
|
1039
|
+
name = name.substring(1);
|
|
1040
|
+
} else if (name.startsWith(";")) {
|
|
1041
|
+
style = "matrix";
|
|
1042
|
+
name = name.substring(1);
|
|
1095
1043
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
throw error;
|
|
1044
|
+
if (!pathParams || pathParams[name] === void 0 || pathParams[name] === null) continue;
|
|
1045
|
+
const value = pathParams[name];
|
|
1046
|
+
if (Array.isArray(value)) {
|
|
1047
|
+
nextURL = nextURL.replace(match, serializeArrayParam(name, value, {
|
|
1048
|
+
style,
|
|
1049
|
+
explode
|
|
1050
|
+
}));
|
|
1051
|
+
continue;
|
|
1105
1052
|
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1053
|
+
if (typeof value === "object") {
|
|
1054
|
+
nextURL = nextURL.replace(match, serializeObjectParam(name, value, {
|
|
1055
|
+
style,
|
|
1056
|
+
explode
|
|
1057
|
+
}));
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
if (style === "matrix") {
|
|
1061
|
+
nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
nextURL = nextURL.replace(match, style === "label" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));
|
|
1113
1065
|
}
|
|
1066
|
+
return nextURL;
|
|
1114
1067
|
}
|
|
1115
|
-
|
|
1116
|
-
if (
|
|
1117
|
-
if (
|
|
1118
|
-
|
|
1119
|
-
let removeDeadlineAbort = () => {};
|
|
1120
|
-
const operationAbort = new Promise((_, reject) => {
|
|
1121
|
-
if (!operationSignal) return;
|
|
1122
|
-
const onAbort = () => reject(new DriveError("aborted"));
|
|
1123
|
-
operationSignal.addEventListener("abort", onAbort, { once: true });
|
|
1124
|
-
removeOperationAbort = () => operationSignal.removeEventListener("abort", onAbort);
|
|
1125
|
-
});
|
|
1126
|
-
const deadlineAbort = new Promise((_, reject) => {
|
|
1127
|
-
const onAbort = () => reject(new DriveError("invalid_response"));
|
|
1128
|
-
deadlineSignal.addEventListener("abort", onAbort, { once: true });
|
|
1129
|
-
removeDeadlineAbort = () => deadlineSignal.removeEventListener("abort", onAbort);
|
|
1130
|
-
});
|
|
1131
|
-
try {
|
|
1132
|
-
return await Promise.race([
|
|
1133
|
-
reader.read(),
|
|
1134
|
-
operationAbort,
|
|
1135
|
-
deadlineAbort
|
|
1136
|
-
]);
|
|
1137
|
-
} finally {
|
|
1138
|
-
removeOperationAbort();
|
|
1139
|
-
removeDeadlineAbort();
|
|
1068
|
+
function defaultBodySerializer(body, headers) {
|
|
1069
|
+
if (body instanceof FormData) return body;
|
|
1070
|
+
if (headers) {
|
|
1071
|
+
if ((headers.get instanceof Function ? headers.get("Content-Type") ?? headers.get("content-type") : headers["Content-Type"] ?? headers["content-type"]) === "application/x-www-form-urlencoded") return new URLSearchParams(body).toString();
|
|
1140
1072
|
}
|
|
1073
|
+
return JSON.stringify(body);
|
|
1141
1074
|
}
|
|
1142
|
-
function
|
|
1143
|
-
|
|
1075
|
+
function createFinalURL(pathname, options) {
|
|
1076
|
+
let finalURL = `${options.baseUrl}${pathname}`;
|
|
1077
|
+
if (options.params?.path) finalURL = options.pathSerializer(finalURL, options.params.path);
|
|
1078
|
+
let search = options.querySerializer(options.params.query ?? {});
|
|
1079
|
+
if (search.startsWith("?")) search = search.substring(1);
|
|
1080
|
+
if (search) finalURL += `?${search}`;
|
|
1081
|
+
return finalURL;
|
|
1144
1082
|
}
|
|
1145
|
-
function
|
|
1146
|
-
|
|
1083
|
+
function mergeHeaders(...allHeaders) {
|
|
1084
|
+
const finalHeaders = new Headers();
|
|
1085
|
+
for (const h of allHeaders) {
|
|
1086
|
+
if (!h || typeof h !== "object") continue;
|
|
1087
|
+
const iterator = h instanceof Headers ? h.entries() : Object.entries(h);
|
|
1088
|
+
for (const [k, v] of iterator) if (v === null) finalHeaders.delete(k);
|
|
1089
|
+
else if (Array.isArray(v)) for (const v2 of v) finalHeaders.append(k, v2);
|
|
1090
|
+
else if (v !== void 0) finalHeaders.set(k, v);
|
|
1091
|
+
}
|
|
1092
|
+
return finalHeaders;
|
|
1147
1093
|
}
|
|
1148
|
-
function
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
const permissionGrantEtag = headers.get("drive-permission-grant-etag");
|
|
1152
|
-
return Object.freeze({
|
|
1153
|
-
...etag !== null && LIST_ETAG.test(etag) ? { etag } : {},
|
|
1154
|
-
...permissionCollectionEtag !== null && parseCollectionEtag(permissionCollectionEtag) !== void 0 ? { permissionCollectionEtag } : {},
|
|
1155
|
-
...permissionGrantEtag !== null && parseGrantEtag(permissionGrantEtag) !== void 0 ? { permissionGrantEtag } : {}
|
|
1156
|
-
});
|
|
1094
|
+
function removeTrailingSlash(url) {
|
|
1095
|
+
if (url.endsWith("/")) return url.substring(0, url.length - 1);
|
|
1096
|
+
return url;
|
|
1157
1097
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1098
|
+
String.fromCharCode;
|
|
1099
|
+
const TRAILING_SLASH_RE = /\/$|\/\?|\/#/;
|
|
1100
|
+
const JOIN_LEADING_SLASH_RE = /^\.?\//;
|
|
1101
|
+
function hasTrailingSlash(input = "", respectQueryAndFragment) {
|
|
1102
|
+
if (!respectQueryAndFragment) return input.endsWith("/");
|
|
1103
|
+
return TRAILING_SLASH_RE.test(input);
|
|
1161
1104
|
}
|
|
1162
|
-
function
|
|
1163
|
-
return
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1105
|
+
function withTrailingSlash(input = "", respectQueryAndFragment) {
|
|
1106
|
+
if (!respectQueryAndFragment) return input.endsWith("/") ? input : input + "/";
|
|
1107
|
+
if (hasTrailingSlash(input, true)) return input || "/";
|
|
1108
|
+
let path = input;
|
|
1109
|
+
let fragment = "";
|
|
1110
|
+
const fragmentIndex = input.indexOf("#");
|
|
1111
|
+
if (fragmentIndex !== -1) {
|
|
1112
|
+
path = input.slice(0, fragmentIndex);
|
|
1113
|
+
fragment = input.slice(fragmentIndex);
|
|
1114
|
+
if (!path) return fragment;
|
|
1115
|
+
}
|
|
1116
|
+
const [s0, ...s] = path.split("?");
|
|
1117
|
+
return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment;
|
|
1173
1118
|
}
|
|
1174
|
-
function
|
|
1175
|
-
|
|
1176
|
-
"items",
|
|
1177
|
-
"nextCursor",
|
|
1178
|
-
"collectionRevision",
|
|
1179
|
-
"collectionEtag"
|
|
1180
|
-
]) && Array.isArray(value.items) && value.items.length <= 50 && value.items.every(isPermissionGrant) && (value.nextCursor === null || typeof value.nextCursor === "string" && value.nextCursor.length <= 699 && CURSOR.test(value.nextCursor)) && isSafeInteger(value.collectionRevision) && typeof value.collectionEtag === "string" && parseCollectionEtag(value.collectionEtag) === value.collectionRevision)) return false;
|
|
1181
|
-
const collectionHeader = headers.get("drive-permission-collection-etag");
|
|
1182
|
-
const representationEtag = headers.get("etag");
|
|
1183
|
-
const collectionRevision = value.collectionRevision;
|
|
1184
|
-
if (!isSafeInteger(collectionRevision)) return false;
|
|
1185
|
-
return collectionHeader === value.collectionEtag && representationEtag !== null && LIST_ETAG.test(representationEtag) && value.items.every((grant) => (grant.source === "direct" ? grant.sourceItemId === targetItemId : grant.sourceItemId !== targetItemId) && grant.etag === permissionGrantEtag(collectionRevision, grant.revision)) && isStrictlyOrdered(value.items, (grant) => `${grant.sourceItemId}\0${grant.grantId}`);
|
|
1119
|
+
function isNonEmptyURL(url) {
|
|
1120
|
+
return url && url !== "/";
|
|
1186
1121
|
}
|
|
1187
|
-
function
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
"
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
"availability",
|
|
1195
|
-
"expiresAtEpochMilliseconds",
|
|
1196
|
-
"revision",
|
|
1197
|
-
"etag"
|
|
1198
|
-
]) && (value.source === "direct" || value.source === "inherited") && typeof value.sourceItemId === "string" && ITEM_ID.test(value.sourceItemId) && typeof value.grantId === "string" && GRANT_ID.test(value.grantId) && isGrantee(value.grantee) && isPermissionActions(value.actions) && [
|
|
1199
|
-
"active",
|
|
1200
|
-
"expired",
|
|
1201
|
-
"revoked"
|
|
1202
|
-
].includes(String(value.availability)) && (value.expiresAtEpochMilliseconds === null || isSafeInteger(value.expiresAtEpochMilliseconds)) && isSafeInteger(value.revision) && typeof value.etag === "string" && GRANT_ETAG.test(value.etag);
|
|
1122
|
+
function joinURL(base, ...input) {
|
|
1123
|
+
let url = base || "";
|
|
1124
|
+
for (const segment of input.filter((url2) => isNonEmptyURL(url2))) if (url) {
|
|
1125
|
+
const _segment = segment.replace(JOIN_LEADING_SLASH_RE, "");
|
|
1126
|
+
url = withTrailingSlash(url) + _segment;
|
|
1127
|
+
} else url = segment;
|
|
1128
|
+
return url;
|
|
1203
1129
|
}
|
|
1204
|
-
|
|
1205
|
-
|
|
1130
|
+
//#endregion
|
|
1131
|
+
//#region src/internal/client/transport.ts
|
|
1132
|
+
const DEFAULT_REQUEST_TIMEOUT_MILLISECONDS = 3e4;
|
|
1133
|
+
const MAX_REQUEST_TIMEOUT_MILLISECONDS = 12e4;
|
|
1134
|
+
function createClientRuntime(config) {
|
|
1135
|
+
let runtime;
|
|
1136
|
+
try {
|
|
1137
|
+
runtime = Object.freeze({
|
|
1138
|
+
baseUrl: parseBaseUrl(config.baseUrl),
|
|
1139
|
+
fetchImplementation: config.fetch ?? globalThis.fetch,
|
|
1140
|
+
getCredential: config.getCredential,
|
|
1141
|
+
timeoutMilliseconds: parseTimeoutMilliseconds(config.timeoutMilliseconds)
|
|
1142
|
+
});
|
|
1143
|
+
} catch {
|
|
1144
|
+
throw new DriveError("invalid_input");
|
|
1145
|
+
}
|
|
1146
|
+
if (typeof runtime.fetchImplementation !== "function" || typeof runtime.getCredential !== "function") throw new DriveError("invalid_input");
|
|
1147
|
+
return runtime;
|
|
1148
|
+
}
|
|
1149
|
+
async function execute(runtime, signal, preconditionStatus, send, successStatuses, guard, allowsQuotaExceeded = false) {
|
|
1150
|
+
const operation = createOperationSignal(signal, runtime.timeoutMilliseconds);
|
|
1151
|
+
try {
|
|
1152
|
+
const operationSignal = operation.signal;
|
|
1153
|
+
throwIfAborted(operationSignal);
|
|
1154
|
+
const credential = await obtainCredential(runtime.getCredential, operationSignal);
|
|
1155
|
+
let capturedResponse;
|
|
1156
|
+
await send(createClient({
|
|
1157
|
+
baseUrl: runtime.baseUrl,
|
|
1158
|
+
fetch: async (request) => {
|
|
1159
|
+
try {
|
|
1160
|
+
const response = await raceWithAbort(runtime.fetchImplementation(request), operationSignal);
|
|
1161
|
+
if (!(response instanceof Response)) throw new DriveError("invalid_response");
|
|
1162
|
+
capturedResponse = response;
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
if (error instanceof DriveError) throw error;
|
|
1165
|
+
throw operationSignal.aborted ? new DriveError("aborted") : new DriveError("network_error");
|
|
1166
|
+
}
|
|
1167
|
+
return new Response(null, { status: 204 });
|
|
1168
|
+
}
|
|
1169
|
+
}), {
|
|
1170
|
+
cache: "no-store",
|
|
1171
|
+
credentials: "omit",
|
|
1172
|
+
headers: new Headers({ authorization: `Bearer ${credential}` }),
|
|
1173
|
+
signal: operationSignal
|
|
1174
|
+
});
|
|
1175
|
+
if (!capturedResponse) throw new DriveError("network_error");
|
|
1176
|
+
return await parseResponse(capturedResponse, operationSignal, preconditionStatus, successStatuses, guard, allowsQuotaExceeded);
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
if (operation.didTimeout()) throw new DriveError("timeout");
|
|
1179
|
+
if (error instanceof DriveError) throw error;
|
|
1180
|
+
throw operation.signal.aborted ? new DriveError("aborted") : new DriveError("network_error");
|
|
1181
|
+
} finally {
|
|
1182
|
+
operation.dispose();
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
function parseTimeoutMilliseconds(value) {
|
|
1186
|
+
if (value === void 0) return DEFAULT_REQUEST_TIMEOUT_MILLISECONDS;
|
|
1187
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_REQUEST_TIMEOUT_MILLISECONDS) throw new DriveError("invalid_input");
|
|
1188
|
+
return value;
|
|
1189
|
+
}
|
|
1190
|
+
function createOperationSignal(callerSignal, timeoutMilliseconds) {
|
|
1191
|
+
const controller = new AbortController();
|
|
1192
|
+
let timedOut = false;
|
|
1193
|
+
const onAbort = () => controller.abort();
|
|
1194
|
+
if (callerSignal?.aborted) controller.abort();
|
|
1195
|
+
else callerSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1196
|
+
const timeout = setTimeout(() => {
|
|
1197
|
+
timedOut = true;
|
|
1198
|
+
controller.abort();
|
|
1199
|
+
}, timeoutMilliseconds);
|
|
1200
|
+
return {
|
|
1201
|
+
signal: controller.signal,
|
|
1202
|
+
didTimeout: () => timedOut,
|
|
1203
|
+
dispose: () => {
|
|
1204
|
+
clearTimeout(timeout);
|
|
1205
|
+
callerSignal?.removeEventListener("abort", onAbort);
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
function parseBaseUrl(value) {
|
|
1210
|
+
if (typeof value !== "string") throw new TypeError("Drive base URL is invalid");
|
|
1211
|
+
let url;
|
|
1212
|
+
try {
|
|
1213
|
+
url = new URL(value);
|
|
1214
|
+
} catch {
|
|
1215
|
+
throw new TypeError("Drive base URL is invalid");
|
|
1216
|
+
}
|
|
1217
|
+
const localHttp = url.protocol === "http:" && [
|
|
1218
|
+
"localhost",
|
|
1219
|
+
"127.0.0.1",
|
|
1220
|
+
"[::1]"
|
|
1221
|
+
].includes(url.hostname);
|
|
1222
|
+
if (url.protocol !== "https:" && !localHttp || url.username || url.password || url.search || url.hash || !url.host) throw new TypeError("Drive base URL is invalid");
|
|
1223
|
+
return joinURL(url.origin, url.pathname);
|
|
1206
1224
|
}
|
|
1207
|
-
function
|
|
1208
|
-
|
|
1225
|
+
async function obtainCredential(provider, signal) {
|
|
1226
|
+
throwIfAborted(signal);
|
|
1227
|
+
let credential;
|
|
1228
|
+
try {
|
|
1229
|
+
credential = await raceWithAbort(provider({ signal }), signal);
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
if (error instanceof DriveError && error.code === "aborted") throw error;
|
|
1232
|
+
throw signal.aborted ? new DriveError("aborted") : new DriveError("credential_unavailable");
|
|
1233
|
+
}
|
|
1234
|
+
if (typeof credential !== "string" || credential.length < 1 || credential.length > 16384 || !/^[\x21-\x7e]+$/.test(credential)) throw new DriveError("credential_unavailable");
|
|
1235
|
+
return credential;
|
|
1209
1236
|
}
|
|
1210
|
-
function
|
|
1211
|
-
if (
|
|
1212
|
-
"outcome",
|
|
1213
|
-
"grant",
|
|
1214
|
-
"collectionRevision"
|
|
1215
|
-
]) || value.outcome !== "committed" && value.outcome !== "replayed" || !isSafeInteger(value.collectionRevision)) return false;
|
|
1216
|
-
const grant = value.grant;
|
|
1217
|
-
return isExactRecord(grant, [
|
|
1218
|
-
"source",
|
|
1219
|
-
"sourceItemId",
|
|
1220
|
-
"grantId",
|
|
1221
|
-
"grantee",
|
|
1222
|
-
"actions",
|
|
1223
|
-
"availability",
|
|
1224
|
-
"expiresAtEpochMilliseconds",
|
|
1225
|
-
"revision"
|
|
1226
|
-
]) && grant.source === "direct" && typeof grant.sourceItemId === "string" && grant.sourceItemId === targetItemId && typeof grant.grantId === "string" && GRANT_ID.test(grant.grantId) && (expectedGrantId === void 0 || grant.grantId === expectedGrantId) && isGrantee(grant.grantee) && isPermissionActions(grant.actions) && [
|
|
1227
|
-
"active",
|
|
1228
|
-
"expired",
|
|
1229
|
-
"revoked"
|
|
1230
|
-
].includes(String(grant.availability)) && (grant.expiresAtEpochMilliseconds === null || isSafeInteger(grant.expiresAtEpochMilliseconds)) && isSafeInteger(grant.revision);
|
|
1237
|
+
function throwIfAborted(signal) {
|
|
1238
|
+
if (signal.aborted) throw new DriveError("aborted");
|
|
1231
1239
|
}
|
|
1232
|
-
function
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
"restricted_administrator_bypass",
|
|
1245
|
-
"direct_grant",
|
|
1246
|
-
"inherited_grant"
|
|
1247
|
-
].includes(String(action.basis))) || !(action.sourceItemId === null || typeof action.sourceItemId === "string" && ITEM_ID.test(action.sourceItemId)) || !(action.grantId === null || typeof action.grantId === "string" && GRANT_ID.test(action.grantId)) || !effectiveSourceIsCoherent(action, targetItemId)) return false;
|
|
1240
|
+
async function raceWithAbort(promise, signal) {
|
|
1241
|
+
throwIfAborted(signal);
|
|
1242
|
+
let removeAbort = () => {};
|
|
1243
|
+
const aborted = new Promise((_, reject) => {
|
|
1244
|
+
const onAbort = () => reject(new DriveError("aborted"));
|
|
1245
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1246
|
+
removeAbort = () => signal.removeEventListener("abort", onAbort);
|
|
1247
|
+
});
|
|
1248
|
+
try {
|
|
1249
|
+
return await Promise.race([promise, aborted]);
|
|
1250
|
+
} finally {
|
|
1251
|
+
removeAbort();
|
|
1248
1252
|
}
|
|
1249
|
-
return true;
|
|
1250
|
-
}
|
|
1251
|
-
function isUploadQuotaReservation(value) {
|
|
1252
|
-
return isExactRecord(value, [
|
|
1253
|
-
"workspaceId",
|
|
1254
|
-
"uploadId",
|
|
1255
|
-
"parentItemId",
|
|
1256
|
-
"expectedByteLength",
|
|
1257
|
-
"state",
|
|
1258
|
-
"terminalReason",
|
|
1259
|
-
"createdAtEpochMilliseconds",
|
|
1260
|
-
"expiresAtEpochMilliseconds",
|
|
1261
|
-
"terminalAtEpochMilliseconds"
|
|
1262
|
-
]) && typeof value.workspaceId === "string" && WORKSPACE_ID.test(value.workspaceId) && typeof value.uploadId === "string" && UPLOAD_ID.test(value.uploadId) && typeof value.parentItemId === "string" && ITEM_ID.test(value.parentItemId) && typeof value.expectedByteLength === "number" && Number.isSafeInteger(value.expectedByteLength) && value.expectedByteLength >= 0 && value.expectedByteLength <= MAX_UPLOAD_BYTE_LENGTH && (value.state === "reserved" || value.state === "converted" || value.state === "released") && (value.terminalReason === null || value.terminalReason === "completed" || value.terminalReason === "aborted" || value.terminalReason === "failed" || value.terminalReason === "expired") && isSafeInteger(value.createdAtEpochMilliseconds) && isSafeInteger(value.expiresAtEpochMilliseconds) && value.expiresAtEpochMilliseconds - value.createdAtEpochMilliseconds === UPLOAD_QUOTA_EXPIRY_MILLISECONDS && (value.terminalAtEpochMilliseconds === null || isSafeInteger(value.terminalAtEpochMilliseconds) && value.terminalAtEpochMilliseconds >= value.createdAtEpochMilliseconds);
|
|
1263
1253
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region src/internal/client/operations.ts
|
|
1256
|
+
function createDriveClientInternal(config) {
|
|
1257
|
+
const runtime = createClientRuntime(config);
|
|
1258
|
+
return Object.freeze({
|
|
1259
|
+
listFolderChildren: (input) => listFolderChildren(runtime, input),
|
|
1260
|
+
createFolder: (input) => createFolder(runtime, input),
|
|
1261
|
+
listItemPermissions: (input) => listItemPermissions(runtime, input),
|
|
1262
|
+
readEffectiveItemPermissions: (input) => readEffectiveItemPermissions(runtime, input),
|
|
1263
|
+
createItemPermission: (input) => createItemPermission(runtime, input),
|
|
1264
|
+
updateItemPermission: (input) => updateItemPermission(runtime, input),
|
|
1265
|
+
revokeItemPermission: (input) => revokeItemPermission(runtime, input),
|
|
1266
|
+
createUpload: (input) => createUpload(runtime, input),
|
|
1267
|
+
abortUpload: (input) => abortUpload(runtime, input)
|
|
1268
|
+
});
|
|
1270
1269
|
}
|
|
1271
|
-
function
|
|
1272
|
-
const
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1270
|
+
async function listFolderChildren(runtime, input) {
|
|
1271
|
+
const validated = validatePageInput(input);
|
|
1272
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/children", {
|
|
1273
|
+
...operationOptions("listFolderChildren", { params: {
|
|
1274
|
+
path: resourcePath(validated),
|
|
1275
|
+
query: pageQuery(validated)
|
|
1276
|
+
} }),
|
|
1277
|
+
...requestOptions
|
|
1278
|
+
}), [200], (value) => isFolderPage(value, validated.workspaceId, validated.itemId));
|
|
1279
1279
|
}
|
|
1280
|
-
function
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1280
|
+
async function createFolder(runtime, input) {
|
|
1281
|
+
const validated = validateCreateFolderInput(input);
|
|
1282
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/children", {
|
|
1283
|
+
...operationOptions("createFolder", {
|
|
1284
|
+
params: {
|
|
1285
|
+
path: resourcePath(validated),
|
|
1286
|
+
header: { "Idempotency-Key": validated.idempotencyKey }
|
|
1287
|
+
},
|
|
1288
|
+
body: { name: validated.name }
|
|
1289
|
+
}),
|
|
1290
|
+
...requestOptions
|
|
1291
|
+
}), [200, 201], (value) => isFolderItem(value) && value.workspaceId === validated.workspaceId && value.parentItemId === validated.itemId && value.kind === "folder" && value.name === validated.name);
|
|
1285
1292
|
}
|
|
1286
|
-
function
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1293
|
+
async function listItemPermissions(runtime, input) {
|
|
1294
|
+
const validated = validatePageInput(input);
|
|
1295
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions", {
|
|
1296
|
+
...operationOptions("listItemPermissions", { params: {
|
|
1297
|
+
path: resourcePath(validated),
|
|
1298
|
+
query: pageQuery(validated)
|
|
1299
|
+
} }),
|
|
1300
|
+
...requestOptions
|
|
1301
|
+
}), [200], (value, _status, headers) => isPermissionPage(value, headers, validated.itemId));
|
|
1292
1302
|
}
|
|
1293
|
-
function
|
|
1294
|
-
|
|
1303
|
+
async function readEffectiveItemPermissions(runtime, input) {
|
|
1304
|
+
const validated = validateResourceInput(input);
|
|
1305
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.GET("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions/effective", {
|
|
1306
|
+
...operationOptions("readEffectiveItemPermissions", { params: { path: resourcePath(validated) } }),
|
|
1307
|
+
...requestOptions
|
|
1308
|
+
}), [200], (value) => isEffectivePermissionResponse(value, validated.itemId));
|
|
1295
1309
|
}
|
|
1296
|
-
function
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1310
|
+
async function createItemPermission(runtime, input) {
|
|
1311
|
+
const validated = validateCreatePermissionInput(input);
|
|
1312
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions", {
|
|
1313
|
+
...operationOptions("createItemPermission", {
|
|
1314
|
+
params: {
|
|
1315
|
+
path: resourcePath(validated),
|
|
1316
|
+
header: {
|
|
1317
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
1318
|
+
"If-Match": validated.ifMatch
|
|
1319
|
+
}
|
|
1320
|
+
},
|
|
1321
|
+
body: {
|
|
1322
|
+
grantee: validated.grantee,
|
|
1323
|
+
actions: validated.actions,
|
|
1324
|
+
expiresAtEpochMilliseconds: validated.expiresAtEpochMilliseconds
|
|
1325
|
+
}
|
|
1326
|
+
}),
|
|
1327
|
+
...requestOptions
|
|
1328
|
+
}), [200, 201], (value, status, headers) => isPermissionMutation(value, validated.itemId) && (status === 201 && value.outcome === "committed" || status === 200 && value.outcome === "replayed") && (status === 200 || value.grant.availability !== "revoked") && mutationValidatorsAreCoherent(headers));
|
|
1308
1329
|
}
|
|
1309
|
-
function
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
"
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1330
|
+
async function updateItemPermission(runtime, input) {
|
|
1331
|
+
const validated = validateUpdatePermissionInput(input);
|
|
1332
|
+
const body = {};
|
|
1333
|
+
if (validated.actions !== void 0) body.actions = validated.actions;
|
|
1334
|
+
if (validated.expiresAtEpochMilliseconds !== void 0) body.expiresAtEpochMilliseconds = validated.expiresAtEpochMilliseconds;
|
|
1335
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.PATCH("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions/{grantId}", {
|
|
1336
|
+
...operationOptions("updateItemPermission", {
|
|
1337
|
+
params: {
|
|
1338
|
+
path: {
|
|
1339
|
+
...resourcePath(validated),
|
|
1340
|
+
grantId: validated.grantId
|
|
1341
|
+
},
|
|
1342
|
+
header: {
|
|
1343
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
1344
|
+
"If-Match": validated.ifMatch
|
|
1345
|
+
}
|
|
1346
|
+
},
|
|
1347
|
+
body
|
|
1348
|
+
}),
|
|
1349
|
+
...requestOptions
|
|
1350
|
+
}), [200], (value, _status, headers) => isPermissionMutation(value, validated.itemId, validated.grantId) && value.grant.availability !== "revoked" && mutationValidatorsAreCoherent(headers));
|
|
1320
1351
|
}
|
|
1321
|
-
function
|
|
1322
|
-
|
|
1352
|
+
async function revokeItemPermission(runtime, input) {
|
|
1353
|
+
const validated = validateGrantMutationInput(input);
|
|
1354
|
+
return execute(runtime, validated.signal, 412, (api, requestOptions) => api.DELETE("/api/v1/workspaces/{workspaceId}/items/{itemId}/permissions/{grantId}", {
|
|
1355
|
+
...operationOptions("revokeItemPermission", { params: {
|
|
1356
|
+
path: {
|
|
1357
|
+
...resourcePath(validated),
|
|
1358
|
+
grantId: validated.grantId
|
|
1359
|
+
},
|
|
1360
|
+
header: {
|
|
1361
|
+
"Idempotency-Key": validated.idempotencyKey,
|
|
1362
|
+
"If-Match": validated.ifMatch
|
|
1363
|
+
}
|
|
1364
|
+
} }),
|
|
1365
|
+
...requestOptions
|
|
1366
|
+
}), [200], (value, _status, headers) => isPermissionMutation(value, validated.itemId, validated.grantId) && value.grant.availability === "revoked" && parseCollectionEtag(headers.get("drive-permission-collection-etag") ?? "") !== void 0 && headers.get("drive-permission-grant-etag") === null);
|
|
1323
1367
|
}
|
|
1324
|
-
function
|
|
1325
|
-
|
|
1368
|
+
async function createUpload(runtime, input) {
|
|
1369
|
+
const validated = validateCreateUploadInput(input);
|
|
1370
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.POST("/api/v1/workspaces/{workspaceId}/uploads", {
|
|
1371
|
+
...operationOptions("createUpload", {
|
|
1372
|
+
params: {
|
|
1373
|
+
path: { workspaceId: validated.workspaceId },
|
|
1374
|
+
header: { "Idempotency-Key": validated.idempotencyKey }
|
|
1375
|
+
},
|
|
1376
|
+
body: {
|
|
1377
|
+
parentItemId: validated.parentItemId,
|
|
1378
|
+
expectedByteLength: validated.expectedByteLength
|
|
1379
|
+
}
|
|
1380
|
+
}),
|
|
1381
|
+
...requestOptions
|
|
1382
|
+
}), [200, 201], (value) => isUploadQuotaReservation(value) && value.workspaceId === validated.workspaceId && value.parentItemId === validated.parentItemId && value.expectedByteLength === validated.expectedByteLength && value.state === "reserved" && value.terminalReason === null && value.terminalAtEpochMilliseconds === null, true);
|
|
1326
1383
|
}
|
|
1327
|
-
function
|
|
1328
|
-
|
|
1329
|
-
return
|
|
1384
|
+
async function abortUpload(runtime, input) {
|
|
1385
|
+
const validated = validateAbortUploadInput(input);
|
|
1386
|
+
return execute(runtime, validated.signal, 409, (api, requestOptions) => api.DELETE("/api/v1/workspaces/{workspaceId}/uploads/{uploadId}", {
|
|
1387
|
+
...operationOptions("abortUpload", { params: { path: {
|
|
1388
|
+
workspaceId: validated.workspaceId,
|
|
1389
|
+
uploadId: validated.uploadId
|
|
1390
|
+
} } }),
|
|
1391
|
+
...requestOptions
|
|
1392
|
+
}), [200], (value) => isUploadQuotaReservation(value) && value.workspaceId === validated.workspaceId && value.uploadId === validated.uploadId && value.state === "released" && value.terminalReason === "aborted" && value.terminalAtEpochMilliseconds !== null);
|
|
1330
1393
|
}
|
|
1331
1394
|
//#endregion
|
|
1332
1395
|
//#region src/client.ts
|