@supacloud/cli 0.14.1 → 0.14.3
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 +67 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6335,29 +6335,46 @@ function resolveSupaCloudContext(env = process.env, cwd = process.cwd()) {
|
|
|
6335
6335
|
var DEFAULT_TIMEOUT = 30000;
|
|
6336
6336
|
var MAX_RETRIES = 2;
|
|
6337
6337
|
var RETRY_BASE_DELAY = 500;
|
|
6338
|
-
|
|
6338
|
+
function isRetryableMethod(method) {
|
|
6339
|
+
const normalizedMethod = (method ?? "GET").toUpperCase();
|
|
6340
|
+
return normalizedMethod === "GET" || normalizedMethod === "HEAD";
|
|
6341
|
+
}
|
|
6342
|
+
function isRetryableError(error) {
|
|
6343
|
+
if (!(error instanceof Error))
|
|
6344
|
+
return false;
|
|
6345
|
+
const networkError = error;
|
|
6346
|
+
return networkError.name === "AbortError" || networkError.code === "ECONNREFUSED" || networkError.code === "ECONNRESET";
|
|
6347
|
+
}
|
|
6348
|
+
async function fetchWithTimeout(url, options) {
|
|
6349
|
+
const controller = new AbortController;
|
|
6350
|
+
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
|
|
6351
|
+
try {
|
|
6352
|
+
return await fetch(url, {
|
|
6353
|
+
...options,
|
|
6354
|
+
signal: controller.signal
|
|
6355
|
+
});
|
|
6356
|
+
} finally {
|
|
6357
|
+
clearTimeout(timeout);
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
async function fetchWithRetry(url, options) {
|
|
6361
|
+
const retries = isRetryableMethod(options.method) ? MAX_RETRIES : 0;
|
|
6339
6362
|
for (let attempt = 0;attempt <= retries; attempt++) {
|
|
6340
6363
|
try {
|
|
6341
|
-
const
|
|
6342
|
-
|
|
6343
|
-
const res = await fetch(url, {
|
|
6344
|
-
...options,
|
|
6345
|
-
signal: controller.signal
|
|
6346
|
-
});
|
|
6347
|
-
clearTimeout(timeout);
|
|
6348
|
-
if (res.status >= 500 && attempt < retries) {
|
|
6364
|
+
const res = await fetchWithTimeout(url, options);
|
|
6365
|
+
if (res.status >= 500 && res.status < 600 && attempt < retries) {
|
|
6349
6366
|
const delay = RETRY_BASE_DELAY * Math.pow(2, attempt);
|
|
6350
6367
|
await new Promise((r) => setTimeout(r, delay));
|
|
6351
6368
|
continue;
|
|
6352
6369
|
}
|
|
6353
6370
|
return res;
|
|
6354
|
-
} catch (
|
|
6355
|
-
if (attempt < retries && (
|
|
6371
|
+
} catch (error) {
|
|
6372
|
+
if (attempt < retries && isRetryableError(error)) {
|
|
6356
6373
|
const delay = RETRY_BASE_DELAY * Math.pow(2, attempt);
|
|
6357
6374
|
await new Promise((r) => setTimeout(r, delay));
|
|
6358
6375
|
continue;
|
|
6359
6376
|
}
|
|
6360
|
-
throw
|
|
6377
|
+
throw error;
|
|
6361
6378
|
}
|
|
6362
6379
|
}
|
|
6363
6380
|
throw new Error("Unreachable");
|
|
@@ -7534,6 +7551,20 @@ function parseSecrets(value) {
|
|
|
7534
7551
|
}).filter((entry) => entry.name);
|
|
7535
7552
|
}
|
|
7536
7553
|
var secretsSchema = Type.Optional(decodedSchema(Type.Union([Type.String(), secretListSchema]), secretListSchema, parseSecrets));
|
|
7554
|
+
function confirmedFunctionConfig(payload, expected) {
|
|
7555
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
7556
|
+
return false;
|
|
7557
|
+
const response = payload;
|
|
7558
|
+
if (expected.verify_jwt !== undefined && response.verify_jwt !== expected.verify_jwt)
|
|
7559
|
+
return false;
|
|
7560
|
+
if (expected.background_routes !== undefined) {
|
|
7561
|
+
if (!Array.isArray(response.background_routes))
|
|
7562
|
+
return false;
|
|
7563
|
+
if (JSON.stringify(response.background_routes) !== JSON.stringify(expected.background_routes))
|
|
7564
|
+
return false;
|
|
7565
|
+
}
|
|
7566
|
+
return true;
|
|
7567
|
+
}
|
|
7537
7568
|
function registerAdvancedTools(server, http) {
|
|
7538
7569
|
server.tool("edge_functions", `Edge Function management (Deno/Bun serverless). Server auto-bundles dependencies.
|
|
7539
7570
|
Actions: list, deploy, deploy_bundle, config, source, delete, check`, {
|
|
@@ -7568,6 +7599,17 @@ Actions: list, deploy, deploy_bundle, config, source, delete, check`, {
|
|
|
7568
7599
|
const cr = await http.patch(`/v1/projects/${ref}/functions/${slug}/config`, functionConfig());
|
|
7569
7600
|
return cr.ok ? `✅ Function ${slug} config updated
|
|
7570
7601
|
${JSON.stringify(cr.data, null, 2)}` : `❌ Config update failed (${cr.status}): ${JSON.stringify(cr.data)}`;
|
|
7602
|
+
};
|
|
7603
|
+
const confirmedDeploymentText = async (successText, responsePayload) => {
|
|
7604
|
+
if (!hasFunctionConfig() || confirmedFunctionConfig(responsePayload, functionConfig())) {
|
|
7605
|
+
return successText;
|
|
7606
|
+
}
|
|
7607
|
+
const fallback = await http.patch(`/v1/projects/${ref}/functions/${slug}/config`, functionConfig());
|
|
7608
|
+
if (!fallback.ok || !confirmedFunctionConfig(fallback.data, functionConfig())) {
|
|
7609
|
+
return `❌ Partial deployment (unsafe): POST succeeded and the code/bundle was deployed, but the function policy was not confirmed; legacy PATCH fallback failed (${fallback.status}): ${JSON.stringify(fallback.data)}`;
|
|
7610
|
+
}
|
|
7611
|
+
return `${successText}
|
|
7612
|
+
⚠️ Legacy non-atomic compatibility path: policy applied with follow-up PATCH`;
|
|
7571
7613
|
};
|
|
7572
7614
|
const checkSyntax = async (sourceCode) => {
|
|
7573
7615
|
const tmpDir = mkdtempSync(join2(tmpdir(), "supacloud-edge-check-"));
|
|
@@ -7613,24 +7655,31 @@ ${checkRes.err}`;
|
|
|
7613
7655
|
${deployCheck.err}`;
|
|
7614
7656
|
break;
|
|
7615
7657
|
}
|
|
7616
|
-
const dr = await http.post(`/v1/projects/${ref}/functions/${slug}`, {
|
|
7658
|
+
const dr = await http.post(`/v1/projects/${ref}/functions/${slug}`, {
|
|
7659
|
+
code,
|
|
7660
|
+
minify,
|
|
7661
|
+
...functionConfig()
|
|
7662
|
+
});
|
|
7617
7663
|
if (!dr.ok) {
|
|
7618
7664
|
text = `❌ Failed (${dr.status}): ${JSON.stringify(dr.data)}`;
|
|
7619
7665
|
break;
|
|
7620
7666
|
}
|
|
7621
|
-
text =
|
|
7622
|
-
${await updateFunctionConfig()}` : `✅ Function ${slug} deployed`;
|
|
7667
|
+
text = await confirmedDeploymentText(`✅ Function ${slug} deployed`, dr.data);
|
|
7623
7668
|
break;
|
|
7624
7669
|
case "deploy_bundle":
|
|
7625
7670
|
need("slug", slug);
|
|
7626
7671
|
need("files", files);
|
|
7627
|
-
const br = await http.post(`/v1/projects/${ref}/functions/${slug}/bundle`, {
|
|
7672
|
+
const br = await http.post(`/v1/projects/${ref}/functions/${slug}/bundle`, {
|
|
7673
|
+
files,
|
|
7674
|
+
entrypoint,
|
|
7675
|
+
minify,
|
|
7676
|
+
...functionConfig()
|
|
7677
|
+
});
|
|
7628
7678
|
if (!br.ok) {
|
|
7629
7679
|
text = `❌ Failed (${br.status}): ${JSON.stringify(br.data)}`;
|
|
7630
7680
|
break;
|
|
7631
7681
|
}
|
|
7632
|
-
text =
|
|
7633
|
-
${await updateFunctionConfig()}` : `✅ Function ${slug} bundle deployed (${Object.keys(files).length} files)`;
|
|
7682
|
+
text = await confirmedDeploymentText(`✅ Function ${slug} bundle deployed (${Object.keys(files).length} files)`, br.data);
|
|
7634
7683
|
break;
|
|
7635
7684
|
case "config":
|
|
7636
7685
|
text = await updateFunctionConfig();
|