@supacloud/cli 0.35.0 → 0.36.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 +133 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6503,7 +6503,7 @@ var ACTION_POLICY = {
6503
6503
  },
6504
6504
  edge_functions: {
6505
6505
  read: ["list", "get_config", "source"],
6506
- local: ["check"],
6506
+ local: ["check", "scaffold"],
6507
6507
  write: ["deploy", "deploy_bundle", "config", "activate", "delete"]
6508
6508
  },
6509
6509
  scheduled_functions: { read: ["list", "get"], write: ["create", "update", "delete"] },
@@ -10069,6 +10069,7 @@ import {
10069
10069
  existsSync as existsSync3,
10070
10070
  fstatSync,
10071
10071
  lstatSync,
10072
+ mkdirSync,
10072
10073
  mkdtempSync,
10073
10074
  openSync,
10074
10075
  readFileSync as readFileSync3,
@@ -10087,13 +10088,15 @@ var CANONICAL_VERSION_PATTERN = /^(?:0|[1-9][0-9]*)$/;
10087
10088
  var SAFE_SLUG_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
10088
10089
  var ACTIVATION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
10089
10090
  var LEGACY_ACTIVATION_ID = "legacy";
10091
+ var FUNCTION_FRAMEWORKS = ["fetch", "elysia", "hono", "sveltekit-function"];
10090
10092
  var LIST_STRING_FIELDS = [
10091
10093
  "id",
10092
10094
  "name",
10093
10095
  "status",
10094
10096
  "entrypoint_path",
10095
10097
  "created_at",
10096
- "updated_at"
10098
+ "updated_at",
10099
+ "framework"
10097
10100
  ];
10098
10101
  var LIST_BOOLEAN_FIELDS = ["verify_jwt", "import_map"];
10099
10102
  function objectRecord(candidate) {
@@ -10116,7 +10119,7 @@ function validCommittedFunctionActivationId(candidate) {
10116
10119
  }
10117
10120
  function projectedFunctionListEntry(candidate) {
10118
10121
  const functionRecord = objectRecord(candidate);
10119
- if (!functionRecord || typeof functionRecord.slug !== "string" || !SAFE_SLUG_PATTERN.test(functionRecord.slug) || typeof functionRecord.version !== "number" || !Number.isSafeInteger(functionRecord.version) || functionRecord.version < 0 || !validObservedFunctionActivationId(functionRecord.activation_id) || !optionalTypedFields(functionRecord, LIST_STRING_FIELDS, "string") || !optionalTypedFields(functionRecord, LIST_BOOLEAN_FIELDS, "boolean") || functionRecord.background_routes !== undefined && !stringRoutes(functionRecord.background_routes))
10122
+ if (!functionRecord || typeof functionRecord.slug !== "string" || !SAFE_SLUG_PATTERN.test(functionRecord.slug) || typeof functionRecord.version !== "number" || !Number.isSafeInteger(functionRecord.version) || functionRecord.version < 0 || !validObservedFunctionActivationId(functionRecord.activation_id) || !optionalTypedFields(functionRecord, LIST_STRING_FIELDS, "string") || !optionalTypedFields(functionRecord, LIST_BOOLEAN_FIELDS, "boolean") || functionRecord.framework !== undefined && !FUNCTION_FRAMEWORKS.includes(functionRecord.framework) || functionRecord.background_routes !== undefined && !stringRoutes(functionRecord.background_routes))
10120
10123
  return null;
10121
10124
  const projected = {
10122
10125
  slug: functionRecord.slug,
@@ -10176,12 +10179,16 @@ function projectedFunctionIdentity(payload, expectedProjectRef, expectedSlug) {
10176
10179
  const optionalFields = optionalConfigFields(response);
10177
10180
  if (!optionalFields || !coherentFunctionVersion(response.active_version, optionalFields.version))
10178
10181
  return null;
10182
+ const framework = response.framework;
10183
+ if (framework !== undefined && !FUNCTION_FRAMEWORKS.includes(framework))
10184
+ return null;
10179
10185
  return {
10180
10186
  project_ref: expectedProjectRef,
10181
10187
  slug: expectedSlug,
10182
10188
  active_version: response.active_version,
10183
10189
  verify_jwt: response.verify_jwt,
10184
10190
  background_routes: response.background_routes,
10191
+ ...framework === undefined ? {} : { framework },
10185
10192
  ...optionalFields,
10186
10193
  activation_id: response.activation_id
10187
10194
  };
@@ -10193,8 +10200,12 @@ function configMatchesExpectation(response, expected) {
10193
10200
  if (typeof response.verify_jwt !== "boolean" || !stringRoutes(response.background_routes)) {
10194
10201
  return false;
10195
10202
  }
10203
+ if (response.framework !== undefined && !FUNCTION_FRAMEWORKS.includes(response.framework))
10204
+ return false;
10196
10205
  if (expected.verify_jwt !== undefined && response.verify_jwt !== expected.verify_jwt)
10197
10206
  return false;
10207
+ if (expected.framework !== undefined && response.framework !== expected.framework)
10208
+ return false;
10198
10209
  return expected.background_routes === undefined || JSON.stringify(response.background_routes) === JSON.stringify(expected.background_routes);
10199
10210
  }
10200
10211
  function confirmedFunctionConfigMutation(payload, expectation) {
@@ -10211,6 +10222,7 @@ function confirmedFunctionConfigMutation(payload, expectation) {
10211
10222
  activation_id: response.activation_id,
10212
10223
  verify_jwt: response.verify_jwt,
10213
10224
  background_routes: response.background_routes,
10225
+ ...response.framework === undefined ? {} : { framework: response.framework },
10214
10226
  ...optionalFields
10215
10227
  };
10216
10228
  }
@@ -10233,6 +10245,93 @@ function confirmedFunctionDeletion(payload, expectation) {
10233
10245
  var execFileAsync = promisify(execFile);
10234
10246
  var SHA256_HEX_PATTERN = /^[a-f0-9]{64}$/;
10235
10247
  var FORBIDDEN_BUNDLE_SEGMENTS = new Set(["node_modules", ".git"]);
10248
+ var FUNCTION_FRAMEWORKS2 = ["fetch", "elysia", "hono", "sveltekit-function"];
10249
+ function scaffoldFiles(framework, slug) {
10250
+ if (framework === "elysia") {
10251
+ return {
10252
+ "package.json": JSON.stringify({
10253
+ private: true,
10254
+ type: "module",
10255
+ dependencies: { elysia: "^1.4.30" }
10256
+ }, null, 2) + `
10257
+ `,
10258
+ "index.ts": `import { Elysia } from "elysia";
10259
+
10260
+ export default new Elysia()
10261
+ .get("/", () => ({ function: "${slug}", framework: "elysia" }));
10262
+ `
10263
+ };
10264
+ }
10265
+ if (framework === "hono") {
10266
+ return {
10267
+ "package.json": JSON.stringify({
10268
+ private: true,
10269
+ type: "module",
10270
+ dependencies: { hono: "^4.13.5" }
10271
+ }, null, 2) + `
10272
+ `,
10273
+ "index.ts": `import { Hono } from "hono";
10274
+
10275
+ const app = new Hono();
10276
+ app.get("/", (context) => context.json({ function: "${slug}", framework: "hono" }));
10277
+
10278
+ export default app;
10279
+ `
10280
+ };
10281
+ }
10282
+ if (framework === "sveltekit-function") {
10283
+ return {
10284
+ "package.json": JSON.stringify({
10285
+ private: true,
10286
+ type: "module",
10287
+ scripts: { build: "vite build" },
10288
+ devDependencies: {
10289
+ "@supacloud/function-adapter": "^0.1.0",
10290
+ "@sveltejs/kit": "^2.70.3",
10291
+ "@sveltejs/vite-plugin-svelte": "^7.3.0",
10292
+ svelte: "^5.57.0",
10293
+ vite: "^8.2.2"
10294
+ }
10295
+ }, null, 2) + `
10296
+ `,
10297
+ "svelte.config.js": `import adapter from "@supacloud/function-adapter/sveltekit-adapter";
10298
+
10299
+ export default { kit: { adapter: adapter() } };
10300
+ `,
10301
+ "vite.config.ts": `import { sveltekit } from "@sveltejs/kit/vite";
10302
+ import { defineConfig } from "vite";
10303
+
10304
+ export default defineConfig({ plugins: [sveltekit()] });
10305
+ `,
10306
+ "src/routes/+server.ts": `export function GET() {
10307
+ return Response.json({ function: "${slug}", framework: "sveltekit-function" });
10308
+ }
10309
+ `
10310
+ };
10311
+ }
10312
+ return { "index.ts": `export default function handler(request: Request) {
10313
+ return Response.json({ function: "${slug}", path: new URL(request.url).pathname });
10314
+ }
10315
+ ` };
10316
+ }
10317
+ function scaffoldFunction(pathArg, slug, framework) {
10318
+ if (typeof slug !== "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(slug)) {
10319
+ throw new Error("'slug' required for 'scaffold'");
10320
+ }
10321
+ if (typeof framework !== "string" || !FUNCTION_FRAMEWORKS2.includes(framework)) {
10322
+ throw new Error("'framework' required for 'scaffold'");
10323
+ }
10324
+ const target = resolve2(typeof pathArg === "string" ? pathArg : join2("supabase", "functions", slug));
10325
+ if (existsSync3(target))
10326
+ throw new Error(`Scaffold target already exists: ${target}`);
10327
+ const files = scaffoldFiles(framework, slug);
10328
+ for (const [relativePath, contents] of Object.entries(files)) {
10329
+ const destination = join2(target, relativePath);
10330
+ mkdirSync(resolve2(destination, ".."), { recursive: true });
10331
+ writeFileSync(destination, contents, { flag: "wx" });
10332
+ }
10333
+ return JSON.stringify({ success: true, framework, path: target, files: Object.keys(files) }, null, 2);
10334
+ }
10236
10335
  function openFileIdentity(descriptor) {
10237
10336
  const state = fstatSync(descriptor, { bigint: true });
10238
10337
  if (!state.isFile())
@@ -10648,6 +10747,8 @@ function confirmedFunctionConfig(payload, expected) {
10648
10747
  return false;
10649
10748
  if (expected.verify_jwt !== undefined && response.verify_jwt !== expected.verify_jwt)
10650
10749
  return false;
10750
+ if (expected.framework !== undefined && response.framework !== expected.framework)
10751
+ return false;
10651
10752
  if (expected.background_routes !== undefined) {
10652
10753
  if (!Array.isArray(response.background_routes))
10653
10754
  return false;
@@ -10745,7 +10846,16 @@ function confirmedFunctionMutation(expectation, payload) {
10745
10846
  const activationId = receipt.activation_id;
10746
10847
  if (activeVersion === null || !validCommittedFunctionActivationId(activationId) || config.activation_id !== activationId || typeof config.verify_jwt !== "boolean" || !confirmedFunctionConfig(config, expectation.config ?? {}))
10747
10848
  return null;
10748
- return { activeVersion, activationId, verifyJwt: config.verify_jwt };
10849
+ const framework = config.framework;
10850
+ if (framework !== undefined && (typeof framework !== "string" || !FUNCTION_FRAMEWORKS2.includes(framework))) {
10851
+ return null;
10852
+ }
10853
+ return {
10854
+ activeVersion,
10855
+ activationId,
10856
+ verifyJwt: config.verify_jwt,
10857
+ ...framework === undefined ? {} : { framework }
10858
+ };
10749
10859
  }
10750
10860
  function functionMutationResponse(expectation, response) {
10751
10861
  if (!response.ok)
@@ -10762,7 +10872,8 @@ function functionMutationResponse(expectation, response) {
10762
10872
  activation_id: confirmed.activationId,
10763
10873
  active_version: confirmed.activeVersion,
10764
10874
  version: confirmed.activeVersion,
10765
- verify_jwt: confirmed.verifyJwt
10875
+ verify_jwt: confirmed.verifyJwt,
10876
+ ...confirmed.framework === undefined ? {} : { framework: confirmed.framework }
10766
10877
  });
10767
10878
  }
10768
10879
  function readOnlyActivationResult() {
@@ -10824,13 +10935,13 @@ async function activateFunctionVersion(http, args, readOnly = false) {
10824
10935
  }
10825
10936
  function registerAdvancedTools(server, http, environment = process.env, options = {}) {
10826
10937
  server.tool("edge_functions", `Edge Function management (Deno/Bun serverless). Source deploys are bundled; verified prebuilt artifacts stay byte-exact.
10827
- Actions: list, get_config, deploy, deploy_bundle, config, source, activate, delete, check`, {
10828
- action: withDescription(stringEnum(["list", "get_config", "deploy", "deploy_bundle", "config", "source", "activate", "delete", "check"]), "Action"),
10829
- ref: withDescription(Type.String(), "Project ref"),
10938
+ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, delete, check, scaffold`, {
10939
+ action: withDescription(stringEnum(["list", "get_config", "deploy", "deploy_bundle", "config", "source", "activate", "delete", "check", "scaffold"]), "Action"),
10940
+ ref: optional(Type.String(), "Project ref (not used by scaffold)"),
10830
10941
  slug: optional(Type.String(), "[get_config/deploy/deploy_bundle/config/source/activate/delete/check] Function name"),
10831
10942
  version: withDescription(functionVersionSchema, "[source/activate] Existing immutable Function version; source requires a positive version"),
10832
10943
  code: optional(Type.String(), "[deploy/check] Function source code (TypeScript)"),
10833
- path: optional(Type.String(), "[deploy/check] Local file path to read code from (alternative to code)"),
10944
+ path: optional(Type.String(), "[deploy/check] Source path; [scaffold] optional target directory"),
10834
10945
  "prebundled-path": optional(Type.String(), "[deploy] Prebuilt runtime bundle to upload without rebuilding; requires expected-sha256"),
10835
10946
  "expected-sha256": optional(Type.String({ pattern: SHA256_HEX_PATTERN.source, minLength: 64, maxLength: 64 }), "[deploy] Required lowercase SHA-256 of the exact prebundled-path bytes"),
10836
10947
  output: optional(Type.String(), "[source] Write source to this local file instead of stdout; the file must not already exist"),
@@ -10840,12 +10951,16 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
10840
10951
  minify: optional(Type.Boolean(), "[deploy/deploy_bundle] Minify bundle"),
10841
10952
  verify_jwt: optional(Type.Boolean(), "[deploy/deploy_bundle/config] Set JWT verification for this function"),
10842
10953
  background_routes: withDescription(backgroundRoutesSchema, "[deploy/deploy_bundle/config] Background route paths; pass comma-separated or JSON array in CLI"),
10954
+ framework: optional(withDescription(stringEnum(["fetch", "elysia", "hono", "sveltekit-function"]), "[deploy/deploy_bundle/config/scaffold] Fetch framework adapter profile")),
10843
10955
  "expected-active-version": withDescription(expectedActiveVersionSchema, "[deploy/deploy_bundle/activate] Required current active version, or 'absent' when none exists"),
10844
10956
  "expected-activation-id": withDescription(expectedActivationIdSchema, "[deploy/deploy_bundle/config/activate/delete] Required activation ID from list, or 'legacy' for a new or legacy function")
10845
10957
  }, async (args) => {
10846
10958
  if (args.action === "activate")
10847
10959
  return activateFunctionVersion(http, args, options.readOnly);
10848
- const { action, ref, slug, path: pathArg, output, entrypoint, minify, verify_jwt, background_routes } = args;
10960
+ if (args.action === "scaffold") {
10961
+ return { content: [{ type: "text", text: scaffoldFunction(args.path, args.slug, args.framework) }] };
10962
+ }
10963
+ const { action, ref, slug, path: pathArg, output, entrypoint, minify, verify_jwt, background_routes, framework } = args;
10849
10964
  rejectActionSpecificFlags(action, args);
10850
10965
  const expectedActiveVersion = action === "deploy" || action === "deploy_bundle" ? requiredExpectedActiveVersion(args, action) : undefined;
10851
10966
  const expectedActivationId = FUNCTION_IDENTITY_MUTATIONS.has(action) ? requiredExpectedActivationId(args, action) : undefined;
@@ -10857,7 +10972,8 @@ Actions: list, get_config, deploy, deploy_bundle, config, source, activate, dele
10857
10972
  let text;
10858
10973
  const functionConfig = () => ({
10859
10974
  ...typeof verify_jwt === "boolean" ? { verify_jwt } : {},
10860
- ...Array.isArray(background_routes) ? { background_routes } : {}
10975
+ ...Array.isArray(background_routes) ? { background_routes } : {},
10976
+ ...typeof framework === "string" ? { framework } : {}
10861
10977
  });
10862
10978
  const hasFunctionConfig = () => Object.keys(functionConfig()).length > 0;
10863
10979
  const checkSyntax = async (sourceCode) => {
@@ -10946,7 +11062,7 @@ ${deployCheck.err}`;
10946
11062
  case "config":
10947
11063
  need("slug", slug);
10948
11064
  if (!hasFunctionConfig()) {
10949
- throw new Error("'verify_jwt' or 'background_routes' required for 'config'");
11065
+ throw new Error("'verify_jwt', 'background_routes', or 'framework' required for 'config'");
10950
11066
  }
10951
11067
  return updateFunctionConfiguration(http, {
10952
11068
  projectRef: ref,
@@ -13120,7 +13236,7 @@ function registerBranchTools(server, http, options = {}) {
13120
13236
 
13121
13237
  // src/shared/tools/supabase-cli-tools.ts
13122
13238
  import { spawn } from "node:child_process";
13123
- import { chmodSync, existsSync as existsSync5, mkdirSync, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
13239
+ import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, statSync as statSync3, writeFileSync as writeFileSync2 } from "node:fs";
13124
13240
  import { dirname, isAbsolute, join as join3, resolve as resolve4 } from "node:path";
13125
13241
  var SENSITIVE_ENV_KEY = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIALS?|AUTHORIZATION|AUTH|SESSION|COOKIE|BEARER|DB_URI|DB_URL|DSN|DATABASE_URL|DATABASE_URI|CONNECTION_STRING|CONNECTION_URI)(?:_|$)/i;
13126
13242
  var VALID_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
@@ -13447,7 +13563,7 @@ async function executeOfficialAction(request, runtime) {
13447
13563
  const normalizedRequest = { ...request, workdir };
13448
13564
  const outputPath = actionOutputPath(normalizedRequest, workdir);
13449
13565
  if (outputPath)
13450
- mkdirSync(dirname(outputPath), { recursive: true });
13566
+ mkdirSync2(dirname(outputPath), { recursive: true });
13451
13567
  const secrets = sensitiveValues(runtime.environment, request.db_url);
13452
13568
  const execution = await runtime.executeOfficialCli(normalizedRequest);
13453
13569
  if (execution.exitCode === 0 && request.action === "gen_types" && outputPath) {
@@ -13733,7 +13849,7 @@ import {
13733
13849
  cpSync,
13734
13850
  existsSync as existsSync7,
13735
13851
  lstatSync as lstatSync2,
13736
- mkdirSync as mkdirSync2,
13852
+ mkdirSync as mkdirSync3,
13737
13853
  mkdtempSync as mkdtempSync2,
13738
13854
  readdirSync as readdirSync3,
13739
13855
  readFileSync as readFileSync5,
@@ -13780,7 +13896,7 @@ function availableBackupDirectory(destinationDirectory, now) {
13780
13896
  return candidate;
13781
13897
  }
13782
13898
  function stagedSkill(sourceDirectory, targetRoot) {
13783
- mkdirSync2(targetRoot, { recursive: true });
13899
+ mkdirSync3(targetRoot, { recursive: true });
13784
13900
  const stagingRoot = mkdtempSync2(join5(targetRoot, ".supacloud-cli-install-"));
13785
13901
  const stagingSkill = join5(stagingRoot, SKILL_NAME);
13786
13902
  try {
@@ -14955,7 +15071,7 @@ function registerReleaseTools(server, http, options = {}) {
14955
15071
  // package.json
14956
15072
  var package_default = {
14957
15073
  name: "@supacloud/cli",
14958
- version: "0.35.0",
15074
+ version: "0.36.0",
14959
15075
  description: "Project-scoped CLI for SupaCloud users",
14960
15076
  type: "module",
14961
15077
  main: "./dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/cli",
3
- "version": "0.35.0",
3
+ "version": "0.36.0",
4
4
  "description": "Project-scoped CLI for SupaCloud users",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",