@supacloud/cli 0.92.0 → 0.94.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)) {
@@ -10499,12 +10522,9 @@ function parseApplicationDeployPlan(value) {
10499
10522
  var closed3 = { additionalProperties: false };
10500
10523
  var sha256 = ApplicationReleaseIdSchema;
10501
10524
  var nullableActivation = Union([ApplicationActivationIdSchema, Null()]);
10502
- var ApplicationDeployWebRequestSchema = _Object_({
10525
+ var ApplicationDeployWebReleaseSchema = _Object_({
10503
10526
  deployment_id: String2({ pattern: "^[A-Za-z0-9_-]{1,128}$" }),
10504
- release_id: sha256,
10505
- expected_active_release_id: String2({ minLength: 1 }),
10506
- expected_activation_id: String2({ minLength: 1 }),
10507
- mutation_id: ApplicationActivationIdSchema
10527
+ release_id: sha256
10508
10528
  }, closed3);
10509
10529
  var ApplicationDeployRequestSchema = _Object_({
10510
10530
  mutation_id: ApplicationActivationIdSchema,
@@ -10513,7 +10533,7 @@ var ApplicationDeployRequestSchema = _Object_({
10513
10533
  configuration_write: Optional(ApplicationConfigurationWriteSchema),
10514
10534
  expected_plan_sha256: Optional(sha256),
10515
10535
  approved_migration_digest: Optional(sha256),
10516
- web: Optional(ApplicationDeployWebRequestSchema)
10536
+ web_release: Optional(ApplicationDeployWebReleaseSchema)
10517
10537
  }, closed3);
10518
10538
  var ApplicationBackendReceiptSchema = _Object_({
10519
10539
  schema: Literal("supacloud.application-backend-receipt.v1"),
@@ -10572,7 +10592,7 @@ function parseApplicationDeployResult(value, expected) {
10572
10592
  if (expected) {
10573
10593
  const { request } = expected;
10574
10594
  const configurationId = request.configuration_id ?? request.configuration_write?.configuration_id;
10575
- if (value.project_ref !== expected.project_ref || value.application_id !== expected.application_id || value.environment_id !== expected.environment_id || value.release_id !== request.release_id || value.mutation_id !== request.mutation_id || configurationId !== undefined && value.configuration_id !== configurationId || request.configuration_write !== undefined && value.configuration_id !== request.configuration_write.configuration_id || request.expected_plan_sha256 !== undefined && value.plan_sha256 !== request.expected_plan_sha256 || Boolean(value.web) !== Boolean(request.web) || request.web !== undefined && (value.web?.deployment_id !== request.web.deployment_id || value.web.release_id !== request.web.release_id)) {
10595
+ if (value.project_ref !== expected.project_ref || value.application_id !== expected.application_id || value.environment_id !== expected.environment_id || value.release_id !== request.release_id || value.mutation_id !== request.mutation_id || configurationId !== undefined && value.configuration_id !== configurationId || request.configuration_write !== undefined && value.configuration_id !== request.configuration_write.configuration_id || request.expected_plan_sha256 !== undefined && value.plan_sha256 !== request.expected_plan_sha256 || Boolean(value.web) !== Boolean(request.web_release) || request.web_release !== undefined && (value.web?.deployment_id !== request.web_release.deployment_id || value.web.release_id !== request.web_release.release_id)) {
10576
10596
  throw new Error("Application deploy receipt does not match request");
10577
10597
  }
10578
10598
  }
@@ -11191,6 +11211,7 @@ var resultSchema = _Object_({
11191
11211
  });
11192
11212
  function registerTool(server, name, description, schema, callback) {
11193
11213
  server.tool(name, description, schema, async (input) => {
11214
+ assertCurrentDeploymentInput(name, input);
11194
11215
  const args = parseToolArguments(schema, input);
11195
11216
  const result = await callback(args);
11196
11217
  if (!Check2(resultSchema, result))
@@ -16322,42 +16343,21 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
16322
16343
  }
16323
16344
  return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16324
16345
  }
16325
- async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath) {
16326
- const endpoint = releaseEndpoint(projectRef, deploymentId);
16346
+ async function uploadProjectWebRelease(http, projectRef, environmentId, deploymentId, archivePath) {
16347
+ const endpoint = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/web-release?deployment_id=${encodeURIComponent(deploymentId)}`;
16327
16348
  const archive = await verifiedArchive(archivePath);
16328
- let response;
16329
- try {
16330
- response = await http.postBinary(endpoint, {
16331
- stream: archiveStream(archive),
16332
- byteLength: archive.sizeBytes
16333
- }, {
16334
- contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
16335
- contentLength: archive.sizeBytes,
16336
- contentSha256: archive.sha256,
16337
- maxJsonBytes: RESPONSE_MAX_BYTES,
16338
- timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
16339
- responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
16349
+ const successPayload = (value) => {
16350
+ const release = value ? releaseRecord(value.release) : null;
16351
+ if (!value || value.ok !== true || value.project_ref !== projectRef || value.environment_id !== environmentId || value.deployment_id !== deploymentId || value.release_id !== archive.sha256 || release?.release_id !== archive.sha256 || release.tree_sha256.length !== 64)
16352
+ return null;
16353
+ return toolResponse({
16354
+ project_ref: projectRef,
16355
+ environment_id: environmentId,
16356
+ deployment_id: deploymentId,
16357
+ release_id: archive.sha256,
16358
+ release
16340
16359
  });
16341
- } finally {
16342
- await archive.handle.close();
16343
- }
16344
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
16345
- if (!release) {
16346
- if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
16347
- return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
16348
- }
16349
- return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
16350
- }
16351
- const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
16352
- const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
16353
- if (!verified || verified.tree_sha256 !== release.tree_sha256) {
16354
- return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", readback.status);
16355
- }
16356
- return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release: verified });
16357
- }
16358
- async function uploadFrontendSource(http, projectRef, deploymentId, archivePath) {
16359
- const endpoint = `${deploymentEndpoint(projectRef, deploymentId)}/deploy/upload`;
16360
- const archive = await verifiedArchive(archivePath);
16360
+ };
16361
16361
  try {
16362
16362
  const response = await http.postBinary(endpoint, {
16363
16363
  stream: archiveStream(archive),
@@ -16367,29 +16367,36 @@ async function uploadFrontendSource(http, projectRef, deploymentId, archivePath)
16367
16367
  contentLength: archive.sizeBytes,
16368
16368
  contentSha256: archive.sha256,
16369
16369
  maxJsonBytes: RESPONSE_MAX_BYTES,
16370
- timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS
16370
+ timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
16371
+ responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
16371
16372
  });
16372
- if (!response.ok) {
16373
- return releaseFailure("frontend.deploy_upload", response.status >= 400 && response.status < 500 ? "HTTP_ERROR" : "OUTCOME_UNKNOWN", response.status);
16374
- }
16375
- if (!response.data || typeof response.data !== "object" || !("success" in response.data) || response.data.success !== true) {
16376
- return releaseFailure("frontend.deploy_upload", "INVALID_RESPONSE", response.status);
16373
+ const value = response.data && typeof response.data === "object" && !Array.isArray(response.data) ? response.data : null;
16374
+ if (response.ok && response.status === 201) {
16375
+ const success = successPayload(value);
16376
+ if (success)
16377
+ return success;
16378
+ }
16379
+ if (response.transportError || response.responseReadError || response.status >= 500 || response.status === 202) {
16380
+ const readback = await getFrontendRelease(http, projectRef, deploymentId, archive.sha256);
16381
+ if (!readback.isError) {
16382
+ const readbackValue = JSON.parse(readback.content[0]?.text ?? "{}");
16383
+ const release = readbackValue.release;
16384
+ if (release && typeof release === "object" && !Array.isArray(release) && release.release_id === archive.sha256) {
16385
+ return toolResponse({
16386
+ project_ref: projectRef,
16387
+ environment_id: environmentId,
16388
+ deployment_id: deploymentId,
16389
+ release_id: archive.sha256,
16390
+ release
16391
+ });
16392
+ }
16393
+ }
16377
16394
  }
16378
- return toolResponse(response.data);
16395
+ return releaseFailure("frontend.upload_project_web_release", response.status >= 400 && response.status < 500 && !response.transportError ? "HTTP_ERROR" : "OUTCOME_UNKNOWN", response.status);
16379
16396
  } finally {
16380
16397
  await archive.handle.close();
16381
16398
  }
16382
16399
  }
16383
- async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadStatus) {
16384
- const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
16385
- maxJsonBytes: RESPONSE_MAX_BYTES
16386
- });
16387
- const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
16388
- if (!release) {
16389
- return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
16390
- }
16391
- return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16392
- }
16393
16400
  function stableJson(candidate) {
16394
16401
  if (candidate === null || typeof candidate !== "object")
16395
16402
  return JSON.stringify(candidate);
@@ -16467,9 +16474,6 @@ async function activeReleaseReadback(http, identity) {
16467
16474
  if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
16468
16475
  return { release: null, status: 200 };
16469
16476
  }
16470
- if (snapshot.exactReadback) {
16471
- return { release: inventory.releases[0] ?? null, status: 200 };
16472
- }
16473
16477
  const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
16474
16478
  const release = releaseRead.ok ? releaseEnvelope(releaseRead.data, {
16475
16479
  projectRef: identity.projectRef,
@@ -16487,43 +16491,31 @@ async function readActiveFrontendRelease(http, projectRef, deploymentId) {
16487
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) {
16488
16492
  return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16489
16493
  }
16490
- return { inventory, exactReadback: false };
16491
- }
16492
- if (response.ok || response.status !== 404) {
16493
- return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16494
- }
16495
- const historyResponse = await http.get(`${releaseEndpoint(projectRef, deploymentId)}?limit=1`, {
16496
- maxJsonBytes: RESPONSE_MAX_BYTES
16497
- });
16498
- const history = historyResponse.ok && historyResponse.status === 200 ? releaseInventory(historyResponse.data, { projectRef, deploymentId }) : null;
16499
- if (!history || history.releases.length > 1) {
16500
- return {
16501
- failure: releaseReadFailure("frontend.get_active_release", historyResponse),
16502
- status: historyResponse.status
16503
- };
16494
+ return { inventory };
16504
16495
  }
16505
- if (history.active_release_id === null) {
16506
- return { inventory: { ...history, releases: [], next_cursor: null }, exactReadback: false };
16507
- }
16508
- const exactResponse = await http.get(releasePath(projectRef, deploymentId, history.active_release_id), {
16509
- maxJsonBytes: RESPONSE_MAX_BYTES
16510
- });
16511
- const release = exactResponse.ok && exactResponse.status === 200 ? releaseEnvelope(exactResponse.data, { projectRef, deploymentId, releaseId: history.active_release_id }) : null;
16512
- if (!release) {
16496
+ if (response.status === 404) {
16513
16497
  return {
16514
- failure: releaseReadFailure("frontend.get_active_release", exactResponse),
16515
- 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
16516
16511
  };
16517
16512
  }
16518
- return { inventory: { ...history, releases: [release], next_cursor: null }, exactReadback: true };
16513
+ return { failure: releaseReadFailure("frontend.get_active_release", response), status: response.status };
16519
16514
  }
16520
16515
  async function getActiveFrontendRelease(http, projectRef, deploymentId) {
16521
16516
  const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
16522
16517
  return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
16523
16518
  }
16524
- async function readFrontendReleaseAuthority(http, projectRef, deploymentId) {
16525
- return getActiveFrontendRelease(http, projectRef, deploymentId);
16526
- }
16527
16519
  async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId) {
16528
16520
  if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
16529
16521
  throw new Error("'release_id' must be a SHA-256 digest");
@@ -16619,7 +16611,6 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
16619
16611
  releases: [],
16620
16612
  next_cursor: null
16621
16613
  },
16622
- exactReadback: false,
16623
16614
  ...previous ? { previousRelease: previous } : {}
16624
16615
  };
16625
16616
  }
@@ -16689,16 +16680,13 @@ async function activationReadback(http, input, mutationId, activationStatus) {
16689
16680
  // src/shared/tools/frontend-tools.ts
16690
16681
  function registerFrontendTools(server, http) {
16691
16682
  registerTool(server, "frontend", `Frontend hosting and immutable prebuilt releases. Supports: static, react, vue, svelte, sveltekit, sveltekit-static, nextjs, nuxt, astro.
16692
- 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.`, {
16693
16684
  action: withDescription(stringEnum([
16694
16685
  "list",
16695
16686
  "get",
16696
16687
  "create",
16697
16688
  "update",
16698
16689
  "delete",
16699
- "deploy_git",
16700
- "deploy_upload",
16701
- "redeploy",
16702
16690
  "build_logs",
16703
16691
  "add_domain",
16704
16692
  "remove_domain",
@@ -16708,8 +16696,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16708
16696
  "list_releases",
16709
16697
  "get_active_release",
16710
16698
  "get_release",
16711
- "upload_release",
16712
- "activate_release",
16713
16699
  "rollback"
16714
16700
  ]), "Action"),
16715
16701
  ref: optional(String2(), "Project ref"),
@@ -16723,13 +16709,7 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16723
16709
  node_version: optional(String2(), "[create/update] Node.js version"),
16724
16710
  health_check_path: optional(String2(), "[create/update] SSR readiness path (default: /)"),
16725
16711
  env_vars: optional(Record(String2(), String2()), "[create/update/set_env] Environment variables"),
16726
- git_url: optional(String2(), "[deploy_git] Git repository URL"),
16727
- branch: optional(String2(), "[deploy_git] Branch (default: main)"),
16728
- archive_path: optional(String2(), "[deploy_upload/upload_release] Local tar.zst file path"),
16729
- release_id: optional(String2(), "[get_release/activate_release] SHA-256 release ID; [rollback] optional, defaults to journal-verified previous release"),
16730
- expected_active_release_id: optional(String2(), "[activate_release] Current release SHA-256 or absent"),
16731
- expected_activation_id: optional(String2(), "[activate_release] Current activation UUIDv4 or absent"),
16732
- 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"),
16733
16713
  cursor: optional(String2(), "[list_releases] Last release SHA-256 cursor"),
16734
16714
  limit: optional(Number2(), "[list_releases] Page size, 1-100 (default 50)")
16735
16715
  }, async (args) => {
@@ -16746,13 +16726,7 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16746
16726
  node_version,
16747
16727
  health_check_path,
16748
16728
  env_vars,
16749
- git_url,
16750
- branch,
16751
- archive_path,
16752
16729
  release_id,
16753
- expected_active_release_id,
16754
- expected_activation_id,
16755
- mutation_id,
16756
16730
  cursor,
16757
16731
  limit
16758
16732
  } = args;
@@ -16807,22 +16781,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16807
16781
  need("id", id);
16808
16782
  text = (await http.delete(`/v1/projects/${ref}/frontend/deployments/${id}`)).ok ? `✅ Deleted` : `❌ Failed`;
16809
16783
  break;
16810
- case "deploy_git":
16811
- need("ref", ref);
16812
- need("id", id);
16813
- need("git_url", git_url);
16814
- text = ok(await http.post(`/v1/projects/${ref}/frontend/deployments/${id}/deploy/git`, { git_url, branch }));
16815
- break;
16816
- case "deploy_upload":
16817
- need("ref", ref);
16818
- need("id", id);
16819
- need("archive_path", archive_path);
16820
- return uploadFrontendSource(http, ref, id, archive_path);
16821
- case "redeploy":
16822
- need("ref", ref);
16823
- need("id", id);
16824
- text = ok(await http.post(`/v1/projects/${ref}/frontend/deployments/${id}/redeploy`));
16825
- break;
16826
16784
  case "build_logs":
16827
16785
  need("ref", ref);
16828
16786
  need("id", id);
@@ -16868,26 +16826,6 @@ Actions: list, get, create, update, delete, deploy_git, deploy_upload, redeploy,
16868
16826
  need("ref", ref);
16869
16827
  need("id", id);
16870
16828
  return getActiveFrontendRelease(http, ref, id);
16871
- case "upload_release":
16872
- need("ref", ref);
16873
- need("id", id);
16874
- need("archive_path", archive_path);
16875
- return uploadFrontendRelease(http, ref, id, archive_path);
16876
- case "activate_release":
16877
- need("ref", ref);
16878
- need("id", id);
16879
- need("release_id", release_id);
16880
- need("expected_active_release_id", expected_active_release_id);
16881
- need("expected_activation_id", expected_activation_id);
16882
- need("mutation_id", mutation_id);
16883
- return activateFrontendRelease(http, {
16884
- projectRef: ref,
16885
- deploymentId: id,
16886
- releaseId: release_id,
16887
- expectedActiveReleaseId: expected_active_release_id,
16888
- expectedActivationId: expected_activation_id,
16889
- mutationId: mutation_id
16890
- });
16891
16829
  case "rollback":
16892
16830
  need("ref", ref);
16893
16831
  need("id", id);
@@ -16912,7 +16850,7 @@ var ApplicationRollbackSnapshotSchema2 = ApplicationRollbackSnapshotSchema;
16912
16850
  var ApplicationActivationHistoryCursorSchema2 = ApplicationActivationHistoryCursorSchema;
16913
16851
  var ApplicationPromotionPlanSchema2 = ApplicationPromotionPlanSchema;
16914
16852
  var ApplicationDeployRequestSchema2 = ApplicationDeployRequestSchema;
16915
- var ApplicationDeployWebRequestSchema2 = ApplicationDeployWebRequestSchema;
16853
+ var ApplicationDeployWebReleaseSchema2 = ApplicationDeployWebReleaseSchema;
16916
16854
 
16917
16855
  // src/shared/mutation-protocol.ts
16918
16856
  import { createHash as createHash6 } from "node:crypto";
@@ -17730,7 +17668,7 @@ var APPLICATION_TOOL_SCHEMA = {
17730
17668
  configuration_path: optional(String2(), "[put_configuration] Local configuration write JSON including revision and expected revision"),
17731
17669
  configuration_write: optional(Unknown(), "[deploy_application] Parsed immutable configuration write"),
17732
17670
  manifest_path: optional(String2(), "[upload_release] Local delivery.manifest.json"),
17733
- web: optional(ApplicationDeployWebRequestSchema2, "[deploy_application] Immutable staged Web release binding"),
17671
+ web_release: optional(ApplicationDeployWebReleaseSchema2, "[deploy_application] Immutable staged Web release uploaded by the deploy profile"),
17734
17672
  release_id: optional(ApplicationReleaseIdSchema2, "[get_release/get_deploy_plan/deploy_release/activate_release/reconcile_activation/rollback_release] Immutable application release ID; platform selects previous for default rollback"),
17735
17673
  source_ref: optional(String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" }), "[get_release_transfer_plan/transfer_release] Source project ref"),
17736
17674
  source_release_id: optional(ApplicationReleaseIdSchema2, "[get_release_transfer_plan/transfer_release] Source immutable release ID"),
@@ -18109,7 +18047,7 @@ function registerApplicationTools(server, http) {
18109
18047
  ...configurationId === undefined ? {} : { configuration_id: configurationId },
18110
18048
  ...configurationWrite === undefined ? {} : { configuration_write: configurationWrite },
18111
18049
  ...typeof args["approved_migration_digest"] === "string" ? { approved_migration_digest: args["approved_migration_digest"] } : {},
18112
- ...args["web"] === undefined ? {} : { web: args["web"] }
18050
+ ...args["web_release"] === undefined ? {} : { web_release: args["web_release"] }
18113
18051
  };
18114
18052
  if (!Check2(ApplicationDeployRequestSchema2, body)) {
18115
18053
  throw new Error("Invalid application deploy request");
@@ -21179,7 +21117,7 @@ var starter_metadata_default = {
21179
21117
  version: "0.8.1"
21180
21118
  },
21181
21119
  db: {
21182
- version: "0.16.1",
21120
+ version: "0.16.2",
21183
21121
  peerDependencies: {
21184
21122
  "drizzle-orm": "1.0.0-rc.5-169397b"
21185
21123
  },
@@ -24587,7 +24525,7 @@ var REMOTE_APP_DESCRIPTIONS = {
24587
24525
  source_environment_id: "[promote-plan/diff/promote] Source environment ID",
24588
24526
  mutation_id: "[promote-status/promote-reconcile] Stable promotion mutation ID",
24589
24527
  approved_migration_digest: "[promote] Exact reviewed migration execution-plan digest",
24590
- web: "[release] Immutable staged Web release binding prepared by the deploy profile",
24528
+ web_release: "[release] Immutable staged Web release uploaded by the deploy profile",
24591
24529
  branch_ref: "[preview-plan] Preview branch identity",
24592
24530
  branch_name: "[preview/preview-create] Human-readable preview branch name",
24593
24531
  data_mode: "[preview-plan/preview/preview-create] schema_only or full_clone",
@@ -25630,10 +25568,13 @@ async function runAppRelease(request, options, delegate) {
25630
25568
  mutation_id: activationId,
25631
25569
  ...configurationId === undefined ? {} : { configuration_id: configurationId },
25632
25570
  ...configurationWrite === undefined ? {} : { configuration_write: configurationWrite },
25633
- ...request.web === undefined ? {} : { web: request.web }
25571
+ ...request.web_release === undefined ? {} : { web_release: request.web_release }
25634
25572
  };
25635
25573
  validateToolArguments(APPLICATION_TOOL_SCHEMA, deployArgs);
25636
- const deployed = options.projectDeployment ? await options.projectDeployment(deployArgs) : await delegate(deployArgs);
25574
+ if (!options.projectDeployment) {
25575
+ throw new Error("Application release requires the unified project deployment handler");
25576
+ }
25577
+ const deployed = await options.projectDeployment(deployArgs);
25637
25578
  const deployReceipt = resultObject(deployed);
25638
25579
  const resolvedConfigurationId = typeof deployReceipt?.configuration_id === "string" ? deployReceipt.configuration_id : undefined;
25639
25580
  if (resolvedConfigurationId !== undefined) {
@@ -28054,6 +27995,117 @@ import { spawn as spawn2 } from "node:child_process";
28054
27995
  import { createHash as createHash9 } from "node:crypto";
28055
27996
  import { tmpdir as tmpdir3 } from "node:os";
28056
27997
  import { basename as basename8, dirname as dirname11, join as join17, relative as relative10, resolve as resolve22, sep as sep5 } from "node:path";
27998
+
27999
+ // src/shared/tools/project-deployment.ts
28000
+ async function requireProjectDeploymentProtocol(http, projectRef, environmentId) {
28001
+ const response = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/protocol`, { retry: false, totalTimeoutMs: 5000, maxJsonBytes: 4096 });
28002
+ if (response.transportError || response.responseReadError || response.status >= 500 || response.status === 401 || response.status === 403 || response.status === 429) {
28003
+ 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.`);
28004
+ }
28005
+ const data = response.data;
28006
+ 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) {
28007
+ 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.");
28008
+ }
28009
+ }
28010
+ var operation = "applications.project_deploy";
28011
+ var scopeSchema = _Object_({
28012
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
28013
+ application_id: ApplicationIdSchema,
28014
+ environment_id: ApplicationIdSchema
28015
+ });
28016
+ var statusSchema = _Object_({
28017
+ schema: Literal("supacloud.project-deployment-status.v1"),
28018
+ deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
28019
+ status: Union([
28020
+ Literal("pending"),
28021
+ Literal("running"),
28022
+ Literal("succeeded"),
28023
+ Literal("failed_retryable"),
28024
+ Literal("failed_terminal"),
28025
+ Literal("outcome_unknown")
28026
+ ]),
28027
+ phase: Union([
28028
+ Literal("queued"),
28029
+ Literal("prepared"),
28030
+ Literal("migrating"),
28031
+ Literal("activating"),
28032
+ Literal("binding-web"),
28033
+ Literal("verifying")
28034
+ ]),
28035
+ operation: Literal("application.release.deploy"),
28036
+ ...scopeSchema.properties,
28037
+ receipt: Optional(Unknown()),
28038
+ failure_code: Optional(String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }))
28039
+ }, { additionalProperties: false });
28040
+ function responseReceipt(data, expected) {
28041
+ if (!data || typeof data !== "object" || Array.isArray(data) || !("ok" in data) || data.ok !== true) {
28042
+ throw new Error("Invalid project deployment response");
28043
+ }
28044
+ const { ok: _ok, ...receipt } = data;
28045
+ return parseApplicationDeployResult(receipt, expected);
28046
+ }
28047
+ async function runProjectDeployment(http, args) {
28048
+ const scope = { project_ref: args.ref, application_id: args.id, environment_id: args.environment_id };
28049
+ const request = {
28050
+ mutation_id: args.mutation_id,
28051
+ release_id: args.release_id,
28052
+ ...args.configuration_id === undefined ? {} : { configuration_id: args.configuration_id },
28053
+ ...args.configuration_write === undefined ? {} : { configuration_write: args.configuration_write },
28054
+ ...args.expected_plan_sha256 === undefined ? {} : { expected_plan_sha256: args.expected_plan_sha256 },
28055
+ ...args.approved_migration_digest === undefined ? {} : { approved_migration_digest: args.approved_migration_digest },
28056
+ ...args.web_release === undefined ? {} : { web_release: args.web_release }
28057
+ };
28058
+ if (!Check2(scopeSchema, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
28059
+ return releaseControlFailure(operation, "INVALID_RESPONSE", null);
28060
+ }
28061
+ const expected = { ...scope, request };
28062
+ const identity = {
28063
+ ...scope,
28064
+ deployment_id: request.mutation_id,
28065
+ mutation_id: request.mutation_id,
28066
+ release_id: request.release_id
28067
+ };
28068
+ const endpoint = `/v1/projects/${encodeURIComponent(scope.project_ref)}/environments/${encodeURIComponent(scope.environment_id)}/deployments`;
28069
+ const { mutation_id, ...candidate } = request;
28070
+ const result = await http.post(endpoint, {
28071
+ ...candidate,
28072
+ deployment_id: mutation_id,
28073
+ application_id: scope.application_id
28074
+ }, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
28075
+ if (result.ok && result.status === 200) {
28076
+ try {
28077
+ return releaseControlSuccess(operation, {
28078
+ ...responseReceipt(result.data, expected),
28079
+ deployment_id: mutation_id
28080
+ });
28081
+ } catch {}
28082
+ } else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
28083
+ return releaseControlMutationFailure(operation, result, identity);
28084
+ }
28085
+ const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
28086
+ retry: false,
28087
+ totalTimeoutMs: 30000,
28088
+ maxJsonBytes: 131072
28089
+ });
28090
+ try {
28091
+ if (!observed.ok || observed.status !== 200 || !Check2(statusSchema, observed.data))
28092
+ throw new Error;
28093
+ const state = observed.data;
28094
+ 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")
28095
+ throw new Error;
28096
+ const receipt = parseApplicationDeployResult(state.receipt, expected);
28097
+ return releaseControlSuccess(operation, {
28098
+ ...receipt,
28099
+ deployment_id: mutation_id,
28100
+ replayed: true,
28101
+ execution_performed: false
28102
+ });
28103
+ } catch {
28104
+ return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
28105
+ }
28106
+ }
28107
+
28108
+ // src/shared/tools/deploy-tools.ts
28057
28109
  var MAX_SOURCE_BYTES = 256 * 1024 * 1024;
28058
28110
  var PUBLIC_BUILD_ENV_PREFIXES = ["PUBLIC_", "VITE_", "NEXT_PUBLIC_", "NUXT_PUBLIC_", "ASTRO_PUBLIC_"];
28059
28111
  var SENSITIVE_BUILD_ENV = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIAL|AUTHORIZATION|COOKIE|SESSION)(?:_|$)|(?:DATABASE_URL|DATABASE_URI|CONNECTION_STRING|DSN|PRIVATE_KEY)/i;
@@ -28065,15 +28117,8 @@ function isProtectedBuildEnv(name) {
28065
28117
  }
28066
28118
  var deployToolSchema = {
28067
28119
  ref: optional(String2(), "Project ref (defaults to the linked project)"),
28068
- target: optional(String2(), "Named deploy target from supacloud.json"),
28069
- id: optional(String2(), "Frontend deployment ID (auto-selected when unambiguous)"),
28070
28120
  cwd: optional(String2(), "Project directory (default: current directory)"),
28071
- build_command: optional(String2(), "Build command override"),
28072
- output_dir: optional(String2(), "Build output directory override"),
28073
28121
  skip_build: optional(Boolean2(), "Use an existing output directory without building"),
28074
- dry_run: optional(Boolean2(), "Resolve and validate the deployment without building or publishing"),
28075
- plan: optional(Boolean2(), "Build and compare the release with current authority without publishing"),
28076
- diff: optional(Boolean2(), "Build and report the immutable release-level diff without publishing"),
28077
28122
  json: optional(Boolean2(), "Print only the final JSON result")
28078
28123
  };
28079
28124
  function record4(candidate) {
@@ -28332,40 +28377,6 @@ function targetRoot(configRoot, target, name) {
28332
28377
  }
28333
28378
  return root;
28334
28379
  }
28335
- function selectTarget(configRoot, invocationDirectory, config, requestedName) {
28336
- const targets = config.targets ? Object.entries(config.targets) : [["frontend", {
28337
- type: "frontend",
28338
- root: config.frontend?.root,
28339
- id: config.frontend?.id,
28340
- buildCommand: config.frontend?.buildCommand,
28341
- outputDirectory: config.frontend?.outputDirectory,
28342
- buildEnv: config.frontend?.buildEnv
28343
- }]];
28344
- if (targets.length === 0)
28345
- throw new Error("supacloud.json defines no deploy targets");
28346
- if (requestedName) {
28347
- const selected = targets.find(([name]) => name === requestedName);
28348
- if (!selected)
28349
- throw new Error(`Deploy target '${requestedName}' was not found in supacloud.json`);
28350
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28351
- }
28352
- 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);
28353
- if (containing.length === 1 || containing.length > 1 && containing[0].root !== containing[1].root) {
28354
- const selected = containing[0];
28355
- return { name: selected.name, config: selected.target, root: selected.root };
28356
- }
28357
- if (config.defaultTarget) {
28358
- const selected = targets.find(([name]) => name === config.defaultTarget);
28359
- if (!selected)
28360
- throw new Error(`supacloud.json defaultTarget '${config.defaultTarget}' was not found`);
28361
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28362
- }
28363
- if (targets.length === 1) {
28364
- const selected = targets[0];
28365
- return { name: selected[0], config: selected[1], root: targetRoot(configRoot, selected[1], selected[0]) };
28366
- }
28367
- throw new Error(`Multiple deploy targets found (${targets.map(([name]) => name).sort().join(", ")}). Pass --target`);
28368
- }
28369
28380
  function defaultOutputDirectory(framework) {
28370
28381
  switch (framework) {
28371
28382
  case "sveltekit-static":
@@ -28502,7 +28513,7 @@ function payload(response) {
28502
28513
  throw new Error("Deployment operation returned an invalid response");
28503
28514
  return parsed;
28504
28515
  }
28505
- async function stageApplicationWebRelease(http, projectRef, configRoot, skipBuild, json, environmentVariables) {
28516
+ async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables) {
28506
28517
  const target = selectFrontendTarget(configRoot, await readDeployConfig(configRoot));
28507
28518
  if (!target)
28508
28519
  return null;
@@ -28528,17 +28539,7 @@ async function stageApplicationWebRelease(http, projectRef, configRoot, skipBuil
28528
28539
  }
28529
28540
  const archive = await createFrontendArchive(outputDirectory);
28530
28541
  try {
28531
- const authority = payload(await readFrontendReleaseAuthority(http, projectRef, selected.id));
28532
- const activeReleaseId = typeof authority.active_release_id === "string" ? authority.active_release_id : null;
28533
- const activeActivationId = typeof authority.active_activation_id === "string" ? authority.active_activation_id : null;
28534
- const current = Array.isArray(authority.releases) ? record4(authority.releases[0]) : null;
28535
- if (archive.sha256 === activeReleaseId && archive.treeSha256 !== current?.tree_sha256) {
28536
- throw new Error("Active Web release tree does not match the local archive");
28537
- }
28538
- if (archive.treeSha256 === current?.tree_sha256) {
28539
- return {};
28540
- }
28541
- const uploaded = payload(await uploadFrontendRelease(http, projectRef, selected.id, archive.archivePath));
28542
+ const uploaded = payload(await uploadProjectWebRelease(http, projectRef, environmentId, selected.id, archive.archivePath));
28542
28543
  const release = record4(uploaded.release);
28543
28544
  const releaseId = requiredString(release?.release_id, "release.release_id");
28544
28545
  if (releaseId !== archive.sha256)
@@ -28548,34 +28549,15 @@ async function stageApplicationWebRelease(http, projectRef, configRoot, skipBuil
28548
28549
  return {
28549
28550
  request: {
28550
28551
  deployment_id: selected.id,
28551
- release_id: releaseId,
28552
- expected_active_release_id: activeReleaseId ?? "absent",
28553
- expected_activation_id: activeActivationId ?? "absent",
28554
- mutation_id: crypto.randomUUID()
28552
+ release_id: releaseId
28555
28553
  }
28556
28554
  };
28557
28555
  } finally {
28558
28556
  await archive.cleanup();
28559
28557
  }
28560
28558
  }
28561
- function deployResponse(result, json) {
28562
- if (json)
28563
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
28564
- const lines = [
28565
- result.unchanged === true ? "Already up to date." : `Deployed ${String(result.target || result.deployment_id || result.slug)}.`,
28566
- result.url ? `URL: ${String(result.url)}` : null,
28567
- result.release_id ? `Release: ${String(result.release_id)}` : null,
28568
- result.active_version ? `Active version: ${String(result.active_version)}` : null,
28569
- result.file_count ? `Files: ${String(result.file_count)}` : null
28570
- ].filter((line) => Boolean(line));
28571
- return { content: [{ type: "text", text: lines.join(`
28572
- `) }] };
28573
- }
28574
28559
  function registerDeployTools(server, http, options = {}) {
28575
28560
  registerTool(server, "deploy", "Build and publish the linked project with one command", deployToolSchema, async (args) => {
28576
- if (args.dry_run === true && (args.plan === true || args.diff === true)) {
28577
- throw new Error("Use dry_run for resolution only, or plan/diff for a built release comparison, not both");
28578
- }
28579
28561
  const invocationDirectory = resolve22(String(args.cwd || options.cwd || process.cwd()));
28580
28562
  const projectRef = String(args.ref || options.projectRef || "").trim();
28581
28563
  if (!projectRef)
@@ -28586,8 +28568,8 @@ function registerDeployTools(server, http, options = {}) {
28586
28568
  ...config.application,
28587
28569
  environmentId: options.environment || config.application.environmentId
28588
28570
  } : undefined;
28589
- if (!args.target && await hasProjectReleaseManifest(configRoot)) {
28590
- 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.");
28571
+ if (await hasProjectReleaseManifest(configRoot)) {
28572
+ throw new Error(`${DEPLOYMENT_UPGRADE} Replace deploy-manifest.json with the current application delivery configuration; no remote mutation was performed.`);
28591
28573
  }
28592
28574
  if (application?.id) {
28593
28575
  if (Object.values(config.targets ?? {}).some((target) => target.type === "edge_function")) {
@@ -28596,12 +28578,6 @@ function registerDeployTools(server, http, options = {}) {
28596
28578
  if (!options.applicationRelease) {
28597
28579
  throw new Error("Application release support is unavailable in this CLI context");
28598
28580
  }
28599
- if (args.target || args.build_command || args.output_dir) {
28600
- throw new Error("Application profile deploy does not accept frontend target, build command, or output directory flags");
28601
- }
28602
- if (args.dry_run === true || args.plan === true || args.diff === true) {
28603
- throw new Error("Application profile deploy does not support dry_run, plan, or diff; use app deploy-plan for a read-only plan");
28604
- }
28605
28581
  const environmentId = application.environmentId?.trim();
28606
28582
  if (!environmentId || !Check2(ApplicationIdSchema, environmentId) || !Check2(ApplicationIdSchema, application.id)) {
28607
28583
  throw new Error("Application profile requires SUPACLOUD_APPLICATION_ENVIRONMENT_ID or SUPACLOUD_ENV");
@@ -28611,7 +28587,8 @@ function registerDeployTools(server, http, options = {}) {
28611
28587
  if (configurationPath && configurationId) {
28612
28588
  throw new Error("Application profile must set only one of SUPACLOUD_APPLICATION_CONFIGURATION_PATH or SUPACLOUD_APPLICATION_CONFIGURATION_ID");
28613
28589
  }
28614
- const stagedWeb = await stageApplicationWebRelease(http, projectRef, configRoot, args.skip_build === true, args.json === true, options.environmentVariables);
28590
+ await requireProjectDeploymentProtocol(http, projectRef, environmentId);
28591
+ const stagedWeb = await stageApplicationWebRelease(http, projectRef, environmentId, configRoot, args.skip_build === true, args.json === true, options.environmentVariables);
28615
28592
  const result = await options.applicationRelease({
28616
28593
  action: "release",
28617
28594
  ref: projectRef,
@@ -28622,220 +28599,12 @@ function registerDeployTools(server, http, options = {}) {
28622
28599
  ...configurationId ? { configuration_id: configurationId } : {},
28623
28600
  ...application.manifestPath ? { manifest_path: application.manifestPath } : {},
28624
28601
  ...args.skip_build === true ? { skip_build: true } : {},
28625
- ...stagedWeb?.request === undefined ? {} : { web: stagedWeb.request },
28602
+ ...stagedWeb?.request === undefined ? {} : { web_release: stagedWeb.request },
28626
28603
  ...args.json === true ? { format: "json", json: true } : {}
28627
28604
  });
28628
28605
  return result;
28629
28606
  }
28630
- const target = selectTarget(configRoot, invocationDirectory, config, String(args.target || "").trim() || undefined);
28631
- 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")))) {
28632
- 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.");
28633
- }
28634
- const projectDirectory = target.root;
28635
- const targetState = await lstat5(projectDirectory).catch(() => null);
28636
- if (!targetState?.isDirectory() || targetState.isSymbolicLink()) {
28637
- throw new Error(`Deploy target '${target.name}' root is not a regular directory: ${projectDirectory}`);
28638
- }
28639
- const requestedId = String(args.id || target.config.id || "").trim() || undefined;
28640
- const build = createBuildEnvironment(target.config.buildEnv, options.environmentVariables);
28641
- if (target.config.type === "edge_function") {
28642
- if (args.diff === true)
28643
- throw new Error("Function release diffs require an immutable function release manifest");
28644
- if (!options.edgeFunctionDeploy)
28645
- throw new Error("Edge Function deploy support is unavailable in this CLI context");
28646
- const slug = target.config.slug || requestedId || target.name;
28647
- const functionListResponse = await options.edgeFunctionDeploy({
28648
- action: "list",
28649
- ref: projectRef
28650
- });
28651
- if (functionListResponse.isError) {
28652
- throw new Error(`Unable to read the current identity for Edge Function '${slug}'`);
28653
- }
28654
- const functionListText = functionListResponse.content.find((chunk) => chunk.type === "text")?.text;
28655
- if (!functionListText)
28656
- throw new Error(`Unable to read the current identity for Edge Function '${slug}'`);
28657
- const functions = projectedFunctionList(JSON.parse(functionListText));
28658
- if (!functions)
28659
- throw new Error(`Invalid current identity for Edge Function '${slug}'`);
28660
- const current = functions?.find((candidate) => candidate.slug === slug);
28661
- const activeVersion = current && typeof current.version === "number" ? String(current.version) : "absent";
28662
- const activationId = current && typeof current.activation_id === "string" ? current.activation_id : "legacy";
28663
- if (!activeVersion || !activationId)
28664
- throw new Error(`Edge Function '${slug}' has an invalid active identity`);
28665
- const buildCommand = String(args.build_command || target.config.buildCommand || "").trim() || (args.skip_build === true ? "" : await defaultBuildCommand(projectDirectory, configRoot));
28666
- const bundleDirectory = resolveInsideProject(projectDirectory, String(args.output_dir || target.config.bundleDirectory || target.config.outputDirectory || "dist"), true);
28667
- if (args.dry_run === true || args.plan === true) {
28668
- return { content: [{ type: "text", text: JSON.stringify({
28669
- ok: true,
28670
- dry_run: true,
28671
- type: target.config.type,
28672
- target: target.name,
28673
- project_ref: projectRef,
28674
- slug,
28675
- build_command: args.skip_build === true ? null : buildCommand,
28676
- build_env: build.names,
28677
- missing_build_env: build.missing,
28678
- bundle_directory: bundleDirectory,
28679
- expected_active_version: activeVersion,
28680
- expected_activation_id: activationId
28681
- }, null, 2) }] };
28682
- }
28683
- assertBuildEnvironment(build, args.skip_build === true);
28684
- if (args.skip_build !== true) {
28685
- await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28686
- }
28687
- const deployed = await options.edgeFunctionDeploy({
28688
- action: "deploy_bundle",
28689
- ref: projectRef,
28690
- slug,
28691
- "bundle-dir": bundleDirectory,
28692
- entrypoint: target.config.entrypoint || "index.ts",
28693
- minify: target.config.minify,
28694
- verify_jwt: target.config.verifyJwt,
28695
- framework: target.config.framework,
28696
- "expected-active-version": activeVersion,
28697
- "expected-activation-id": activationId
28698
- });
28699
- if (deployed.isError)
28700
- return deployed;
28701
- const deployedText = deployed.content.find((chunk) => chunk.type === "text")?.text;
28702
- const deployedPayload = deployedText ? record4(JSON.parse(deployedText)) : null;
28703
- return deployResponse({
28704
- ok: true,
28705
- unchanged: false,
28706
- type: target.config.type,
28707
- target: target.name,
28708
- project_ref: projectRef,
28709
- slug,
28710
- active_version: deployedPayload?.active_version,
28711
- activation_id: deployedPayload?.activation_id
28712
- }, args.json === true);
28713
- }
28714
- const listResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments`);
28715
- if (!listResponse.ok)
28716
- throw new Error(`Failed to list frontend deployments (HTTP ${listResponse.status})`);
28717
- const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory));
28718
- const configuredBuildCommand = String(args.build_command || target.config.buildCommand || selected.buildCommand || "").trim();
28719
- const buildCommand = configuredBuildCommand || (args.skip_build === true ? "" : await defaultBuildCommand(projectDirectory, configRoot));
28720
- const configuredOutput = String(args.output_dir || target.config.outputDirectory || "").trim();
28721
- const remoteOutput = selected.outputDirectory && selected.outputDirectory !== "." ? selected.outputDirectory : "";
28722
- const outputDirectory = resolveInsideProject(projectDirectory, configuredOutput || remoteOutput || defaultOutputDirectory(selected.framework));
28723
- if (args.dry_run === true) {
28724
- return { content: [{ type: "text", text: JSON.stringify({
28725
- ok: true,
28726
- dry_run: true,
28727
- project_ref: projectRef,
28728
- deployment_id: selected.id,
28729
- build_command: args.skip_build === true ? null : buildCommand,
28730
- build_env: build.names,
28731
- missing_build_env: build.missing,
28732
- output_directory: outputDirectory
28733
- }, null, 2) }] };
28734
- }
28735
- assertBuildEnvironment(build, args.skip_build === true);
28736
- if (args.skip_build !== true) {
28737
- await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28738
- }
28739
- const archive = await createFrontendArchive(outputDirectory);
28740
- try {
28741
- const inventory = payload(await readFrontendReleaseAuthority(http, projectRef, selected.id));
28742
- const activeReleaseId = typeof inventory.active_release_id === "string" ? inventory.active_release_id : null;
28743
- const activeActivationId = typeof inventory.active_activation_id === "string" ? inventory.active_activation_id : null;
28744
- const current = Array.isArray(inventory.releases) ? record4(inventory.releases[0]) : null;
28745
- if (archive.sha256 === activeReleaseId && archive.treeSha256 !== current?.tree_sha256) {
28746
- throw new Error("Active release tree does not match the local archive");
28747
- }
28748
- const unchanged = archive.treeSha256 === current?.tree_sha256;
28749
- if (args.plan === true || args.diff === true) {
28750
- return { content: [{ type: "text", text: JSON.stringify({
28751
- schema: "supacloud.frontend-deploy-plan.v1",
28752
- ok: true,
28753
- planned: true,
28754
- published: false,
28755
- unchanged,
28756
- environment: options.environment ?? null,
28757
- type: "frontend",
28758
- target: target.name,
28759
- project_ref: projectRef,
28760
- deployment_id: selected.id,
28761
- comparison: "immutable_release",
28762
- archive_format: FRONTEND_ARCHIVE_FORMAT,
28763
- release_id: archive.sha256,
28764
- tree_sha256: archive.treeSha256,
28765
- active_release_id: activeReleaseId,
28766
- active_tree_sha256: current?.tree_sha256 ?? null,
28767
- expected_active_release_id: activeReleaseId ?? "absent",
28768
- expected_activation_id: activeActivationId ?? "absent",
28769
- actions: unchanged ? [] : ["upload_release", "activate_release"],
28770
- file_count: archive.fileCount,
28771
- source_bytes: archive.sourceBytes,
28772
- archive_bytes: archive.archiveBytes
28773
- }, null, 2) }] };
28774
- }
28775
- if (unchanged) {
28776
- return deployResponse({
28777
- ok: true,
28778
- unchanged: true,
28779
- project_ref: projectRef,
28780
- deployment_id: selected.id,
28781
- release_id: activeReleaseId,
28782
- tree_sha256: archive.treeSha256,
28783
- url: selected.deploymentUrl,
28784
- file_count: archive.fileCount,
28785
- source_bytes: archive.sourceBytes
28786
- }, args.json === true);
28787
- }
28788
- const uploaded = payload(await uploadFrontendRelease(http, projectRef, selected.id, archive.archivePath));
28789
- const release = record4(uploaded.release);
28790
- const releaseId = requiredString(release?.release_id, "release.release_id");
28791
- if (releaseId !== archive.sha256)
28792
- throw new Error("Uploaded release identity does not match the local archive");
28793
- if (release?.tree_sha256 !== archive.treeSha256)
28794
- throw new Error("Uploaded release tree does not match the local build");
28795
- const mutationId = crypto.randomUUID();
28796
- const activationResponse = await activateFrontendRelease(http, {
28797
- projectRef,
28798
- deploymentId: selected.id,
28799
- releaseId,
28800
- expectedActiveReleaseId: activeReleaseId || "absent",
28801
- expectedActivationId: activeActivationId || "absent",
28802
- mutationId
28803
- });
28804
- if (activationResponse.isError) {
28805
- const failure = record4(JSON.parse(activationResponse.content[0]?.text ?? "{}"));
28806
- return {
28807
- isError: true,
28808
- content: [{ type: "text", text: JSON.stringify({
28809
- ...failure,
28810
- operation: "deploy",
28811
- project_ref: projectRef,
28812
- deployment_id: selected.id,
28813
- mutation_id: mutationId,
28814
- target_release_id: releaseId,
28815
- expected_active_release_id: activeReleaseId ?? "absent",
28816
- expected_activation_id: activeActivationId ?? "absent"
28817
- }) }]
28818
- };
28819
- }
28820
- const activated = payload(activationResponse);
28821
- const finalResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments/${encodeURIComponent(selected.id)}`);
28822
- const finalDeployment = finalResponse.ok ? frontendDeployment(finalResponse.data) : selected;
28823
- return deployResponse({
28824
- ok: true,
28825
- unchanged: false,
28826
- project_ref: projectRef,
28827
- deployment_id: selected.id,
28828
- release_id: activated.active_release_id,
28829
- activation_id: activated.activation_id,
28830
- previous_release_id: activeReleaseId,
28831
- previous_activation_id: activeActivationId,
28832
- url: finalDeployment.deploymentUrl,
28833
- file_count: archive.fileCount,
28834
- source_bytes: archive.sourceBytes
28835
- }, args.json === true);
28836
- } finally {
28837
- await archive.cleanup();
28838
- }
28607
+ throw new Error(DEPLOYMENT_UPGRADE);
28839
28608
  });
28840
28609
  }
28841
28610
 
@@ -29127,6 +28896,7 @@ var TEST_PROFILE = [
29127
28896
  "SUPACLOUD_API_URL=https://management.test.example.com",
29128
28897
  "SUPACLOUD_API_TOKEN=<test-management-api-token>",
29129
28898
  "SUPACLOUD_PROJECT_REF=<test-project-ref>",
28899
+ "SUPACLOUD_APPLICATION_ID=<application-id>",
29130
28900
  ""
29131
28901
  ].join(`
29132
28902
  `);
@@ -29135,6 +28905,7 @@ var PRODUCTION_PROFILE = [
29135
28905
  "SUPACLOUD_API_URL=https://management.example.com",
29136
28906
  "SUPACLOUD_API_TOKEN=<production-management-api-token>",
29137
28907
  "SUPACLOUD_PROJECT_REF=<production-project-ref>",
28908
+ "SUPACLOUD_APPLICATION_ID=<application-id>",
29138
28909
  ""
29139
28910
  ].join(`
29140
28911
  `);
@@ -29258,6 +29029,7 @@ async function initializeProject(request, options) {
29258
29029
  },
29259
29030
  next: [
29260
29031
  "cp .env.supacloud.test.example .env.supacloud.test",
29032
+ "Set SUPACLOUD_APPLICATION_ID to the application's ID and configure its current SupaCloud delivery build.",
29261
29033
  "supacloud env check",
29262
29034
  "supacloud --env test deploy"
29263
29035
  ]
@@ -29305,17 +29077,16 @@ function statusMissing(context) {
29305
29077
  }
29306
29078
  return ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
29307
29079
  }
29308
- function deployMissing(context) {
29080
+ function deployMissing(context, application) {
29309
29081
  const missing = statusMissing(context);
29310
29082
  if (context.credentialScope !== "management") {
29311
29083
  return [...missing, "Management API context"];
29312
29084
  }
29313
- if (context.applicationId) {
29314
- if (!context.applicationEnvironmentId)
29315
- missing.push("SUPACLOUD_APPLICATION_ENVIRONMENT_ID");
29316
- if (!context.applicationConfigurationPath && !context.applicationConfigurationId) {
29317
- missing.push("SUPACLOUD_APPLICATION_CONFIGURATION_PATH or SUPACLOUD_APPLICATION_CONFIGURATION_ID");
29318
- }
29085
+ if (!Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
29086
+ missing.push("valid SUPACLOUD_APPLICATION_ID or supacloud.json application.id");
29087
+ }
29088
+ if (!Check2(ApplicationIdSchema, context.applicationEnvironmentId || application?.environmentId)) {
29089
+ missing.push("valid SUPACLOUD_APPLICATION_ENVIRONMENT_ID or SUPACLOUD_ENV");
29319
29090
  }
29320
29091
  return missing;
29321
29092
  }
@@ -29325,7 +29096,13 @@ async function inspectProfile(profile) {
29325
29096
  environmentName: profile.name
29326
29097
  });
29327
29098
  const status = statusMissing(context);
29328
- const deploy = deployMissing(context);
29099
+ const configText = await readFile8(join19(dirname12(profile.path), "supacloud.json"), "utf8").catch((error) => {
29100
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
29101
+ return "{}";
29102
+ throw error;
29103
+ });
29104
+ const config = record5(JSON.parse(configText));
29105
+ const deploy = deployMissing(context, record5(config?.application));
29329
29106
  return {
29330
29107
  name: profile.name,
29331
29108
  path: profile.path,
@@ -29418,109 +29195,10 @@ function registerDeveloperExperienceTools(server, options = {}) {
29418
29195
  registerTool(server, "init", "Create SupaCloud deployment configuration and non-secret environment examples without overwriting project files.", initToolSchema, (request) => initializeProject(request, options));
29419
29196
  registerTool(server, "env", "List or locally validate named SupaCloud environment profiles without contacting the platform or printing secrets.", environmentToolSchema, (request) => inspectEnvironment(request, options));
29420
29197
  }
29421
-
29422
- // src/shared/tools/project-deployment.ts
29423
- var operation = "applications.project_deploy";
29424
- var scopeSchema = _Object_({
29425
- project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
29426
- application_id: ApplicationIdSchema,
29427
- environment_id: ApplicationIdSchema
29428
- });
29429
- var statusSchema = _Object_({
29430
- schema: Literal("supacloud.project-deployment-status.v1"),
29431
- deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
29432
- status: Union([
29433
- Literal("pending"),
29434
- Literal("running"),
29435
- Literal("succeeded"),
29436
- Literal("failed_retryable"),
29437
- Literal("failed_terminal"),
29438
- Literal("outcome_unknown")
29439
- ]),
29440
- phase: Union([
29441
- Literal("queued"),
29442
- Literal("prepared"),
29443
- Literal("migrating"),
29444
- Literal("activating"),
29445
- Literal("binding-web"),
29446
- Literal("verifying")
29447
- ]),
29448
- operation: Literal("application.release.deploy"),
29449
- ...scopeSchema.properties,
29450
- receipt: Optional(Unknown()),
29451
- failure_code: Optional(String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }))
29452
- }, { additionalProperties: false });
29453
- function responseReceipt(data, expected) {
29454
- if (!data || typeof data !== "object" || Array.isArray(data) || !("ok" in data) || data.ok !== true) {
29455
- throw new Error("Invalid project deployment response");
29456
- }
29457
- const { ok: _ok, ...receipt } = data;
29458
- return parseApplicationDeployResult(receipt, expected);
29459
- }
29460
- async function runProjectDeployment(http, args) {
29461
- const scope = { project_ref: args.ref, application_id: args.id, environment_id: args.environment_id };
29462
- const request = {
29463
- mutation_id: args.mutation_id,
29464
- release_id: args.release_id,
29465
- ...args.configuration_id === undefined ? {} : { configuration_id: args.configuration_id },
29466
- ...args.configuration_write === undefined ? {} : { configuration_write: args.configuration_write },
29467
- ...args.expected_plan_sha256 === undefined ? {} : { expected_plan_sha256: args.expected_plan_sha256 },
29468
- ...args.approved_migration_digest === undefined ? {} : { approved_migration_digest: args.approved_migration_digest },
29469
- ...args.web === undefined ? {} : { web: args.web }
29470
- };
29471
- if (!Check2(scopeSchema, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
29472
- return releaseControlFailure(operation, "INVALID_RESPONSE", null);
29473
- }
29474
- const expected = { ...scope, request };
29475
- const identity = {
29476
- ...scope,
29477
- deployment_id: request.mutation_id,
29478
- mutation_id: request.mutation_id,
29479
- release_id: request.release_id
29480
- };
29481
- const endpoint = `/v1/projects/${encodeURIComponent(scope.project_ref)}/environments/${encodeURIComponent(scope.environment_id)}/deployments`;
29482
- const { mutation_id, ...candidate } = request;
29483
- const result = await http.post(endpoint, {
29484
- ...candidate,
29485
- deployment_id: mutation_id,
29486
- application_id: scope.application_id
29487
- }, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
29488
- if (result.ok && result.status === 200) {
29489
- try {
29490
- return releaseControlSuccess(operation, {
29491
- ...responseReceipt(result.data, expected),
29492
- deployment_id: mutation_id
29493
- });
29494
- } catch {}
29495
- } else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
29496
- return releaseControlMutationFailure(operation, result, identity);
29497
- }
29498
- const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
29499
- retry: false,
29500
- totalTimeoutMs: 30000,
29501
- maxJsonBytes: 131072
29502
- });
29503
- try {
29504
- if (!observed.ok || observed.status !== 200 || !Check2(statusSchema, observed.data))
29505
- throw new Error;
29506
- const state = observed.data;
29507
- 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")
29508
- throw new Error;
29509
- const receipt = parseApplicationDeployResult(state.receipt, expected);
29510
- return releaseControlSuccess(operation, {
29511
- ...receipt,
29512
- deployment_id: mutation_id,
29513
- replayed: true,
29514
- execution_performed: false
29515
- });
29516
- } catch {
29517
- return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
29518
- }
29519
- }
29520
29198
  // package.json
29521
29199
  var package_default = {
29522
29200
  name: "@supacloud/cli",
29523
- version: "0.92.0",
29201
+ version: "0.94.0",
29524
29202
  description: "Project-scoped CLI for SupaCloud users",
29525
29203
  type: "module",
29526
29204
  main: "./dist/index.js",
@@ -29573,13 +29251,13 @@ var package_default = {
29573
29251
  },
29574
29252
  dependencies: {
29575
29253
  "@supacloud/compiler": "^0.44.1",
29576
- "@supacloud/delivery": "0.15.1",
29577
- "@supacloud/db": "0.16.1",
29254
+ "@supacloud/delivery": "0.16.0",
29255
+ "@supacloud/db": "0.16.2",
29578
29256
  typebox: "1.3.36"
29579
29257
  },
29580
29258
  overrides: {
29581
29259
  "@supacloud/contracts": "0.8.1",
29582
- "@supacloud/delivery": "0.15.1",
29260
+ "@supacloud/delivery": "0.16.0",
29583
29261
  "@graphql-tools/utils": "^12.0.3"
29584
29262
  },
29585
29263
  devDependencies: {
@@ -29796,8 +29474,6 @@ EXAMPLES
29796
29474
  ${preferredCommand} deploy
29797
29475
  ${preferredCommand} --env test deploy
29798
29476
  ${preferredCommand} --env production deploy --confirm-production <project-ref>
29799
- ${preferredCommand} deploy --target web
29800
- ${preferredCommand} deploy --target api
29801
29477
  ${preferredCommand} dev sync --env test --target functions --function api
29802
29478
  ${preferredCommand} dev status --env test
29803
29479
  ${preferredCommand} dev watch --env test --target project
@@ -30153,8 +29829,7 @@ function createCliTools(context, confirmProduction) {
30153
29829
  applicationRelease: (args) => tools.app ? tools.app.callback(args) : Promise.resolve({
30154
29830
  isError: true,
30155
29831
  content: [{ type: "text", text: "Application release support is unavailable in this CLI context" }]
30156
- }),
30157
- edgeFunctionDeploy: advancedTools.edge_functions?.callback
29832
+ })
30158
29833
  })));
30159
29834
  assign(captureTools((server) => registerGatewayTools(server, http, {
30160
29835
  projectRef: context.projectRef || undefined