@supacloud/admin 0.16.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +65 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -26123,6 +26123,14 @@ function validatedPostTimeout(options) {
|
|
|
26123
26123
|
}
|
|
26124
26124
|
return timeoutMs;
|
|
26125
26125
|
}
|
|
26126
|
+
function validatedResponseTimeout(timeoutMs) {
|
|
26127
|
+
if (timeoutMs === undefined)
|
|
26128
|
+
return;
|
|
26129
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_POST_TIMEOUT_MS) {
|
|
26130
|
+
throw new RangeError(`HTTP response timeout must be between 1 and ${MAX_POST_TIMEOUT_MS} ms`);
|
|
26131
|
+
}
|
|
26132
|
+
return timeoutMs;
|
|
26133
|
+
}
|
|
26126
26134
|
function validatedGetResponseLimit(options) {
|
|
26127
26135
|
const maxBytes = options.maxResponseBytes;
|
|
26128
26136
|
if (maxBytes === undefined)
|
|
@@ -26154,16 +26162,12 @@ function joinedResponseBytes(chunks, totalBytes) {
|
|
|
26154
26162
|
}
|
|
26155
26163
|
return responseBytes;
|
|
26156
26164
|
}
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
26162
|
-
|
|
26163
|
-
}
|
|
26164
|
-
if (!response.body)
|
|
26165
|
-
return new Uint8Array;
|
|
26166
|
-
const reader = response.body.getReader();
|
|
26165
|
+
function cancelResponseReader(reader) {
|
|
26166
|
+
reader.cancel().catch(() => {
|
|
26167
|
+
return;
|
|
26168
|
+
});
|
|
26169
|
+
}
|
|
26170
|
+
async function responseBytesFromReader(reader, maxBytes) {
|
|
26167
26171
|
const chunks = [];
|
|
26168
26172
|
let totalBytes = 0;
|
|
26169
26173
|
while (true) {
|
|
@@ -26172,14 +26176,41 @@ async function boundedResponseBytes(response, maxBytes) {
|
|
|
26172
26176
|
return joinedResponseBytes(chunks, totalBytes);
|
|
26173
26177
|
totalBytes += value.byteLength;
|
|
26174
26178
|
if (totalBytes > maxBytes) {
|
|
26175
|
-
reader
|
|
26176
|
-
return;
|
|
26177
|
-
});
|
|
26179
|
+
cancelResponseReader(reader);
|
|
26178
26180
|
return null;
|
|
26179
26181
|
}
|
|
26180
26182
|
chunks.push(value);
|
|
26181
26183
|
}
|
|
26182
26184
|
}
|
|
26185
|
+
async function responseBytesBeforeDeadline(reader, maxBytes, responseTimeoutMs) {
|
|
26186
|
+
let deadlineTimer;
|
|
26187
|
+
const deadline = new Promise((resolve2) => {
|
|
26188
|
+
deadlineTimer = setTimeout(() => {
|
|
26189
|
+
cancelResponseReader(reader);
|
|
26190
|
+
resolve2(null);
|
|
26191
|
+
}, responseTimeoutMs);
|
|
26192
|
+
});
|
|
26193
|
+
try {
|
|
26194
|
+
return await Promise.race([responseBytesFromReader(reader, maxBytes), deadline]);
|
|
26195
|
+
} catch {
|
|
26196
|
+
cancelResponseReader(reader);
|
|
26197
|
+
return null;
|
|
26198
|
+
} finally {
|
|
26199
|
+
clearTimeout(deadlineTimer);
|
|
26200
|
+
}
|
|
26201
|
+
}
|
|
26202
|
+
async function boundedResponseBytes(response, maxBytes, responseTimeoutMs) {
|
|
26203
|
+
if (responseExceedsDeclaredLimit(response, maxBytes)) {
|
|
26204
|
+
response.body?.cancel().catch(() => {
|
|
26205
|
+
return;
|
|
26206
|
+
});
|
|
26207
|
+
return null;
|
|
26208
|
+
}
|
|
26209
|
+
if (!response.body)
|
|
26210
|
+
return new Uint8Array;
|
|
26211
|
+
const reader = response.body.getReader();
|
|
26212
|
+
return responseTimeoutMs === undefined ? responseBytesFromReader(reader, maxBytes) : responseBytesBeforeDeadline(reader, maxBytes, responseTimeoutMs);
|
|
26213
|
+
}
|
|
26183
26214
|
async function boundedResponseJson(response, maxBytes) {
|
|
26184
26215
|
const responseBytes = await boundedResponseBytes(response, maxBytes);
|
|
26185
26216
|
if (responseBytes === null)
|
|
@@ -26193,8 +26224,8 @@ async function boundedResponseJson(response, maxBytes) {
|
|
|
26193
26224
|
throw error;
|
|
26194
26225
|
}
|
|
26195
26226
|
}
|
|
26196
|
-
async function strictBoundedResponseJson(response, maxBytes) {
|
|
26197
|
-
const responseBytes = await boundedResponseBytes(response, maxBytes);
|
|
26227
|
+
async function strictBoundedResponseJson(response, maxBytes, responseTimeoutMs) {
|
|
26228
|
+
const responseBytes = await boundedResponseBytes(response, maxBytes, responseTimeoutMs);
|
|
26198
26229
|
if (responseBytes === null)
|
|
26199
26230
|
throw new Error("HTTP JSON response exceeded its byte limit");
|
|
26200
26231
|
const responseText = new TextDecoder("utf-8", { fatal: true }).decode(responseBytes);
|
|
@@ -26282,6 +26313,7 @@ class HttpTransport {
|
|
|
26282
26313
|
async post(path, body, options) {
|
|
26283
26314
|
const timeoutMs = validatedPostTimeout(options);
|
|
26284
26315
|
const maxJsonBytes = validatedStrictJsonLimit({ maxJsonBytes: options?.maxJsonBytes });
|
|
26316
|
+
const responseTimeoutMs = validatedResponseTimeout(options?.responseTimeoutMs);
|
|
26285
26317
|
let response;
|
|
26286
26318
|
try {
|
|
26287
26319
|
response = await fetchWithRetry(`${this.baseUrl}${path}`, {
|
|
@@ -26294,7 +26326,7 @@ class HttpTransport {
|
|
|
26294
26326
|
}
|
|
26295
26327
|
if (maxJsonBytes !== undefined) {
|
|
26296
26328
|
try {
|
|
26297
|
-
const data2 = await strictBoundedResponseJson(response, maxJsonBytes);
|
|
26329
|
+
const data2 = await strictBoundedResponseJson(response, maxJsonBytes, responseTimeoutMs);
|
|
26298
26330
|
return { ok: response.ok, status: response.status, data: data2 };
|
|
26299
26331
|
} catch {
|
|
26300
26332
|
return responseBodyFailure(response.status);
|
|
@@ -26315,6 +26347,7 @@ class HttpTransport {
|
|
|
26315
26347
|
}
|
|
26316
26348
|
const maxJsonBytes = validatedStrictJsonLimit({ maxJsonBytes: options.maxJsonBytes });
|
|
26317
26349
|
const timeoutMs = validatedPostTimeout(options.timeoutMs === undefined ? undefined : { timeoutMs: options.timeoutMs });
|
|
26350
|
+
const responseTimeoutMs = validatedResponseTimeout(options.responseTimeoutMs);
|
|
26318
26351
|
try {
|
|
26319
26352
|
const request = {
|
|
26320
26353
|
method: "POST",
|
|
@@ -26329,7 +26362,7 @@ class HttpTransport {
|
|
|
26329
26362
|
};
|
|
26330
26363
|
const response = await fetchWithRetry(`${this.baseUrl}${path}`, request, timeoutMs);
|
|
26331
26364
|
try {
|
|
26332
|
-
const data = await strictBoundedResponseJson(response, maxJsonBytes);
|
|
26365
|
+
const data = await strictBoundedResponseJson(response, maxJsonBytes, responseTimeoutMs);
|
|
26333
26366
|
return { ok: response.ok, status: response.status, data };
|
|
26334
26367
|
} catch {
|
|
26335
26368
|
return responseBodyFailure(response.status);
|
|
@@ -31817,6 +31850,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
31817
31850
|
managed_upstream: optional(stringEnum(["edge-functions"]), "[upsert_route/update_route] 托管上游(同步 Edge Function)"),
|
|
31818
31851
|
upstream_tls_insecure_skip_verify: optional(Type.Boolean(), "[upsert_route/update_route] 上游 TLS 跳过校验"),
|
|
31819
31852
|
static_root: optional(Type.String(), "[upsert_route/update_route] 静态站点根目录"),
|
|
31853
|
+
spa: optional(Type.Boolean(), "[upsert_route/update_route] 是否启用 SPA 单页回退"),
|
|
31820
31854
|
protocol: optional(stringEnum(["http", "https"]), "[upsert_route/update_route] 可选请求协议匹配"),
|
|
31821
31855
|
redirect_to: optional(Type.String(), "[upsert_route/update_route] 带固定 host 的绝对 http(s) 目标,可在末尾使用 {http.request.uri}"),
|
|
31822
31856
|
redirect_status: withDescription(redirectStatus, "[upsert_route/update_route] 重定向状态码,默认 308"),
|
|
@@ -31863,6 +31897,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
31863
31897
|
managed_upstream,
|
|
31864
31898
|
upstream_tls_insecure_skip_verify,
|
|
31865
31899
|
static_root,
|
|
31900
|
+
spa,
|
|
31866
31901
|
protocol,
|
|
31867
31902
|
redirect_to,
|
|
31868
31903
|
redirect_status,
|
|
@@ -31912,6 +31947,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
31912
31947
|
body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
|
|
31913
31948
|
if (static_root !== undefined)
|
|
31914
31949
|
body.static_root = static_root;
|
|
31950
|
+
if (spa !== undefined)
|
|
31951
|
+
body.spa = spa;
|
|
31915
31952
|
if (protocol !== undefined)
|
|
31916
31953
|
body.protocol = protocol;
|
|
31917
31954
|
if (redirect_to !== undefined)
|
|
@@ -31949,6 +31986,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
31949
31986
|
body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
|
|
31950
31987
|
if (static_root !== undefined)
|
|
31951
31988
|
body.static_root = static_root;
|
|
31989
|
+
if (spa !== undefined)
|
|
31990
|
+
body.spa = spa;
|
|
31952
31991
|
if (protocol !== undefined)
|
|
31953
31992
|
body.protocol = protocol;
|
|
31954
31993
|
if (redirect_to !== undefined)
|
|
@@ -32066,7 +32105,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
|
|
|
32066
32105
|
});
|
|
32067
32106
|
}
|
|
32068
32107
|
|
|
32069
|
-
// src/shared/tools/frontend-release-control.ts
|
|
32108
|
+
// ../cli/src/shared/tools/frontend-release-control.ts
|
|
32070
32109
|
import { createHash as createHash3 } from "node:crypto";
|
|
32071
32110
|
import { constants as fsConstants2 } from "node:fs";
|
|
32072
32111
|
import { open as open2 } from "node:fs/promises";
|
|
@@ -32080,6 +32119,7 @@ var ARCHIVE_MAX_BYTES = 100 * 1024 * 1024;
|
|
|
32080
32119
|
var ARCHIVE_CHUNK_BYTES = 64 * 1024;
|
|
32081
32120
|
var RESPONSE_MAX_BYTES = 1024 * 1024;
|
|
32082
32121
|
var UPLOAD_REQUEST_TIMEOUT_MS = 10 * 60000;
|
|
32122
|
+
var MUTATION_RESPONSE_TIMEOUT_MS = 5000;
|
|
32083
32123
|
var RELEASE_LIST_LIMIT_MAX = 100;
|
|
32084
32124
|
function toolResponse(payload) {
|
|
32085
32125
|
return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
|
|
@@ -32290,7 +32330,8 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
|
|
|
32290
32330
|
contentLength: archive.sizeBytes,
|
|
32291
32331
|
contentSha256: archive.sha256,
|
|
32292
32332
|
maxJsonBytes: RESPONSE_MAX_BYTES,
|
|
32293
|
-
timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS
|
|
32333
|
+
timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
|
|
32334
|
+
responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
|
|
32294
32335
|
});
|
|
32295
32336
|
} finally {
|
|
32296
32337
|
await archive.handle.close();
|
|
@@ -32423,7 +32464,10 @@ async function activateFrontendRelease(http, input) {
|
|
|
32423
32464
|
expected_active_release_id: input.expectedActiveReleaseId,
|
|
32424
32465
|
expected_activation_id: input.expectedActivationId,
|
|
32425
32466
|
mutation_id: mutationId
|
|
32426
|
-
}, {
|
|
32467
|
+
}, {
|
|
32468
|
+
maxJsonBytes: RESPONSE_MAX_BYTES,
|
|
32469
|
+
responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
|
|
32470
|
+
});
|
|
32427
32471
|
const release = activationReceipt(response.data, { ...input, mutationId });
|
|
32428
32472
|
if (!response.ok || !release) {
|
|
32429
32473
|
if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
|
|
@@ -32467,7 +32511,6 @@ async function activationReadback(http, input, mutationId, activationStatus) {
|
|
|
32467
32511
|
release: readback.release
|
|
32468
32512
|
});
|
|
32469
32513
|
}
|
|
32470
|
-
|
|
32471
32514
|
// src/shared/tools/frontend-tools.ts
|
|
32472
32515
|
function registerFrontendTools(server, http) {
|
|
32473
32516
|
server.tool("frontend", `Immutable prebuilt frontend release control.
|
|
@@ -32542,7 +32585,7 @@ Actions: list_releases, get_release, upload_release, activate_release`, {
|
|
|
32542
32585
|
// package.json
|
|
32543
32586
|
var package_default = {
|
|
32544
32587
|
name: "@supacloud/admin",
|
|
32545
|
-
version: "0.
|
|
32588
|
+
version: "0.18.0",
|
|
32546
32589
|
description: "Platform administration CLI for SupaCloud operators",
|
|
32547
32590
|
type: "module",
|
|
32548
32591
|
main: "./dist/index.js",
|