@supacloud/cli 0.14.2 → 0.14.4
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/README.md +12 -0
- package/dist/index.js +90 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,8 +68,20 @@ supacloud-cli frontend list --ref abc123
|
|
|
68
68
|
supacloud-cli branch create --name feature-orders --data_mode schema_only
|
|
69
69
|
supacloud-cli branch promotion_plan --branch_ref preview123
|
|
70
70
|
supacloud-cli branch promote --branch_ref preview123 --plan_checksum <sha256>
|
|
71
|
+
supacloud-cli edge_functions deploy --ref abc123 --slug hello --path ./supabase/functions/hello
|
|
72
|
+
supacloud-cli edge_functions deploy_bundle --ref abc123 --slug hello --files '{"index.ts":"export default { fetch: () => new Response(\"ok\") }"}'
|
|
73
|
+
supacloud-cli edge_functions source --ref abc123 --slug hello --output ./hello.ts
|
|
71
74
|
```
|
|
72
75
|
|
|
76
|
+
`edge_functions deploy --path` bundles local TypeScript and dependencies with
|
|
77
|
+
Bun and runs a local syntax check before upload. The Management API validates and
|
|
78
|
+
normalizes the final server-side artifact against the multi-tenant Edge Runtime
|
|
79
|
+
module policy consistently for CLI, Web Console, and direct API deployments.
|
|
80
|
+
`deploy_bundle --files` accepts a JSON object in shell usage.
|
|
81
|
+
Use `source --output <file>` for large Functions so terminal or automation output
|
|
82
|
+
limits cannot truncate the original TS/JS source code. The destination must not
|
|
83
|
+
already exist.
|
|
84
|
+
|
|
73
85
|
Branch promotion is migration-first. `branch promotion_plan` prints pending
|
|
74
86
|
versions, names, statement counts, and checksums without echoing SQL into terminal
|
|
75
87
|
logs; review the migration files or the Web Console SQL view before approval.
|
package/dist/index.js
CHANGED
|
@@ -6155,15 +6155,18 @@ async function runCli(cliTools, args, options = {}) {
|
|
|
6155
6155
|
console.error(`❌ Unknown command: ${toolName}`);
|
|
6156
6156
|
console.error(`Available commands:
|
|
6157
6157
|
${formatAvailableCommands()}`);
|
|
6158
|
-
process.
|
|
6158
|
+
process.exitCode = 1;
|
|
6159
|
+
return;
|
|
6159
6160
|
}
|
|
6160
6161
|
if (args.length === 1 || args[1] === "--help" || args[1] === "-h") {
|
|
6161
6162
|
console.error(formatToolHelp(toolName, tool));
|
|
6162
|
-
process.
|
|
6163
|
+
process.exitCode = 0;
|
|
6164
|
+
return;
|
|
6163
6165
|
}
|
|
6164
6166
|
if (args.length > 2 && !args[1].startsWith("--") && (args[2] === "--help" || args[2] === "-h")) {
|
|
6165
6167
|
console.error(formatActionHelp(toolName, args[1], tool));
|
|
6166
|
-
process.
|
|
6168
|
+
process.exitCode = 0;
|
|
6169
|
+
return;
|
|
6167
6170
|
}
|
|
6168
6171
|
const parsedArgs = {};
|
|
6169
6172
|
let startIdx = 1;
|
|
@@ -6198,14 +6201,14 @@ async function runCli(cliTools, args, options = {}) {
|
|
|
6198
6201
|
} else {
|
|
6199
6202
|
console.log(JSON.stringify(result, null, 2));
|
|
6200
6203
|
}
|
|
6201
|
-
process.
|
|
6204
|
+
process.exitCode = cliToolResultIsError(result) ? 1 : 0;
|
|
6202
6205
|
} catch (error) {
|
|
6203
6206
|
const message = error instanceof Error ? error.message : String(error);
|
|
6204
6207
|
console.error(`❌ Error: ${message}`);
|
|
6205
6208
|
if (message.includes("required")) {
|
|
6206
6209
|
console.error(`Hint: Pass arguments like --ref YOUR_REF`);
|
|
6207
6210
|
}
|
|
6208
|
-
process.
|
|
6211
|
+
process.exitCode = 1;
|
|
6209
6212
|
}
|
|
6210
6213
|
}
|
|
6211
6214
|
|
|
@@ -7524,6 +7527,19 @@ function parseBackgroundRoutes(value) {
|
|
|
7524
7527
|
}
|
|
7525
7528
|
}
|
|
7526
7529
|
var backgroundRoutesSchema = Type.Optional(decodedSchema(Type.Union([Type.String(), Type.Array(Type.String())]), Type.Array(Type.String()), parseBackgroundRoutes));
|
|
7530
|
+
var functionFilesRecordSchema = Type.Record(Type.String(), Type.String());
|
|
7531
|
+
function parseFunctionFiles(input) {
|
|
7532
|
+
if (typeof input !== "string")
|
|
7533
|
+
return input;
|
|
7534
|
+
try {
|
|
7535
|
+
return JSON.parse(input);
|
|
7536
|
+
} catch (error) {
|
|
7537
|
+
if (!(error instanceof SyntaxError))
|
|
7538
|
+
throw error;
|
|
7539
|
+
throw new Error("Invalid files JSON object");
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7542
|
+
var functionFilesSchema = decodedSchema(Type.Union([Type.String(), functionFilesRecordSchema]), functionFilesRecordSchema, parseFunctionFiles);
|
|
7527
7543
|
var secretListSchema = Type.Array(Type.Object({ name: Type.String(), value: Type.String() }));
|
|
7528
7544
|
function parseSecrets(value) {
|
|
7529
7545
|
if (Array.isArray(value))
|
|
@@ -7551,6 +7567,26 @@ function parseSecrets(value) {
|
|
|
7551
7567
|
}).filter((entry) => entry.name);
|
|
7552
7568
|
}
|
|
7553
7569
|
var secretsSchema = Type.Optional(decodedSchema(Type.Union([Type.String(), secretListSchema]), secretListSchema, parseSecrets));
|
|
7570
|
+
function confirmedFunctionConfig(payload, expected) {
|
|
7571
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
7572
|
+
return false;
|
|
7573
|
+
const response = payload;
|
|
7574
|
+
if (expected.verify_jwt !== undefined && response.verify_jwt !== expected.verify_jwt)
|
|
7575
|
+
return false;
|
|
7576
|
+
if (expected.background_routes !== undefined) {
|
|
7577
|
+
if (!Array.isArray(response.background_routes))
|
|
7578
|
+
return false;
|
|
7579
|
+
if (JSON.stringify(response.background_routes) !== JSON.stringify(expected.background_routes))
|
|
7580
|
+
return false;
|
|
7581
|
+
}
|
|
7582
|
+
return true;
|
|
7583
|
+
}
|
|
7584
|
+
function functionSourceCode(payload) {
|
|
7585
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
7586
|
+
return null;
|
|
7587
|
+
const code = payload.code;
|
|
7588
|
+
return typeof code === "string" ? code : null;
|
|
7589
|
+
}
|
|
7554
7590
|
function registerAdvancedTools(server, http) {
|
|
7555
7591
|
server.tool("edge_functions", `Edge Function management (Deno/Bun serverless). Server auto-bundles dependencies.
|
|
7556
7592
|
Actions: list, deploy, deploy_bundle, config, source, delete, check`, {
|
|
@@ -7559,13 +7595,14 @@ Actions: list, deploy, deploy_bundle, config, source, delete, check`, {
|
|
|
7559
7595
|
slug: optional(Type.String(), "[deploy/deploy_bundle/config/source/delete/check] Function name"),
|
|
7560
7596
|
code: optional(Type.String(), "[deploy/check] Function source code (TypeScript)"),
|
|
7561
7597
|
path: optional(Type.String(), "[deploy/check] Local file path to read code from (alternative to code)"),
|
|
7562
|
-
|
|
7598
|
+
output: optional(Type.String(), "[source] Write source to this local file instead of stdout; the file must not already exist"),
|
|
7599
|
+
files: optional(functionFilesSchema, "[deploy_bundle] File map as a JSON object: { 'index.ts': '...', '_shared/x.ts': '...' }"),
|
|
7563
7600
|
entrypoint: optional(Type.String(), "[deploy_bundle] Entrypoint file (default: index.ts)"),
|
|
7564
7601
|
minify: optional(Type.Boolean(), "[deploy/deploy_bundle] Minify bundle"),
|
|
7565
7602
|
verify_jwt: optional(Type.Boolean(), "[deploy/deploy_bundle/config] Set JWT verification for this function"),
|
|
7566
7603
|
background_routes: withDescription(backgroundRoutesSchema, "[deploy/deploy_bundle/config] Background route paths; pass comma-separated or JSON array in CLI")
|
|
7567
7604
|
}, async (args) => {
|
|
7568
|
-
const { action, ref, slug, path: pathArg, files, entrypoint, minify, verify_jwt, background_routes } = args;
|
|
7605
|
+
const { action, ref, slug, path: pathArg, output, files, entrypoint, minify, verify_jwt, background_routes } = args;
|
|
7569
7606
|
let code = args.code;
|
|
7570
7607
|
const need = (f, v) => {
|
|
7571
7608
|
if (!v)
|
|
@@ -7585,6 +7622,17 @@ Actions: list, deploy, deploy_bundle, config, source, delete, check`, {
|
|
|
7585
7622
|
const cr = await http.patch(`/v1/projects/${ref}/functions/${slug}/config`, functionConfig());
|
|
7586
7623
|
return cr.ok ? `✅ Function ${slug} config updated
|
|
7587
7624
|
${JSON.stringify(cr.data, null, 2)}` : `❌ Config update failed (${cr.status}): ${JSON.stringify(cr.data)}`;
|
|
7625
|
+
};
|
|
7626
|
+
const confirmedDeploymentText = async (successText, responsePayload) => {
|
|
7627
|
+
if (!hasFunctionConfig() || confirmedFunctionConfig(responsePayload, functionConfig())) {
|
|
7628
|
+
return successText;
|
|
7629
|
+
}
|
|
7630
|
+
const fallback = await http.patch(`/v1/projects/${ref}/functions/${slug}/config`, functionConfig());
|
|
7631
|
+
if (!fallback.ok || !confirmedFunctionConfig(fallback.data, functionConfig())) {
|
|
7632
|
+
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)}`;
|
|
7633
|
+
}
|
|
7634
|
+
return `${successText}
|
|
7635
|
+
⚠️ Legacy non-atomic compatibility path: policy applied with follow-up PATCH`;
|
|
7588
7636
|
};
|
|
7589
7637
|
const checkSyntax = async (sourceCode) => {
|
|
7590
7638
|
const tmpDir = mkdtempSync(join2(tmpdir(), "supacloud-edge-check-"));
|
|
@@ -7603,8 +7651,9 @@ ${e.stderr || e.message}` };
|
|
|
7603
7651
|
if (pathArg && !code) {
|
|
7604
7652
|
try {
|
|
7605
7653
|
code = await bundleEdgeFunctionPath(pathArg);
|
|
7606
|
-
} catch (
|
|
7607
|
-
|
|
7654
|
+
} catch (error) {
|
|
7655
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
7656
|
+
throw new Error(`Failed to bundle/read path ${pathArg}: ${message}`);
|
|
7608
7657
|
}
|
|
7609
7658
|
}
|
|
7610
7659
|
switch (action) {
|
|
@@ -7630,24 +7679,31 @@ ${checkRes.err}`;
|
|
|
7630
7679
|
${deployCheck.err}`;
|
|
7631
7680
|
break;
|
|
7632
7681
|
}
|
|
7633
|
-
const dr = await http.post(`/v1/projects/${ref}/functions/${slug}`, {
|
|
7682
|
+
const dr = await http.post(`/v1/projects/${ref}/functions/${slug}`, {
|
|
7683
|
+
code,
|
|
7684
|
+
minify,
|
|
7685
|
+
...functionConfig()
|
|
7686
|
+
});
|
|
7634
7687
|
if (!dr.ok) {
|
|
7635
7688
|
text = `❌ Failed (${dr.status}): ${JSON.stringify(dr.data)}`;
|
|
7636
7689
|
break;
|
|
7637
7690
|
}
|
|
7638
|
-
text =
|
|
7639
|
-
${await updateFunctionConfig()}` : `✅ Function ${slug} deployed`;
|
|
7691
|
+
text = await confirmedDeploymentText(`✅ Function ${slug} deployed`, dr.data);
|
|
7640
7692
|
break;
|
|
7641
7693
|
case "deploy_bundle":
|
|
7642
7694
|
need("slug", slug);
|
|
7643
7695
|
need("files", files);
|
|
7644
|
-
const br = await http.post(`/v1/projects/${ref}/functions/${slug}/bundle`, {
|
|
7696
|
+
const br = await http.post(`/v1/projects/${ref}/functions/${slug}/bundle`, {
|
|
7697
|
+
files,
|
|
7698
|
+
entrypoint,
|
|
7699
|
+
minify,
|
|
7700
|
+
...functionConfig()
|
|
7701
|
+
});
|
|
7645
7702
|
if (!br.ok) {
|
|
7646
7703
|
text = `❌ Failed (${br.status}): ${JSON.stringify(br.data)}`;
|
|
7647
7704
|
break;
|
|
7648
7705
|
}
|
|
7649
|
-
text =
|
|
7650
|
-
${await updateFunctionConfig()}` : `✅ Function ${slug} bundle deployed (${Object.keys(files).length} files)`;
|
|
7706
|
+
text = await confirmedDeploymentText(`✅ Function ${slug} bundle deployed (${Object.keys(files).length} files)`, br.data);
|
|
7651
7707
|
break;
|
|
7652
7708
|
case "config":
|
|
7653
7709
|
text = await updateFunctionConfig();
|
|
@@ -7655,7 +7711,22 @@ ${await updateFunctionConfig()}` : `✅ Function ${slug} bundle deployed (${Obje
|
|
|
7655
7711
|
case "source":
|
|
7656
7712
|
need("slug", slug);
|
|
7657
7713
|
const sr = await http.get(`/v1/projects/${ref}/functions/${slug}/source`);
|
|
7658
|
-
|
|
7714
|
+
if (!sr.ok) {
|
|
7715
|
+
text = `❌ Not found (${sr.status})`;
|
|
7716
|
+
break;
|
|
7717
|
+
}
|
|
7718
|
+
if (!output) {
|
|
7719
|
+
text = JSON.stringify(sr.data, null, 2);
|
|
7720
|
+
break;
|
|
7721
|
+
}
|
|
7722
|
+
const sourceCode = functionSourceCode(sr.data);
|
|
7723
|
+
if (sourceCode === null) {
|
|
7724
|
+
text = "❌ Source response did not contain a string code field";
|
|
7725
|
+
break;
|
|
7726
|
+
}
|
|
7727
|
+
const outputPath = resolve2(output);
|
|
7728
|
+
writeFileSync(outputPath, sourceCode, { flag: "wx" });
|
|
7729
|
+
text = `✅ Function ${slug} source written to ${outputPath} (${Buffer.byteLength(sourceCode)} bytes)`;
|
|
7659
7730
|
break;
|
|
7660
7731
|
case "delete":
|
|
7661
7732
|
need("slug", slug);
|
|
@@ -9840,7 +9911,8 @@ async function main() {
|
|
|
9840
9911
|
const args = process.argv.slice(2);
|
|
9841
9912
|
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
9842
9913
|
printHelp();
|
|
9843
|
-
process.
|
|
9914
|
+
process.exitCode = 0;
|
|
9915
|
+
return;
|
|
9844
9916
|
}
|
|
9845
9917
|
const cliTools = createCliTools();
|
|
9846
9918
|
if (args.length === 1 && !["ai", "supabase"].includes(args[0]) && cliTools[args[0]]) {
|
|
@@ -9862,5 +9934,5 @@ async function main() {
|
|
|
9862
9934
|
}
|
|
9863
9935
|
main().catch((error) => {
|
|
9864
9936
|
console.error(`${commandName} failed:`, error);
|
|
9865
|
-
process.
|
|
9937
|
+
process.exitCode = 1;
|
|
9866
9938
|
});
|