@supacloud/cli 0.93.0 → 0.95.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.
package/dist/index.js CHANGED
@@ -8766,6 +8766,28 @@ function outcomeUnknownGuidance(text) {
8766
8766
  保持原 --env/--env-file 选择,先查询:${command}` : "");
8767
8767
  }
8768
8768
 
8769
+ // src/shared/deployment-upgrade.ts
8770
+ var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment is no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, bind application.id and application.environmentId in supacloud.json (or SUPACLOUD_APPLICATION_ID and SUPACLOUD_ENV), then run `supacloud deploy`. SupaCloud owns deployment planning and activation; do not retry with legacy commands.";
8771
+ var removedFrontendActions = new Set([
8772
+ "deploy_git",
8773
+ "deploy_upload",
8774
+ "redeploy",
8775
+ "upload_release",
8776
+ "activate_release"
8777
+ ]);
8778
+ var removedDeployFlags = ["target", "id", "build_command", "output_dir", "plan", "diff", "dry_run"];
8779
+ function assertCurrentDeploymentInput(tool, input) {
8780
+ if (!input || typeof input !== "object" || Array.isArray(input))
8781
+ return;
8782
+ const args = input;
8783
+ if (tool === "frontend" && typeof args["action"] === "string" && removedFrontendActions.has(args["action"])) {
8784
+ throw new Error(DEPLOYMENT_UPGRADE);
8785
+ }
8786
+ if (tool === "deploy" && removedDeployFlags.some((flag) => Object.hasOwn(args, flag))) {
8787
+ throw new Error(`${DEPLOYMENT_UPGRADE} Put build settings in the frontend configuration. For read-only review use \`supacloud app deploy-plan\`.`);
8788
+ }
8789
+ }
8790
+
8769
8791
  // src/shared/cli.ts
8770
8792
  function cliToolResultIsError(toolResult) {
8771
8793
  if (toolResult.isError === true)
@@ -8889,6 +8911,7 @@ async function runCli(cliTools, args, options = {}) {
8889
8911
  const parsedArgs = parseCliFlags(args, startIdx, tool.schema);
8890
8912
  if (startIdx === 2)
8891
8913
  parsedArgs.action = args[1];
8914
+ assertCurrentDeploymentInput(args[0], parsedArgs);
8892
8915
  validateToolArguments(tool.schema, parsedArgs);
8893
8916
  const result = await tool.callback(parsedArgs);
8894
8917
  if (result && result.content && Array.isArray(result.content)) {
@@ -11188,6 +11211,7 @@ var resultSchema = _Object_({
11188
11211
  });
11189
11212
  function registerTool(server, name, description, schema, callback) {
11190
11213
  server.tool(name, description, schema, async (input) => {
11214
+ assertCurrentDeploymentInput(name, input);
11191
11215
  const args = parseToolArguments(schema, input);
11192
11216
  const result = await callback(args);
11193
11217
  if (!Check2(resultSchema, result))
@@ -16319,39 +16343,6 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
16319
16343
  }
16320
16344
  return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16321
16345
  }
16322
- async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath) {
16323
- const endpoint = releaseEndpoint(projectRef, deploymentId);
16324
- const archive = await verifiedArchive(archivePath);
16325
- let response;
16326
- try {
16327
- response = await http.postBinary(endpoint, {
16328
- stream: archiveStream(archive),
16329
- byteLength: archive.sizeBytes
16330
- }, {
16331
- contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
16332
- contentLength: archive.sizeBytes,
16333
- contentSha256: archive.sha256,
16334
- maxJsonBytes: RESPONSE_MAX_BYTES,
16335
- timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
16336
- responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
16337
- });
16338
- } finally {
16339
- await archive.handle.close();
16340
- }
16341
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
16342
- if (!release) {
16343
- if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
16344
- return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
16345
- }
16346
- return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
16347
- }
16348
- const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
16349
- const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
16350
- if (!verified || verified.tree_sha256 !== release.tree_sha256) {
16351
- return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", readback.status);
16352
- }
16353
- return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release: verified });
16354
- }
16355
16346
  async function uploadProjectWebRelease(http, projectRef, environmentId, deploymentId, archivePath) {
16356
16347
  const endpoint = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/web-release?deployment_id=${encodeURIComponent(deploymentId)}`;
16357
16348
  const archive = await verifiedArchive(archivePath);
@@ -16406,41 +16397,6 @@ async function uploadProjectWebRelease(http, projectRef, environmentId, deployme
16406
16397
  await archive.handle.close();
16407
16398
  }
16408
16399
  }
16409
- async function uploadFrontendSource(http, projectRef, deploymentId, archivePath) {
16410
- const endpoint = `${deploymentEndpoint(projectRef, deploymentId)}/deploy/upload`;
16411
- const archive = await verifiedArchive(archivePath);
16412
- try {
16413
- const response = await http.postBinary(endpoint, {
16414
- stream: archiveStream(archive),
16415
- byteLength: archive.sizeBytes
16416
- }, {
16417
- contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
16418
- contentLength: archive.sizeBytes,
16419
- contentSha256: archive.sha256,
16420
- maxJsonBytes: RESPONSE_MAX_BYTES,
16421
- timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS
16422
- });
16423
- if (!response.ok) {
16424
- return releaseFailure("frontend.deploy_upload", response.status >= 400 && response.status < 500 ? "HTTP_ERROR" : "OUTCOME_UNKNOWN", response.status);
16425
- }
16426
- if (!response.data || typeof response.data !== "object" || !("success" in response.data) || response.data.success !== true) {
16427
- return releaseFailure("frontend.deploy_upload", "INVALID_RESPONSE", response.status);
16428
- }
16429
- return toolResponse(response.data);
16430
- } finally {
16431
- await archive.handle.close();
16432
- }
16433
- }
16434
- async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadStatus) {
16435
- const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
16436
- maxJsonBytes: RESPONSE_MAX_BYTES
16437
- });
16438
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
16439
- if (!release) {
16440
- return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
16441
- }
16442
- return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16443
- }
16444
16400
  function stableJson(candidate) {
16445
16401
  if (candidate === null || typeof candidate !== "object")
16446
16402
  return JSON.stringify(candidate);
@@ -16518,9 +16474,6 @@ async function activeReleaseReadback(http, identity) {
16518
16474
  if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
16519
16475
  return { release: null, status: 200 };
16520
16476
  }
16521
- if (snapshot.exactReadback) {
16522
- return { release: inventory.releases[0] ?? null, status: 200 };
16523
- }
16524
16477
  const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
16525
16478
  const release = releaseRead.ok ? releaseEnvelope(releaseRead.data, {
16526
16479
  projectRef: identity.projectRef,
@@ -16538,43 +16491,31 @@ async function readActiveFrontendRelease(http, projectRef, deploymentId) {
16538
16491
  if (inventory.next_cursor !== null || inventory.releases.length !== (inventory.active_release_id === null ? 0 : 1) || inventory.releases[0] && inventory.releases[0].release_id !== inventory.active_release_id) {
16539
16492
  return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16540
16493
  }
16541
- return { inventory, exactReadback: false };
16542
- }
16543
- if (response.ok || response.status !== 404) {
16544
- return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16494
+ return { inventory };
16545
16495
  }
16546
- const historyResponse = await http.get(`${releaseEndpoint(projectRef, deploymentId)}?limit=1`, {
16547
- maxJsonBytes: RESPONSE_MAX_BYTES
16548
- });
16549
- const history = historyResponse.ok && historyResponse.status === 200 ? releaseInventory(historyResponse.data, { projectRef, deploymentId }) : null;
16550
- if (!history || history.releases.length > 1) {
16496
+ if (response.status === 404) {
16551
16497
  return {
16552
- failure: releaseReadFailure("frontend.get_active_release", historyResponse),
16553
- status: historyResponse.status
16554
- };
16555
- }
16556
- if (history.active_release_id === null) {
16557
- return { inventory: { ...history, releases: [], next_cursor: null }, exactReadback: false };
16558
- }
16559
- const exactResponse = await http.get(releasePath(projectRef, deploymentId, history.active_release_id), {
16560
- maxJsonBytes: RESPONSE_MAX_BYTES
16561
- });
16562
- const release = exactResponse.ok && exactResponse.status === 200 ? releaseEnvelope(exactResponse.data, { projectRef, deploymentId, releaseId: history.active_release_id }) : null;
16563
- if (!release) {
16564
- return {
16565
- failure: releaseReadFailure("frontend.get_active_release", exactResponse),
16566
- status: exactResponse.status
16498
+ failure: {
16499
+ isError: true,
16500
+ content: [{ type: "text", text: JSON.stringify({
16501
+ ok: false,
16502
+ operation: "frontend.get_active_release",
16503
+ error: {
16504
+ code: "DEPLOYMENT_UPGRADE_REQUIRED",
16505
+ http_status: 404,
16506
+ message: `${DEPLOYMENT_UPGRADE} Check that the deployment exists and upgrade the server if this endpoint is unavailable.`
16507
+ }
16508
+ }) }]
16509
+ },
16510
+ status: response.status
16567
16511
  };
16568
16512
  }
16569
- return { inventory: { ...history, releases: [release], next_cursor: null }, exactReadback: true };
16513
+ return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16570
16514
  }
16571
16515
  async function getActiveFrontendRelease(http, projectRef, deploymentId) {
16572
16516
  const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
16573
16517
  return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
16574
16518
  }
16575
- async function readFrontendReleaseAuthority(http, projectRef, deploymentId) {
16576
- return getActiveFrontendRelease(http, projectRef, deploymentId);
16577
- }
16578
16519
  async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId) {
16579
16520
  if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
16580
16521
  throw new Error("'release_id' must be a SHA-256 digest");
@@ -16670,7 +16611,6 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
16670
16611
  releases: [],
16671
16612
  next_cursor: null
16672
16613
  },
16673
- exactReadback: false,
16674
16614
  ...previous ? { previousRelease: previous } : {}
16675
16615
  };
16676
16616
  }
@@ -16740,16 +16680,13 @@ async function activationReadback(http, input, mutationId, activationStatus) {
16740
16680
  // src/shared/tools/frontend-tools.ts
16741
16681
  function registerFrontendTools(server, http) {
16742
16682
  registerTool(server, "frontend", `Frontend hosting and immutable prebuilt releases. Supports: static, react, vue, svelte, sveltekit, sveltekit-static, nextjs, nuxt, astro.
16743
- Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy, build_logs, add_domain, remove_domain, set_env, list_frameworks, list_records, list_releases, get_active_release, get_release, upload_release, activate_release, rollback`, {
16683
+ Actions: list, get, create, update, delete, build_logs, add_domain, remove_domain, set_env, list_frameworks, list_records, list_releases, get_active_release, get_release, rollback. Publish with supacloud deploy.`, {
16744
16684
  action: withDescription(stringEnum([
16745
16685
  "list",
16746
16686
  "get",
16747
16687
  "create",
16748
16688
  "update",
16749
16689
  "delete",
16750
- "deploy_git",
16751
- "deploy_upload",
16752
- "redeploy",
16753
16690
  "build_logs",
16754
16691
  "add_domain",
16755
16692
  "remove_domain",
@@ -16759,8 +16696,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16759
16696
  "list_releases",
16760
16697
  "get_active_release",
16761
16698
  "get_release",
16762
- "upload_release",
16763
- "activate_release",
16764
16699
  "rollback"
16765
16700
  ]), "Action"),
16766
16701
  ref: optional(String2(), "Project ref"),
@@ -16774,13 +16709,7 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16774
16709
  node_version: optional(String2(), "[create/update] Node.js version"),
16775
16710
  health_check_path: optional(String2(), "[create/update] SSR readiness path (default: /)"),
16776
16711
  env_vars: optional(Record(String2(), String2()), "[create/update/set_env] Environment variables"),
16777
- git_url: optional(String2(), "[deploy_git] Git repository URL"),
16778
- branch: optional(String2(), "[deploy_git] Branch (default: main)"),
16779
- archive_path: optional(String2(), "[deploy_upload/upload_release] Local tar.zst file path"),
16780
- release_id: optional(String2(), "[get_release/activate_release] SHA-256 release ID; [rollback] optional, defaults to journal-verified previous release"),
16781
- expected_active_release_id: optional(String2(), "[activate_release] Current release SHA-256 or absent"),
16782
- expected_activation_id: optional(String2(), "[activate_release] Current activation UUIDv4 or absent"),
16783
- mutation_id: optional(String2(), "[activate_release] Required retry-stable UUIDv4"),
16712
+ release_id: optional(String2(), "[get_release] SHA-256 release ID; [rollback] optional, defaults to journal-verified previous release"),
16784
16713
  cursor: optional(String2(), "[list_releases] Last release SHA-256 cursor"),
16785
16714
  limit: optional(Number2(), "[list_releases] Page size, 1-100 (default 50)")
16786
16715
  }, async (args) => {
@@ -16797,13 +16726,7 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16797
16726
  node_version,
16798
16727
  health_check_path,
16799
16728
  env_vars,
16800
- git_url,
16801
- branch,
16802
- archive_path,
16803
16729
  release_id,
16804
- expected_active_release_id,
16805
- expected_activation_id,
16806
- mutation_id,
16807
16730
  cursor,
16808
16731
  limit
16809
16732
  } = args;
@@ -16858,22 +16781,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16858
16781
  need("id", id);
16859
16782
  text = (await http.delete(`/v1/projects/${ref}/frontend/deployments/${id}`)).ok ? `✅ Deleted` : `❌ Failed`;
16860
16783
  break;
16861
- case "deploy_git":
16862
- need("ref", ref);
16863
- need("id", id);
16864
- need("git_url", git_url);
16865
- text = ok(await http.post(`/v1/projects/${ref}/frontend/deployments/${id}/deploy/git`, { git_url, branch }));
16866
- break;
16867
- case "deploy_upload":
16868
- need("ref", ref);
16869
- need("id", id);
16870
- need("archive_path", archive_path);
16871
- return uploadFrontendSource(http, ref, id, archive_path);
16872
- case "redeploy":
16873
- need("ref", ref);
16874
- need("id", id);
16875
- text = ok(await http.post(`/v1/projects/${ref}/frontend/deployments/${id}/redeploy`));
16876
- break;
16877
16784
  case "build_logs":
16878
16785
  need("ref", ref);
16879
16786
  need("id", id);
@@ -16919,26 +16826,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16919
16826
  need("ref", ref);
16920
16827
  need("id", id);
16921
16828
  return getActiveFrontendRelease(http, ref, id);
16922
- case "upload_release":
16923
- need("ref", ref);
16924
- need("id", id);
16925
- need("archive_path", archive_path);
16926
- return uploadFrontendRelease(http, ref, id, archive_path);
16927
- case "activate_release":
16928
- need("ref", ref);
16929
- need("id", id);
16930
- need("release_id", release_id);
16931
- need("expected_active_release_id", expected_active_release_id);
16932
- need("expected_activation_id", expected_activation_id);
16933
- need("mutation_id", mutation_id);
16934
- return activateFrontendRelease(http, {
16935
- projectRef: ref,
16936
- deploymentId: id,
16937
- releaseId: release_id,
16938
- expectedActiveReleaseId: expected_active_release_id,
16939
- expectedActivationId: expected_activation_id,
16940
- mutationId: mutation_id
16941
- });
16942
16829
  case "rollback":
16943
16830
  need("ref", ref);
16944
16831
  need("id", id);
@@ -21212,7 +21099,7 @@ var starter_metadata_default = {
21212
21099
  generatedBy: "supacloud/starter-metadata-v1",
21213
21100
  packages: {
21214
21101
  compiler: {
21215
- version: "0.44.1"
21102
+ version: "0.45.0"
21216
21103
  },
21217
21104
  app: {
21218
21105
  version: "0.26.1",
@@ -21230,7 +21117,7 @@ var starter_metadata_default = {
21230
21117
  version: "0.8.1"
21231
21118
  },
21232
21119
  db: {
21233
- version: "0.16.1",
21120
+ version: "0.16.2",
21234
21121
  peerDependencies: {
21235
21122
  "drizzle-orm": "1.0.0-rc.5-169397b"
21236
21123
  },
@@ -21250,15 +21137,18 @@ var starter_metadata_default = {
21250
21137
  // src/shared/tools/app-starter-reactive.ts
21251
21138
  var STARTER_REACTIVE_GUIDE = `# Reactive development / 响应式开发
21252
21139
 
21253
- RxJS is installed by default. Ordinary queries and business commands still use
21254
- async/await. Use RxJS for ongoing events and timing/composition, not as a new
21140
+ RxJS is the default and only reactive event library in the starter ecosystem.
21141
+ Ordinary queries and business commands still use async/await. Use RxJS for
21142
+ ongoing events and timing/composition, not as a new
21255
21143
  transaction, retry or durable-delivery system.
21256
21144
 
21257
21145
  Host defaults:
21258
21146
  - In a native Angular host, use signal/resource APIs from @supacloud/app/angular
21259
21147
  and Angular's scheduler. Do not mix them with the legacy root signal graph.
21260
21148
  - In framework-neutral code, use async/await for one result and RxJS for event
21261
- composition. The host owns cancellation through an explicit signal.
21149
+ composition. Raw continuous protocols use AsyncIterable unless an existing
21150
+ RxJS/Angular boundary is the better fit. The host owns cancellation through
21151
+ an explicit signal.
21262
21152
 
21263
21153
  - Import native operators from rxjs; do not invent another event/operator library.
21264
21154
  - Import takeUntilAborted / toReadableStream from @supacloud/app/reactive.
@@ -21307,7 +21197,9 @@ Read README.md and REACTIVE.md before adding asynchronous features. If the
21307
21197
  application is hosted by Angular, read the @supacloud/app/angular guidance
21308
21198
  before choosing a signal API.
21309
21199
  Prefer the generated contracts and existing project-bound @supacloud/js client.
21310
- Use async/await for a single result; RxJS is the default event-composition library.
21200
+ Use async/await for a single result; RxJS is the default event-composition
21201
+ library. Do not introduce another reactive library without a documented special
21202
+ requirement and equivalent lifecycle tests.
21311
21203
  Bind subscriptions to an explicit owner and propagate cancellation to native I/O.
21312
21204
  Never automatically retry a write or turn observable delivery into durable ack.
21313
21205
  Do not bypass authorization, transactions, idempotency or audit to simplify code.
@@ -23121,6 +23013,12 @@ After installing dependencies, run \`bun run db:generate\` once and commit db/co
23121
23013
  The default \`bun run check\` and build fail on stale database contracts before any
23122
23014
  compiler regeneration. After an intentional source change, run db:generate again,
23123
23015
  review the diff, then run check. Ordinary checks are offline.
23016
+ The compiler also runs this source-contract gate on compile/check/dev through
23017
+ databaseGovernance.mode = "check", including incremental cache hits. Missing
23018
+ adoption files or stale contracts fail closed; no contracts are silently regenerated.
23019
+ This is not SQL lint or live Catalog reconciliation. Before promotion, declare
23020
+ the real database modules, their SQL and tests, then explicitly use mode "enforce"
23021
+ with a separately selected read-only local/test database connection.
23124
23022
 
23125
23023
  - Maintain one schema-qualified function with explicit grants per db/functions/*.sql.
23126
23024
  - Preserve migrations/ and its existing executor/ledger. Add forward migrations only.
@@ -23270,6 +23168,7 @@ export default defineSupacloudConfig({
23270
23168
  outDir: "generated",
23271
23169
  strict: true,
23272
23170
  moduleBoundaryPreset: "modular-monolith",
23171
+ databaseGovernance: { mode: "check" },
23273
23172
  effect: {
23274
23173
  requireRouteEffects: true,
23275
23174
  requireErrorMappings: true,
@@ -28108,6 +28007,117 @@ import { spawn as spawn2 } from "node:child_process";
28108
28007
  import { createHash as createHash9 } from "node:crypto";
28109
28008
  import { tmpdir as tmpdir3 } from "node:os";
28110
28009
  import { basename as basename8, dirname as dirname11, join as join17, relative as relative10, resolve as resolve22, sep as sep5 } from "node:path";
28010
+
28011
+ // src/shared/tools/project-deployment.ts
28012
+ async function requireProjectDeploymentProtocol(http, projectRef, environmentId) {
28013
+ const response = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/protocol`, { retry: false, totalTimeoutMs: 5000, maxJsonBytes: 4096 });
28014
+ if (response.transportError || response.responseReadError || response.status >= 500 || response.status === 401 || response.status === 403 || response.status === 429) {
28015
+ throw new Error(`DEPLOYMENT_PROTOCOL_UNAVAILABLE: Cannot verify the selected server (HTTP ${response.status}). Check connectivity, credentials and server health; no upload or deployment was attempted.`);
28016
+ }
28017
+ const data = response.data;
28018
+ if (response.status !== 200 || !response.ok || !data || typeof data !== "object" || !("protocol" in data) || data.protocol !== "supacloud.project-deployment.v1" || !("project_ref" in data) || data.project_ref !== projectRef || !("environment_id" in data) || data.environment_id !== environmentId) {
28019
+ throw new Error("DEPLOYMENT_PROTOCOL_MISMATCH: Upgrade the SupaCloud server and CLI together (`npm install -g @supacloud/cli@latest`), then retry `supacloud deploy`. No upload or deployment was attempted; legacy endpoints will not be used.");
28020
+ }
28021
+ }
28022
+ var operation = "applications.project_deploy";
28023
+ var scopeSchema = _Object_({
28024
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
28025
+ application_id: ApplicationIdSchema,
28026
+ environment_id: ApplicationIdSchema
28027
+ });
28028
+ var statusSchema = _Object_({
28029
+ schema: Literal("supacloud.project-deployment-status.v1"),
28030
+ deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
28031
+ status: Union([
28032
+ Literal("pending"),
28033
+ Literal("running"),
28034
+ Literal("succeeded"),
28035
+ Literal("failed_retryable"),
28036
+ Literal("failed_terminal"),
28037
+ Literal("outcome_unknown")
28038
+ ]),
28039
+ phase: Union([
28040
+ Literal("queued"),
28041
+ Literal("prepared"),
28042
+ Literal("migrating"),
28043
+ Literal("activating"),
28044
+ Literal("binding-web"),
28045
+ Literal("verifying")
28046
+ ]),
28047
+ operation: Literal("application.release.deploy"),
28048
+ ...scopeSchema.properties,
28049
+ receipt: Optional(Unknown()),
28050
+ failure_code: Optional(String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }))
28051
+ }, { additionalProperties: false });
28052
+ function responseReceipt(data, expected) {
28053
+ if (!data || typeof data !== "object" || Array.isArray(data) || !("ok" in data) || data.ok !== true) {
28054
+ throw new Error("Invalid project deployment response");
28055
+ }
28056
+ const { ok: _ok, ...receipt } = data;
28057
+ return parseApplicationDeployResult(receipt, expected);
28058
+ }
28059
+ async function runProjectDeployment(http, args) {
28060
+ const scope = { project_ref: args.ref, application_id: args.id, environment_id: args.environment_id };
28061
+ const request = {
28062
+ mutation_id: args.mutation_id,
28063
+ release_id: args.release_id,
28064
+ ...args.configuration_id === undefined ? {} : { configuration_id: args.configuration_id },
28065
+ ...args.configuration_write === undefined ? {} : { configuration_write: args.configuration_write },
28066
+ ...args.expected_plan_sha256 === undefined ? {} : { expected_plan_sha256: args.expected_plan_sha256 },
28067
+ ...args.approved_migration_digest === undefined ? {} : { approved_migration_digest: args.approved_migration_digest },
28068
+ ...args.web_release === undefined ? {} : { web_release: args.web_release }
28069
+ };
28070
+ if (!Check2(scopeSchema, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
28071
+ return releaseControlFailure(operation, "INVALID_RESPONSE", null);
28072
+ }
28073
+ const expected = { ...scope, request };
28074
+ const identity = {
28075
+ ...scope,
28076
+ deployment_id: request.mutation_id,
28077
+ mutation_id: request.mutation_id,
28078
+ release_id: request.release_id
28079
+ };
28080
+ const endpoint = `/v1/projects/${encodeURIComponent(scope.project_ref)}/environments/${encodeURIComponent(scope.environment_id)}/deployments`;
28081
+ const { mutation_id, ...candidate } = request;
28082
+ const result = await http.post(endpoint, {
28083
+ ...candidate,
28084
+ deployment_id: mutation_id,
28085
+ application_id: scope.application_id
28086
+ }, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
28087
+ if (result.ok && result.status === 200) {
28088
+ try {
28089
+ return releaseControlSuccess(operation, {
28090
+ ...responseReceipt(result.data, expected),
28091
+ deployment_id: mutation_id
28092
+ });
28093
+ } catch {}
28094
+ } else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
28095
+ return releaseControlMutationFailure(operation, result, identity);
28096
+ }
28097
+ const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
28098
+ retry: false,
28099
+ totalTimeoutMs: 30000,
28100
+ maxJsonBytes: 131072
28101
+ });
28102
+ try {
28103
+ if (!observed.ok || observed.status !== 200 || !Check2(statusSchema, observed.data))
28104
+ throw new Error;
28105
+ const state = observed.data;
28106
+ if (state.deployment_id !== mutation_id || state.project_ref !== scope.project_ref || state.application_id !== scope.application_id || state.environment_id !== scope.environment_id || state.status !== "succeeded" || state.phase !== "verifying")
28107
+ throw new Error;
28108
+ const receipt = parseApplicationDeployResult(state.receipt, expected);
28109
+ return releaseControlSuccess(operation, {
28110
+ ...receipt,
28111
+ deployment_id: mutation_id,
28112
+ replayed: true,
28113
+ execution_performed: false
28114
+ });
28115
+ } catch {
28116
+ return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
28117
+ }
28118
+ }
28119
+
28120
+ // src/shared/tools/deploy-tools.ts
28111
28121
  var MAX_SOURCE_BYTES = 256 * 1024 * 1024;
28112
28122
  var PUBLIC_BUILD_ENV_PREFIXES = ["PUBLIC_", "VITE_", "NEXT_PUBLIC_", "NUXT_PUBLIC_", "ASTRO_PUBLIC_"];
28113
28123
  var SENSITIVE_BUILD_ENV = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIAL|AUTHORIZATION|COOKIE|SESSION)(?:_|$)|(?:DATABASE_URL|DATABASE_URI|CONNECTION_STRING|DSN|PRIVATE_KEY)/i;
@@ -28119,15 +28129,8 @@ function isProtectedBuildEnv(name) {
28119
28129
  }
28120
28130
  var deployToolSchema = {
28121
28131
  ref: optional(String2(), "Project ref (defaults to the linked project)"),
28122
- target: optional(String2(), "Named deploy target from supacloud.json"),
28123
- id: optional(String2(), "Frontend deployment ID (auto-selected when unambiguous)"),
28124
28132
  cwd: optional(String2(), "Project directory (default: current directory)"),
28125
- build_command: optional(String2(), "Build command override"),
28126
- output_dir: optional(String2(), "Build output directory override"),
28127
28133
  skip_build: optional(Boolean2(), "Use an existing output directory without building"),
28128
- dry_run: optional(Boolean2(), "Resolve and validate the deployment without building or publishing"),
28129
- plan: optional(Boolean2(), "Build and compare the release with current authority without publishing"),
28130
- diff: optional(Boolean2(), "Build and report the immutable release-level diff without publishing"),
28131
28134
  json: optional(Boolean2(), "Print only the final JSON result")
28132
28135
  };
28133
28136
  function record4(candidate) {
@@ -28386,40 +28389,6 @@ function targetRoot(configRoot, target, name) {
28386
28389
  }
28387
28390
  return root;
28388
28391
  }
28389
- function selectTarget(configRoot, invocationDirectory, config, requestedName) {
28390
- const targets = config.targets ? Object.entries(config.targets) : [["frontend", {
28391
- type: "frontend",
28392
- root: config.frontend?.root,
28393
- id: config.frontend?.id,
28394
- buildCommand: config.frontend?.buildCommand,
28395
- outputDirectory: config.frontend?.outputDirectory,
28396
- buildEnv: config.frontend?.buildEnv
28397
- }]];
28398
- if (targets.length === 0)
28399
- throw new Error("supacloud.json defines no deploy targets");
28400
- if (requestedName) {
28401
- const selected = targets.find(([name]) => name === requestedName);
28402
- if (!selected)
28403
- throw new Error(`Deploy target '${requestedName}' was not found in supacloud.json`);
28404
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28405
- }
28406
- const containing = targets.map(([name, target]) => ({ name, target, root: targetRoot(configRoot, target, name) })).filter((candidate) => invocationDirectory === candidate.root || invocationDirectory.startsWith(`${candidate.root}${sep5}`)).sort((left, right) => right.root.length - left.root.length);
28407
- if (containing.length === 1 || containing.length > 1 && containing[0].root !== containing[1].root) {
28408
- const selected = containing[0];
28409
- return { name: selected.name, config: selected.target, root: selected.root };
28410
- }
28411
- if (config.defaultTarget) {
28412
- const selected = targets.find(([name]) => name === config.defaultTarget);
28413
- if (!selected)
28414
- throw new Error(`supacloud.json defaultTarget '${config.defaultTarget}' was not found`);
28415
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28416
- }
28417
- if (targets.length === 1) {
28418
- const selected = targets[0];
28419
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28420
- }
28421
- throw new Error(`Multiple deploy targets found (${targets.map(([name]) => name).sort().join(", ")}). Pass --target`);
28422
- }
28423
28392
  function defaultOutputDirectory(framework) {
28424
28393
  switch (framework) {
28425
28394
  case "sveltekit-static":
@@ -28599,24 +28568,8 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
28599
28568
  await archive.cleanup();
28600
28569
  }
28601
28570
  }
28602
- function deployResponse(result, json) {
28603
- if (json)
28604
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
28605
- const lines = [
28606
- result.unchanged === true ? "Already up to date." : `Deployed ${String(result.target || result.deployment_id || result.slug)}.`,
28607
- result.url ? `URL: ${String(result.url)}` : null,
28608
- result.release_id ? `Release: ${String(result.release_id)}` : null,
28609
- result.active_version ? `Active version: ${String(result.active_version)}` : null,
28610
- result.file_count ? `Files: ${String(result.file_count)}` : null
28611
- ].filter((line) => Boolean(line));
28612
- return { content: [{ type: "text", text: lines.join(`
28613
- `) }] };
28614
- }
28615
28571
  function registerDeployTools(server, http, options = {}) {
28616
28572
  registerTool(server, "deploy", "Build and publish the linked project with one command", deployToolSchema, async (args) => {
28617
- if (args.dry_run === true && (args.plan === true || args.diff === true)) {
28618
- throw new Error("Use dry_run for resolution only, or plan/diff for a built release comparison, not both");
28619
- }
28620
28573
  const invocationDirectory = resolve22(String(args.cwd || options.cwd || process.cwd()));
28621
28574
  const projectRef = String(args.ref || options.projectRef || "").trim();
28622
28575
  if (!projectRef)
@@ -28627,8 +28580,8 @@ function registerDeployTools(server, http, options = {}) {
28627
28580
  ...config.application,
28628
28581
  environmentId: options.environment || config.application.environmentId
28629
28582
  } : undefined;
28630
- if (!args.target && await hasProjectReleaseManifest(configRoot)) {
28631
- throw new Error("PROJECT_DEPLOYMENT_UNSUPPORTED: This project declares a release manifest that the current deployment orchestrator cannot execute. No Web-only fallback or remote mutation was performed.");
28583
+ if (await hasProjectReleaseManifest(configRoot)) {
28584
+ throw new Error(`${DEPLOYMENT_UPGRADE} Replace deploy-manifest.json with the current application delivery configuration; no remote mutation was performed.`);
28632
28585
  }
28633
28586
  if (application?.id) {
28634
28587
  if (Object.values(config.targets ?? {}).some((target) => target.type === "edge_function")) {
@@ -28637,12 +28590,6 @@ function registerDeployTools(server, http, options = {}) {
28637
28590
  if (!options.applicationRelease) {
28638
28591
  throw new Error("Application release support is unavailable in this CLI context");
28639
28592
  }
28640
- if (args.target || args.build_command || args.output_dir) {
28641
- throw new Error("Application profile deploy does not accept frontend target, build command, or output directory flags");
28642
- }
28643
- if (args.dry_run === true || args.plan === true || args.diff === true) {
28644
- throw new Error("Application profile deploy does not support dry_run, plan, or diff; use app deploy-plan for a read-only plan");
28645
- }
28646
28593
  const environmentId = application.environmentId?.trim();
28647
28594
  if (!environmentId || !Check2(ApplicationIdSchema, environmentId) || !Check2(ApplicationIdSchema, application.id)) {
28648
28595
  throw new Error("Application profile requires SUPACLOUD_APPLICATION_ENVIRONMENT_ID or SUPACLOUD_ENV");
@@ -28652,6 +28599,7 @@ function registerDeployTools(server, http, options = {}) {
28652
28599
  if (configurationPath && configurationId) {
28653
28600
  throw new Error("Application profile must set only one of SUPACLOUD_APPLICATION_CONFIGURATION_PATH or SUPACLOUD_APPLICATION_CONFIGURATION_ID");
28654
28601
  }
28602
+ await requireProjectDeploymentProtocol(http, projectRef, environmentId);
28655
28603
  const stagedWeb = await stageApplicationWebRelease(http, projectRef, environmentId, configRoot, args.skip_build === true, args.json === true, options.environmentVariables);
28656
28604
  const result = await options.applicationRelease({
28657
28605
  action: "release",
@@ -28668,215 +28616,7 @@ function registerDeployTools(server, http, options = {}) {
28668
28616
  });
28669
28617
  return result;
28670
28618
  }
28671
- const target = selectTarget(configRoot, invocationDirectory, config, String(args.target || "").trim() || undefined);
28672
- if (!args.target && target.config.type === "frontend" && (Object.values(config.targets ?? {}).some((candidate) => candidate.type === "edge_function") || await pathExists(join17(configRoot, "supacloud.config.ts")) || await pathExists(join17(configRoot, "supabase", "migrations")) || await pathExists(join17(configRoot, "supabase", "functions")))) {
28673
- throw new Error("PROJECT_DEPLOYMENT_UNSUPPORTED: Backend declarations were detected but are not covered by this deployment. No Web-only fallback or remote mutation was performed.");
28674
- }
28675
- const projectDirectory = target.root;
28676
- const targetState = await lstat5(projectDirectory).catch(() => null);
28677
- if (!targetState?.isDirectory() || targetState.isSymbolicLink()) {
28678
- throw new Error(`Deploy target '${target.name}' root is not a regular directory: ${projectDirectory}`);
28679
- }
28680
- const requestedId = String(args.id || target.config.id || "").trim() || undefined;
28681
- const build = createBuildEnvironment(target.config.buildEnv, options.environmentVariables);
28682
- if (target.config.type === "edge_function") {
28683
- if (args.diff === true)
28684
- throw new Error("Function release diffs require an immutable function release manifest");
28685
- if (!options.edgeFunctionDeploy)
28686
- throw new Error("Edge Function deploy support is unavailable in this CLI context");
28687
- const slug = target.config.slug || requestedId || target.name;
28688
- const functionListResponse = await options.edgeFunctionDeploy({
28689
- action: "list",
28690
- ref: projectRef
28691
- });
28692
- if (functionListResponse.isError) {
28693
- throw new Error(`Unable to read the current identity for Edge Function '${slug}'`);
28694
- }
28695
- const functionListText = functionListResponse.content.find((chunk) => chunk.type === "text")?.text;
28696
- if (!functionListText)
28697
- throw new Error(`Unable to read the current identity for Edge Function '${slug}'`);
28698
- const functions = projectedFunctionList(JSON.parse(functionListText));
28699
- if (!functions)
28700
- throw new Error(`Invalid current identity for Edge Function '${slug}'`);
28701
- const current = functions?.find((candidate) => candidate.slug === slug);
28702
- const activeVersion = current && typeof current.version === "number" ? String(current.version) : "absent";
28703
- const activationId = current && typeof current.activation_id === "string" ? current.activation_id : "legacy";
28704
- if (!activeVersion || !activationId)
28705
- throw new Error(`Edge Function '${slug}' has an invalid active identity`);
28706
- const buildCommand = String(args.build_command || target.config.buildCommand || "").trim() || (args.skip_build === true ? "" : await defaultBuildCommand(projectDirectory, configRoot));
28707
- const bundleDirectory = resolveInsideProject(projectDirectory, String(args.output_dir || target.config.bundleDirectory || target.config.outputDirectory || "dist"), true);
28708
- if (args.dry_run === true || args.plan === true) {
28709
- return { content: [{ type: "text", text: JSON.stringify({
28710
- ok: true,
28711
- dry_run: true,
28712
- type: target.config.type,
28713
- target: target.name,
28714
- project_ref: projectRef,
28715
- slug,
28716
- build_command: args.skip_build === true ? null : buildCommand,
28717
- build_env: build.names,
28718
- missing_build_env: build.missing,
28719
- bundle_directory: bundleDirectory,
28720
- expected_active_version: activeVersion,
28721
- expected_activation_id: activationId
28722
- }, null, 2) }] };
28723
- }
28724
- assertBuildEnvironment(build, args.skip_build === true);
28725
- if (args.skip_build !== true) {
28726
- await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28727
- }
28728
- const deployed = await options.edgeFunctionDeploy({
28729
- action: "deploy_bundle",
28730
- ref: projectRef,
28731
- slug,
28732
- "bundle-dir": bundleDirectory,
28733
- entrypoint: target.config.entrypoint || "index.ts",
28734
- minify: target.config.minify,
28735
- verify_jwt: target.config.verifyJwt,
28736
- framework: target.config.framework,
28737
- "expected-active-version": activeVersion,
28738
- "expected-activation-id": activationId
28739
- });
28740
- if (deployed.isError)
28741
- return deployed;
28742
- const deployedText = deployed.content.find((chunk) => chunk.type === "text")?.text;
28743
- const deployedPayload = deployedText ? record4(JSON.parse(deployedText)) : null;
28744
- return deployResponse({
28745
- ok: true,
28746
- unchanged: false,
28747
- type: target.config.type,
28748
- target: target.name,
28749
- project_ref: projectRef,
28750
- slug,
28751
- active_version: deployedPayload?.active_version,
28752
- activation_id: deployedPayload?.activation_id
28753
- }, args.json === true);
28754
- }
28755
- const listResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments`);
28756
- if (!listResponse.ok)
28757
- throw new Error(`Failed to list frontend deployments (HTTP ${listResponse.status})`);
28758
- const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory));
28759
- const configuredBuildCommand = String(args.build_command || target.config.buildCommand || selected.buildCommand || "").trim();
28760
- const buildCommand = configuredBuildCommand || (args.skip_build === true ? "" : await defaultBuildCommand(projectDirectory, configRoot));
28761
- const configuredOutput = String(args.output_dir || target.config.outputDirectory || "").trim();
28762
- const remoteOutput = selected.outputDirectory && selected.outputDirectory !== "." ? selected.outputDirectory : "";
28763
- const outputDirectory = resolveInsideProject(projectDirectory, configuredOutput || remoteOutput || defaultOutputDirectory(selected.framework));
28764
- if (args.dry_run === true) {
28765
- return { content: [{ type: "text", text: JSON.stringify({
28766
- ok: true,
28767
- dry_run: true,
28768
- project_ref: projectRef,
28769
- deployment_id: selected.id,
28770
- build_command: args.skip_build === true ? null : buildCommand,
28771
- build_env: build.names,
28772
- missing_build_env: build.missing,
28773
- output_directory: outputDirectory
28774
- }, null, 2) }] };
28775
- }
28776
- assertBuildEnvironment(build, args.skip_build === true);
28777
- if (args.skip_build !== true) {
28778
- await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28779
- }
28780
- const archive = await createFrontendArchive(outputDirectory);
28781
- try {
28782
- const inventory = payload(await readFrontendReleaseAuthority(http, projectRef, selected.id));
28783
- const activeReleaseId = typeof inventory.active_release_id === "string" ? inventory.active_release_id : null;
28784
- const activeActivationId = typeof inventory.active_activation_id === "string" ? inventory.active_activation_id : null;
28785
- const current = Array.isArray(inventory.releases) ? record4(inventory.releases[0]) : null;
28786
- if (archive.sha256 === activeReleaseId && archive.treeSha256 !== current?.tree_sha256) {
28787
- throw new Error("Active release tree does not match the local archive");
28788
- }
28789
- const unchanged = archive.treeSha256 === current?.tree_sha256;
28790
- if (args.plan === true || args.diff === true) {
28791
- return { content: [{ type: "text", text: JSON.stringify({
28792
- schema: "supacloud.frontend-deploy-plan.v1",
28793
- ok: true,
28794
- planned: true,
28795
- published: false,
28796
- unchanged,
28797
- environment: options.environment ?? null,
28798
- type: "frontend",
28799
- target: target.name,
28800
- project_ref: projectRef,
28801
- deployment_id: selected.id,
28802
- comparison: "immutable_release",
28803
- archive_format: FRONTEND_ARCHIVE_FORMAT,
28804
- release_id: archive.sha256,
28805
- tree_sha256: archive.treeSha256,
28806
- active_release_id: activeReleaseId,
28807
- active_tree_sha256: current?.tree_sha256 ?? null,
28808
- expected_active_release_id: activeReleaseId ?? "absent",
28809
- expected_activation_id: activeActivationId ?? "absent",
28810
- actions: unchanged ? [] : ["upload_release", "activate_release"],
28811
- file_count: archive.fileCount,
28812
- source_bytes: archive.sourceBytes,
28813
- archive_bytes: archive.archiveBytes
28814
- }, null, 2) }] };
28815
- }
28816
- if (unchanged) {
28817
- return deployResponse({
28818
- ok: true,
28819
- unchanged: true,
28820
- project_ref: projectRef,
28821
- deployment_id: selected.id,
28822
- release_id: activeReleaseId,
28823
- tree_sha256: archive.treeSha256,
28824
- url: selected.deploymentUrl,
28825
- file_count: archive.fileCount,
28826
- source_bytes: archive.sourceBytes
28827
- }, args.json === true);
28828
- }
28829
- const uploaded = payload(await uploadFrontendRelease(http, projectRef, selected.id, archive.archivePath));
28830
- const release = record4(uploaded.release);
28831
- const releaseId = requiredString(release?.release_id, "release.release_id");
28832
- if (releaseId !== archive.sha256)
28833
- throw new Error("Uploaded release identity does not match the local archive");
28834
- if (release?.tree_sha256 !== archive.treeSha256)
28835
- throw new Error("Uploaded release tree does not match the local build");
28836
- const mutationId = crypto.randomUUID();
28837
- const activationResponse = await activateFrontendRelease(http, {
28838
- projectRef,
28839
- deploymentId: selected.id,
28840
- releaseId,
28841
- expectedActiveReleaseId: activeReleaseId || "absent",
28842
- expectedActivationId: activeActivationId || "absent",
28843
- mutationId
28844
- });
28845
- if (activationResponse.isError) {
28846
- const failure = record4(JSON.parse(activationResponse.content[0]?.text ?? "{}"));
28847
- return {
28848
- isError: true,
28849
- content: [{ type: "text", text: JSON.stringify({
28850
- ...failure,
28851
- operation: "deploy",
28852
- project_ref: projectRef,
28853
- deployment_id: selected.id,
28854
- mutation_id: mutationId,
28855
- target_release_id: releaseId,
28856
- expected_active_release_id: activeReleaseId ?? "absent",
28857
- expected_activation_id: activeActivationId ?? "absent"
28858
- }) }]
28859
- };
28860
- }
28861
- const activated = payload(activationResponse);
28862
- const finalResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments/${encodeURIComponent(selected.id)}`);
28863
- const finalDeployment = finalResponse.ok ? frontendDeployment(finalResponse.data) : selected;
28864
- return deployResponse({
28865
- ok: true,
28866
- unchanged: false,
28867
- project_ref: projectRef,
28868
- deployment_id: selected.id,
28869
- release_id: activated.active_release_id,
28870
- activation_id: activated.activation_id,
28871
- previous_release_id: activeReleaseId,
28872
- previous_activation_id: activeActivationId,
28873
- url: finalDeployment.deploymentUrl,
28874
- file_count: archive.fileCount,
28875
- source_bytes: archive.sourceBytes
28876
- }, args.json === true);
28877
- } finally {
28878
- await archive.cleanup();
28879
- }
28619
+ throw new Error(DEPLOYMENT_UPGRADE);
28880
28620
  });
28881
28621
  }
28882
28622
 
@@ -29168,6 +28908,7 @@ var TEST_PROFILE = [
29168
28908
  "SUPACLOUD_API_URL=https://management.test.example.com",
29169
28909
  "SUPACLOUD_API_TOKEN=<test-management-api-token>",
29170
28910
  "SUPACLOUD_PROJECT_REF=<test-project-ref>",
28911
+ "SUPACLOUD_APPLICATION_ID=<application-id>",
29171
28912
  ""
29172
28913
  ].join(`
29173
28914
  `);
@@ -29176,6 +28917,7 @@ var PRODUCTION_PROFILE = [
29176
28917
  "SUPACLOUD_API_URL=https://management.example.com",
29177
28918
  "SUPACLOUD_API_TOKEN=<production-management-api-token>",
29178
28919
  "SUPACLOUD_PROJECT_REF=<production-project-ref>",
28920
+ "SUPACLOUD_APPLICATION_ID=<application-id>",
29179
28921
  ""
29180
28922
  ].join(`
29181
28923
  `);
@@ -29299,6 +29041,7 @@ async function initializeProject(request, options) {
29299
29041
  },
29300
29042
  next: [
29301
29043
  "cp .env.supacloud.test.example .env.supacloud.test",
29044
+ "Set SUPACLOUD_APPLICATION_ID to the application's ID and configure its current SupaCloud delivery build.",
29302
29045
  "supacloud env check",
29303
29046
  "supacloud --env test deploy"
29304
29047
  ]
@@ -29346,17 +29089,16 @@ function statusMissing(context) {
29346
29089
  }
29347
29090
  return ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
29348
29091
  }
29349
- function deployMissing(context) {
29092
+ function deployMissing(context, application) {
29350
29093
  const missing = statusMissing(context);
29351
29094
  if (context.credentialScope !== "management") {
29352
29095
  return [...missing, "Management API context"];
29353
29096
  }
29354
- if (context.applicationId) {
29355
- if (!context.applicationEnvironmentId)
29356
- missing.push("SUPACLOUD_APPLICATION_ENVIRONMENT_ID");
29357
- if (!context.applicationConfigurationPath && !context.applicationConfigurationId) {
29358
- missing.push("SUPACLOUD_APPLICATION_CONFIGURATION_PATH or SUPACLOUD_APPLICATION_CONFIGURATION_ID");
29359
- }
29097
+ if (!Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
29098
+ missing.push("valid SUPACLOUD_APPLICATION_ID or supacloud.json application.id");
29099
+ }
29100
+ if (!Check2(ApplicationIdSchema, context.applicationEnvironmentId || application?.environmentId)) {
29101
+ missing.push("valid SUPACLOUD_APPLICATION_ENVIRONMENT_ID or SUPACLOUD_ENV");
29360
29102
  }
29361
29103
  return missing;
29362
29104
  }
@@ -29366,7 +29108,13 @@ async function inspectProfile(profile) {
29366
29108
  environmentName: profile.name
29367
29109
  });
29368
29110
  const status = statusMissing(context);
29369
- const deploy = deployMissing(context);
29111
+ const configText = await readFile8(join19(dirname12(profile.path), "supacloud.json"), "utf8").catch((error) => {
29112
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
29113
+ return "{}";
29114
+ throw error;
29115
+ });
29116
+ const config = record5(JSON.parse(configText));
29117
+ const deploy = deployMissing(context, record5(config?.application));
29370
29118
  return {
29371
29119
  name: profile.name,
29372
29120
  path: profile.path,
@@ -29459,109 +29207,10 @@ function registerDeveloperExperienceTools(server, options = {}) {
29459
29207
  registerTool(server, "init", "Create SupaCloud deployment configuration and non-secret environment examples without overwriting project files.", initToolSchema, (request) => initializeProject(request, options));
29460
29208
  registerTool(server, "env", "List or locally validate named SupaCloud environment profiles without contacting the platform or printing secrets.", environmentToolSchema, (request) => inspectEnvironment(request, options));
29461
29209
  }
29462
-
29463
- // src/shared/tools/project-deployment.ts
29464
- var operation = "applications.project_deploy";
29465
- var scopeSchema = _Object_({
29466
- project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
29467
- application_id: ApplicationIdSchema,
29468
- environment_id: ApplicationIdSchema
29469
- });
29470
- var statusSchema = _Object_({
29471
- schema: Literal("supacloud.project-deployment-status.v1"),
29472
- deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
29473
- status: Union([
29474
- Literal("pending"),
29475
- Literal("running"),
29476
- Literal("succeeded"),
29477
- Literal("failed_retryable"),
29478
- Literal("failed_terminal"),
29479
- Literal("outcome_unknown")
29480
- ]),
29481
- phase: Union([
29482
- Literal("queued"),
29483
- Literal("prepared"),
29484
- Literal("migrating"),
29485
- Literal("activating"),
29486
- Literal("binding-web"),
29487
- Literal("verifying")
29488
- ]),
29489
- operation: Literal("application.release.deploy"),
29490
- ...scopeSchema.properties,
29491
- receipt: Optional(Unknown()),
29492
- failure_code: Optional(String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }))
29493
- }, { additionalProperties: false });
29494
- function responseReceipt(data, expected) {
29495
- if (!data || typeof data !== "object" || Array.isArray(data) || !("ok" in data) || data.ok !== true) {
29496
- throw new Error("Invalid project deployment response");
29497
- }
29498
- const { ok: _ok, ...receipt } = data;
29499
- return parseApplicationDeployResult(receipt, expected);
29500
- }
29501
- async function runProjectDeployment(http, args) {
29502
- const scope = { project_ref: args.ref, application_id: args.id, environment_id: args.environment_id };
29503
- const request = {
29504
- mutation_id: args.mutation_id,
29505
- release_id: args.release_id,
29506
- ...args.configuration_id === undefined ? {} : { configuration_id: args.configuration_id },
29507
- ...args.configuration_write === undefined ? {} : { configuration_write: args.configuration_write },
29508
- ...args.expected_plan_sha256 === undefined ? {} : { expected_plan_sha256: args.expected_plan_sha256 },
29509
- ...args.approved_migration_digest === undefined ? {} : { approved_migration_digest: args.approved_migration_digest },
29510
- ...args.web_release === undefined ? {} : { web_release: args.web_release }
29511
- };
29512
- if (!Check2(scopeSchema, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
29513
- return releaseControlFailure(operation, "INVALID_RESPONSE", null);
29514
- }
29515
- const expected = { ...scope, request };
29516
- const identity = {
29517
- ...scope,
29518
- deployment_id: request.mutation_id,
29519
- mutation_id: request.mutation_id,
29520
- release_id: request.release_id
29521
- };
29522
- const endpoint = `/v1/projects/${encodeURIComponent(scope.project_ref)}/environments/${encodeURIComponent(scope.environment_id)}/deployments`;
29523
- const { mutation_id, ...candidate } = request;
29524
- const result = await http.post(endpoint, {
29525
- ...candidate,
29526
- deployment_id: mutation_id,
29527
- application_id: scope.application_id
29528
- }, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
29529
- if (result.ok && result.status === 200) {
29530
- try {
29531
- return releaseControlSuccess(operation, {
29532
- ...responseReceipt(result.data, expected),
29533
- deployment_id: mutation_id
29534
- });
29535
- } catch {}
29536
- } else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
29537
- return releaseControlMutationFailure(operation, result, identity);
29538
- }
29539
- const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
29540
- retry: false,
29541
- totalTimeoutMs: 30000,
29542
- maxJsonBytes: 131072
29543
- });
29544
- try {
29545
- if (!observed.ok || observed.status !== 200 || !Check2(statusSchema, observed.data))
29546
- throw new Error;
29547
- const state = observed.data;
29548
- if (state.deployment_id !== mutation_id || state.project_ref !== scope.project_ref || state.application_id !== scope.application_id || state.environment_id !== scope.environment_id || state.status !== "succeeded" || state.phase !== "verifying")
29549
- throw new Error;
29550
- const receipt = parseApplicationDeployResult(state.receipt, expected);
29551
- return releaseControlSuccess(operation, {
29552
- ...receipt,
29553
- deployment_id: mutation_id,
29554
- replayed: true,
29555
- execution_performed: false
29556
- });
29557
- } catch {
29558
- return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
29559
- }
29560
- }
29561
29210
  // package.json
29562
29211
  var package_default = {
29563
29212
  name: "@supacloud/cli",
29564
- version: "0.93.0",
29213
+ version: "0.95.0",
29565
29214
  description: "Project-scoped CLI for SupaCloud users",
29566
29215
  type: "module",
29567
29216
  main: "./dist/index.js",
@@ -29613,9 +29262,9 @@ var package_default = {
29613
29262
  directory: "packages/cli"
29614
29263
  },
29615
29264
  dependencies: {
29616
- "@supacloud/compiler": "^0.44.1",
29265
+ "@supacloud/compiler": "^0.45.0",
29617
29266
  "@supacloud/delivery": "0.16.0",
29618
- "@supacloud/db": "0.16.1",
29267
+ "@supacloud/db": "0.16.2",
29619
29268
  typebox: "1.3.36"
29620
29269
  },
29621
29270
  overrides: {
@@ -29837,8 +29486,6 @@ EXAMPLES
29837
29486
  ${preferredCommand} deploy
29838
29487
  ${preferredCommand} --env test deploy
29839
29488
  ${preferredCommand} --env production deploy --confirm-production <project-ref>
29840
- ${preferredCommand} deploy --target web
29841
- ${preferredCommand} deploy --target api
29842
29489
  ${preferredCommand} dev sync --env test --target functions --function api
29843
29490
  ${preferredCommand} dev status --env test
29844
29491
  ${preferredCommand} dev watch --env test --target project
@@ -30194,8 +29841,7 @@ function createCliTools(context, confirmProduction) {
30194
29841
  applicationRelease: (args) => tools.app ? tools.app.callback(args) : Promise.resolve({
30195
29842
  isError: true,
30196
29843
  content: [{ type: "text", text: "Application release support is unavailable in this CLI context" }]
30197
- }),
30198
- edgeFunctionDeploy: advancedTools.edge_functions?.callback
29844
+ })
30199
29845
  })));
30200
29846
  assign(captureTools((server) => registerGatewayTools(server, http, {
30201
29847
  projectRef: context.projectRef || undefined