@supacloud/admin 0.17.0 → 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.
Files changed (2) hide show
  1. package/dist/index.js +59 -22
  2. 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
- async function boundedResponseBytes(response, maxBytes) {
26158
- if (responseExceedsDeclaredLimit(response, maxBytes)) {
26159
- response.body?.cancel().catch(() => {
26160
- return;
26161
- });
26162
- return null;
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.cancel().catch(() => {
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);
@@ -32072,7 +32105,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
32072
32105
  });
32073
32106
  }
32074
32107
 
32075
- // src/shared/tools/frontend-release-control.ts
32108
+ // ../cli/src/shared/tools/frontend-release-control.ts
32076
32109
  import { createHash as createHash3 } from "node:crypto";
32077
32110
  import { constants as fsConstants2 } from "node:fs";
32078
32111
  import { open as open2 } from "node:fs/promises";
@@ -32086,6 +32119,7 @@ var ARCHIVE_MAX_BYTES = 100 * 1024 * 1024;
32086
32119
  var ARCHIVE_CHUNK_BYTES = 64 * 1024;
32087
32120
  var RESPONSE_MAX_BYTES = 1024 * 1024;
32088
32121
  var UPLOAD_REQUEST_TIMEOUT_MS = 10 * 60000;
32122
+ var MUTATION_RESPONSE_TIMEOUT_MS = 5000;
32089
32123
  var RELEASE_LIST_LIMIT_MAX = 100;
32090
32124
  function toolResponse(payload) {
32091
32125
  return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
@@ -32296,7 +32330,8 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
32296
32330
  contentLength: archive.sizeBytes,
32297
32331
  contentSha256: archive.sha256,
32298
32332
  maxJsonBytes: RESPONSE_MAX_BYTES,
32299
- timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS
32333
+ timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
32334
+ responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
32300
32335
  });
32301
32336
  } finally {
32302
32337
  await archive.handle.close();
@@ -32429,7 +32464,10 @@ async function activateFrontendRelease(http, input) {
32429
32464
  expected_active_release_id: input.expectedActiveReleaseId,
32430
32465
  expected_activation_id: input.expectedActivationId,
32431
32466
  mutation_id: mutationId
32432
- }, { maxJsonBytes: RESPONSE_MAX_BYTES });
32467
+ }, {
32468
+ maxJsonBytes: RESPONSE_MAX_BYTES,
32469
+ responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
32470
+ });
32433
32471
  const release = activationReceipt(response.data, { ...input, mutationId });
32434
32472
  if (!response.ok || !release) {
32435
32473
  if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
@@ -32473,7 +32511,6 @@ async function activationReadback(http, input, mutationId, activationStatus) {
32473
32511
  release: readback.release
32474
32512
  });
32475
32513
  }
32476
-
32477
32514
  // src/shared/tools/frontend-tools.ts
32478
32515
  function registerFrontendTools(server, http) {
32479
32516
  server.tool("frontend", `Immutable prebuilt frontend release control.
@@ -32548,7 +32585,7 @@ Actions: list_releases, get_release, upload_release, activate_release`, {
32548
32585
  // package.json
32549
32586
  var package_default = {
32550
32587
  name: "@supacloud/admin",
32551
- version: "0.17.0",
32588
+ version: "0.18.0",
32552
32589
  description: "Platform administration CLI for SupaCloud operators",
32553
32590
  type: "module",
32554
32591
  main: "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/admin",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Platform administration CLI for SupaCloud operators",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",