@supacloud/admin 0.6.0 → 0.7.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.
Files changed (2) hide show
  1. package/dist/index.js +43 -16
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -25159,29 +25159,46 @@ function resolveSupaCloudContext(env = process.env, cwd = process.cwd()) {
25159
25159
  var DEFAULT_TIMEOUT = 30000;
25160
25160
  var MAX_RETRIES = 2;
25161
25161
  var RETRY_BASE_DELAY = 500;
25162
- async function fetchWithRetry(url, options, retries = MAX_RETRIES) {
25162
+ function isRetryableMethod(method) {
25163
+ const normalizedMethod = (method ?? "GET").toUpperCase();
25164
+ return normalizedMethod === "GET" || normalizedMethod === "HEAD";
25165
+ }
25166
+ function isRetryableError(error) {
25167
+ if (!(error instanceof Error))
25168
+ return false;
25169
+ const networkError = error;
25170
+ return networkError.name === "AbortError" || networkError.code === "ECONNREFUSED" || networkError.code === "ECONNRESET";
25171
+ }
25172
+ async function fetchWithTimeout(url, options) {
25173
+ const controller = new AbortController;
25174
+ const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
25175
+ try {
25176
+ return await fetch(url, {
25177
+ ...options,
25178
+ signal: controller.signal
25179
+ });
25180
+ } finally {
25181
+ clearTimeout(timeout);
25182
+ }
25183
+ }
25184
+ async function fetchWithRetry(url, options) {
25185
+ const retries = isRetryableMethod(options.method) ? MAX_RETRIES : 0;
25163
25186
  for (let attempt = 0;attempt <= retries; attempt++) {
25164
25187
  try {
25165
- const controller = new AbortController;
25166
- const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
25167
- const res = await fetch(url, {
25168
- ...options,
25169
- signal: controller.signal
25170
- });
25171
- clearTimeout(timeout);
25172
- if (res.status >= 500 && attempt < retries) {
25188
+ const res = await fetchWithTimeout(url, options);
25189
+ if (res.status >= 500 && res.status < 600 && attempt < retries) {
25173
25190
  const delay = RETRY_BASE_DELAY * Math.pow(2, attempt);
25174
25191
  await new Promise((r) => setTimeout(r, delay));
25175
25192
  continue;
25176
25193
  }
25177
25194
  return res;
25178
- } catch (err) {
25179
- if (attempt < retries && (err.name === "AbortError" || err.code === "ECONNREFUSED" || err.code === "ECONNRESET")) {
25195
+ } catch (error) {
25196
+ if (attempt < retries && isRetryableError(error)) {
25180
25197
  const delay = RETRY_BASE_DELAY * Math.pow(2, attempt);
25181
25198
  await new Promise((r) => setTimeout(r, delay));
25182
25199
  continue;
25183
25200
  }
25184
- throw err;
25201
+ throw error;
25185
25202
  }
25186
25203
  }
25187
25204
  throw new Error("Unreachable");
@@ -25578,6 +25595,7 @@ class SshTransport {
25578
25595
  import { randomUUID } from "node:crypto";
25579
25596
  var SAFE_CONTAINER_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
25580
25597
  var SAFE_PROJECT_REF = /^[a-z0-9-]{1,20}$/;
25598
+ var SAFE_SCHEMA_IDENTIFIER = /^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/;
25581
25599
  var SAFE_RELEASE_TAG = /^[a-zA-Z0-9._-]{1,80}$/;
25582
25600
  var SAFE_TIMEOUT_SECONDS = 300;
25583
25601
  var SAFE_HOSTNAME = /^(?=.{1,253}$)(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)(?:\.(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?))*$/;
@@ -26071,12 +26089,15 @@ ${output}`;
26071
26089
  if (sourceRef === targetRef)
26072
26090
  throw new Error("source_ref and target_ref must be different");
26073
26091
  const s = args.schemas || "public,auth,storage";
26074
- if (!/^[a-z_,\s]+$/.test(s))
26075
- throw new Error("Invalid schemas");
26076
26092
  const schemas = s.split(",").map((x) => x.trim()).filter(Boolean);
26077
26093
  if (schemas.length === 0)
26078
26094
  throw new Error("At least one schema is required");
26079
- const schemaArgs = schemas.map((schema) => `-n ${schema}`).join(" ");
26095
+ for (const schema of schemas) {
26096
+ if (!SAFE_SCHEMA_IDENTIFIER.test(schema)) {
26097
+ throw new Error(`Invalid schema identifier: ${JSON.stringify(schema)}`);
26098
+ }
26099
+ }
26100
+ const schemaArgs = schemas.map((schema) => `-n '${schema}'`).join(" ");
26080
26101
  const df = args.data_only ? "--data-only" : "";
26081
26102
  const cmd = [
26082
26103
  "set -euo pipefail",
@@ -26515,8 +26536,9 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
26515
26536
  ref: optional(Type.String(), projectRef ? "可选:覆盖自动关联的项目 ref" : "项目 ref"),
26516
26537
  route_id: optional(Type.String(), "[upsert_route/update_route/delete_route] 路由 ID(字母/数字/_/-,1-64)"),
26517
26538
  hosts: withDescription(stringArray, "[upsert_route/update_route] 主机名列表,逗号分隔或 JSON 数组(1-20)"),
26518
- paths: withDescription(stringArray, "[upsert_route/update_route] 路径列表,逗号分隔或 JSON 数组(1-20)"),
26539
+ paths: withDescription(stringArray, "[upsert_route/update_route] 路径列表,逗号分隔或 JSON 数组(1-32)"),
26519
26540
  upstream: optional(Type.String(), "[upsert_route/update_route] 反代上游 host:port 或 http(s)://host[:port]"),
26541
+ managed_upstream: optional(stringEnum(["edge-functions"]), "[upsert_route/update_route] 托管上游(同步 Edge Function)"),
26520
26542
  upstream_tls_insecure_skip_verify: optional(Type.Boolean(), "[upsert_route/update_route] 上游 TLS 跳过校验"),
26521
26543
  static_root: optional(Type.String(), "[upsert_route/update_route] 静态站点根目录"),
26522
26544
  protocol: optional(stringEnum(["http", "https"]), "[upsert_route/update_route] 可选请求协议匹配"),
@@ -26562,6 +26584,7 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
26562
26584
  hosts,
26563
26585
  paths,
26564
26586
  upstream,
26587
+ managed_upstream,
26565
26588
  upstream_tls_insecure_skip_verify,
26566
26589
  static_root,
26567
26590
  protocol,
@@ -26607,6 +26630,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
26607
26630
  };
26608
26631
  if (upstream !== undefined)
26609
26632
  body.upstream = upstream;
26633
+ if (managed_upstream !== undefined)
26634
+ body.managed_upstream = managed_upstream;
26610
26635
  if (upstream_tls_insecure_skip_verify !== undefined)
26611
26636
  body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
26612
26637
  if (static_root !== undefined)
@@ -26642,6 +26667,8 @@ Actions: routes, upsert_route, update_route, delete_route, config, get_certifica
26642
26667
  };
26643
26668
  if (upstream !== undefined)
26644
26669
  body.upstream = upstream;
26670
+ if (managed_upstream !== undefined)
26671
+ body.managed_upstream = managed_upstream;
26645
26672
  if (upstream_tls_insecure_skip_verify !== undefined)
26646
26673
  body.upstream_tls_insecure_skip_verify = upstream_tls_insecure_skip_verify;
26647
26674
  if (static_root !== undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/admin",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Platform administration CLI for SupaCloud operators",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",