@supacloud/cli 0.96.0 → 0.96.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,11 +26,15 @@ supacloud --env test deploy
26
26
  overwriting an existing project configuration. `env list` and `env check` are
27
27
  local-only, redact credentials, and provide stable JSON with `--json` for CI or
28
28
  AI tooling. The real `.env.supacloud.*` files are added to `.gitignore`.
29
- Fill in `SUPACLOUD_APPLICATION_ID` and the Management credentials in the
30
- selected profile, and configure the application's current delivery build.
31
- Standalone frontend deployment is no longer supported. Upgrade the CLI with
29
+ Fill in the Management credentials and project/environment in the selected profile.
30
+ Static frontends need only `frontend` build configuration; no application binding
31
+ or backend delivery build is required. Set `SUPACLOUD_APPLICATION_ID` only for
32
+ executable application delivery. Upgrade the CLI with
32
33
  `npm install -g @supacloud/cli@latest` and upgrade the SupaCloud server together.
33
34
  `deploy` checks the server protocol before building or uploading.
35
+ Use `frontend.name` to select exactly one named site in each environment when
36
+ deployment IDs differ. A missing or ambiguous name fails before upload; it never
37
+ falls back to another site.
34
38
 
35
39
  ## Application Starter
36
40
 
@@ -645,7 +649,12 @@ FA-owned business features are documented in
645
649
  and `--dry_run` are removed. Put build settings in `supacloud.json`; use
646
650
  `app deploy-plan` for read-only review. Historical project-specific manifests
647
651
  and standalone Function targets must move to application delivery configuration.
648
- The CLI rejects them rather than falling back to a partial Web deployment.
652
+ The CLI rejects them rather than silently falling back to a partial Web deployment.
653
+ For an intentional Web-only release in a mixed repository, use
654
+ `supacloud --env test deploy --assets_only`. This preserves historical manifests,
655
+ Functions, schedules and migrations without invoking application compilation.
656
+ Static publication reuses immutable archives, pre-upload CAS, mutation receipts
657
+ and exact post-activation readback. It never retries a conflicting activation.
649
658
 
650
659
  The legacy `.env` fallback is unclassified and therefore does not enable the
651
660
  production confirmation gate. Production automation must select a `prod` or
package/dist/index.js CHANGED
@@ -8767,7 +8767,7 @@ function outcomeUnknownGuidance(text) {
8767
8767
  }
8768
8768
 
8769
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.";
8770
+ var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
8771
8771
  var removedFrontendActions = new Set([
8772
8772
  "deploy_git",
8773
8773
  "deploy_upload",
@@ -16350,6 +16350,39 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
16350
16350
  }
16351
16351
  return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16352
16352
  }
16353
+ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath) {
16354
+ const endpoint = releaseEndpoint(projectRef, deploymentId);
16355
+ const archive = await verifiedArchive(archivePath);
16356
+ let response;
16357
+ try {
16358
+ response = await http.postBinary(endpoint, {
16359
+ stream: archiveStream(archive),
16360
+ byteLength: archive.sizeBytes
16361
+ }, {
16362
+ contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
16363
+ contentLength: archive.sizeBytes,
16364
+ contentSha256: archive.sha256,
16365
+ maxJsonBytes: RESPONSE_MAX_BYTES,
16366
+ timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
16367
+ responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
16368
+ });
16369
+ } finally {
16370
+ await archive.handle.close();
16371
+ }
16372
+ const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
16373
+ if (!release) {
16374
+ if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
16375
+ return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
16376
+ }
16377
+ return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
16378
+ }
16379
+ const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
16380
+ const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
16381
+ if (!verified || verified.tree_sha256 !== release.tree_sha256) {
16382
+ return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", readback.status);
16383
+ }
16384
+ return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release: verified });
16385
+ }
16353
16386
  async function uploadProjectWebRelease(http, projectRef, environmentId, deploymentId, archivePath) {
16354
16387
  const endpoint = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/web-release?deployment_id=${encodeURIComponent(deploymentId)}`;
16355
16388
  const archive = await verifiedArchive(archivePath);
@@ -16404,6 +16437,16 @@ async function uploadProjectWebRelease(http, projectRef, environmentId, deployme
16404
16437
  await archive.handle.close();
16405
16438
  }
16406
16439
  }
16440
+ async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadStatus) {
16441
+ const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
16442
+ maxJsonBytes: RESPONSE_MAX_BYTES
16443
+ });
16444
+ const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
16445
+ if (!release) {
16446
+ return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
16447
+ }
16448
+ return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
16449
+ }
16407
16450
  function stableJson(candidate) {
16408
16451
  if (candidate === null || typeof candidate !== "object")
16409
16452
  return JSON.stringify(candidate);
@@ -16523,6 +16566,57 @@ async function getActiveFrontendRelease(http, projectRef, deploymentId) {
16523
16566
  const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
16524
16567
  return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
16525
16568
  }
16569
+ async function publishFrontendRelease(http, projectRef, deploymentId, archivePath, expectedTreeSha256) {
16570
+ const authority = await readActiveFrontendRelease(http, projectRef, deploymentId);
16571
+ if ("failure" in authority)
16572
+ return authority.failure;
16573
+ const inventory = authority.inventory;
16574
+ const current = inventory.releases[0];
16575
+ if (current?.tree_sha256 === expectedTreeSha256) {
16576
+ return toolResponse({
16577
+ operation: "frontend.deploy",
16578
+ project_ref: projectRef,
16579
+ deployment_id: deploymentId,
16580
+ active_release_id: inventory.active_release_id,
16581
+ activation_id: inventory.active_activation_id,
16582
+ release: current,
16583
+ unchanged: true
16584
+ });
16585
+ }
16586
+ const uploaded = await uploadFrontendRelease(http, projectRef, deploymentId, archivePath);
16587
+ if (uploaded.isError)
16588
+ return uploaded;
16589
+ const value = JSON.parse(uploaded.content[0].text);
16590
+ const envelope = value && typeof value === "object" && !Array.isArray(value) ? value : null;
16591
+ const candidate = envelope?.release;
16592
+ const release = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
16593
+ if (!release || release.tree_sha256 !== expectedTreeSha256 || typeof release.release_id !== "string" || !RELEASE_ID_PATTERN.test(release.release_id)) {
16594
+ return releaseFailure("frontend.deploy", "INVALID_RESPONSE", 200);
16595
+ }
16596
+ const mutationId = crypto.randomUUID();
16597
+ const activated = await activateFrontendRelease(http, {
16598
+ projectRef,
16599
+ deploymentId,
16600
+ releaseId: release.release_id,
16601
+ mutationId,
16602
+ expectedActiveReleaseId: inventory.active_release_id ?? "absent",
16603
+ expectedActivationId: inventory.active_activation_id ?? "absent"
16604
+ });
16605
+ const activatedPayload = JSON.parse(activated.content[0].text);
16606
+ const active = activatedPayload.release;
16607
+ const treeMismatch = !activated.isError && (!active || typeof active !== "object" || !("tree_sha256" in active) || active.tree_sha256 !== expectedTreeSha256);
16608
+ return {
16609
+ ...toolResponse({
16610
+ ...treeMismatch ? { ok: false, error: { code: "OUTCOME_UNKNOWN", http_status: 200 } } : activatedPayload,
16611
+ operation: "frontend.deploy",
16612
+ mutation_id: mutationId,
16613
+ target_release_id: release.release_id,
16614
+ previous_release_id: inventory.active_release_id,
16615
+ previous_activation_id: inventory.active_activation_id
16616
+ }),
16617
+ ...activated.isError || treeMismatch ? { isError: true } : {}
16618
+ };
16619
+ }
16526
16620
  async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId) {
16527
16621
  if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
16528
16622
  throw new Error("'release_id' must be a SHA-256 digest");
@@ -28186,6 +28280,7 @@ var deployToolSchema = {
28186
28280
  ref: optional(String2(), "Project ref (defaults to the linked project)"),
28187
28281
  cwd: optional(String2(), "Project directory (default: current directory)"),
28188
28282
  skip_build: optional(Boolean2(), "Use an existing output directory without building"),
28283
+ assets_only: optional(Boolean2(), "Publish only configured static assets; leave backend Functions, schedules and migrations unchanged"),
28189
28284
  json: optional(Boolean2(), "Print only the final JSON result")
28190
28285
  };
28191
28286
  function record4(candidate) {
@@ -28280,6 +28375,7 @@ function deployTargetConfig(candidate, name) {
28280
28375
  type: value.type,
28281
28376
  root: optionalText(value.root, `targets.${name}.root`),
28282
28377
  id: optionalText(value.id, `targets.${name}.id`),
28378
+ name: optionalText(value.name, `targets.${name}.name`),
28283
28379
  slug: optionalText(value.slug, `targets.${name}.slug`),
28284
28380
  buildCommand: optionalText(value.buildCommand, `targets.${name}.buildCommand`),
28285
28381
  outputDirectory: optionalText(value.outputDirectory, `targets.${name}.outputDirectory`),
@@ -28330,6 +28426,7 @@ async function readDeployConfig(configRoot) {
28330
28426
  targets: targetValues ? Object.fromEntries(Object.entries(targetValues).map(([name, value]) => [name, deployTargetConfig(value, name)])) : undefined,
28331
28427
  frontend: frontend ? {
28332
28428
  id: optionalText(frontend.id, "frontend.id"),
28429
+ name: optionalText(frontend.name, "frontend.name"),
28333
28430
  root: optionalText(frontend.root, "frontend.root"),
28334
28431
  buildCommand: optionalText(frontend.buildCommand, "frontend.buildCommand"),
28335
28432
  outputDirectory: optionalText(frontend.outputDirectory, "frontend.outputDirectory"),
@@ -28392,13 +28489,22 @@ function deploymentList(candidate) {
28392
28489
  throw new Error("Invalid frontend deployment list response");
28393
28490
  return values.map(frontendDeployment);
28394
28491
  }
28395
- function selectDeployment(deployments, requestedId, projectName) {
28492
+ function selectDeployment(deployments, requestedId, projectName, requestedName) {
28396
28493
  if (requestedId) {
28397
28494
  const selected = deployments.find((deployment) => deployment.id === requestedId);
28398
28495
  if (!selected)
28399
28496
  throw new Error(`Frontend deployment '${requestedId}' was not found`);
28497
+ if (requestedName && selected.name !== requestedName) {
28498
+ throw new Error(`Frontend deployment '${requestedId}' does not match name '${requestedName}'`);
28499
+ }
28400
28500
  return selected;
28401
28501
  }
28502
+ if (requestedName) {
28503
+ const matches = deployments.filter((deployment) => deployment.name === requestedName);
28504
+ if (matches.length !== 1)
28505
+ throw new Error(`Expected exactly one frontend deployment named '${requestedName}'`);
28506
+ return matches[0];
28507
+ }
28402
28508
  if (deployments.length === 1)
28403
28509
  return deployments[0];
28404
28510
  if (projectName) {
@@ -28416,6 +28522,7 @@ function selectFrontendTarget(configRoot, config) {
28416
28522
  type: "frontend",
28417
28523
  root: config.frontend?.root,
28418
28524
  id: config.frontend?.id,
28525
+ name: config.frontend?.name,
28419
28526
  buildCommand: config.frontend?.buildCommand,
28420
28527
  outputDirectory: config.frontend?.outputDirectory,
28421
28528
  buildEnv: config.frontend?.buildEnv
@@ -28580,7 +28687,7 @@ function payload(response) {
28580
28687
  throw new Error("Deployment operation returned an invalid response");
28581
28688
  return parsed;
28582
28689
  }
28583
- async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables) {
28690
+ async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables, assetsOnly = false) {
28584
28691
  const target = selectFrontendTarget(configRoot, await readDeployConfig(configRoot));
28585
28692
  if (!target)
28586
28693
  return null;
@@ -28593,7 +28700,7 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
28593
28700
  const listResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments`);
28594
28701
  if (!listResponse.ok)
28595
28702
  throw new Error(`Failed to list frontend deployments (HTTP ${listResponse.status})`);
28596
- const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory));
28703
+ const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory), target.config.name);
28597
28704
  const configuredBuildCommand = String(target.config.buildCommand || selected.buildCommand || "").trim();
28598
28705
  const buildCommand = configuredBuildCommand || (skipBuild ? "" : await defaultBuildCommand(projectDirectory, configRoot));
28599
28706
  const configuredOutput = String(target.config.outputDirectory || "").trim();
@@ -28606,6 +28713,9 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
28606
28713
  }
28607
28714
  const archive = await createFrontendArchive(outputDirectory);
28608
28715
  try {
28716
+ if (assetsOnly) {
28717
+ return { result: await publishFrontendRelease(http, projectRef, selected.id, archive.archivePath, archive.treeSha256) };
28718
+ }
28609
28719
  const uploaded = payload(await uploadProjectWebRelease(http, projectRef, environmentId, selected.id, archive.archivePath));
28610
28720
  const release = record4(uploaded.release);
28611
28721
  const releaseId = requiredString(release?.release_id, "release.release_id");
@@ -28635,7 +28745,23 @@ function registerDeployTools(server, http, options = {}) {
28635
28745
  ...config.application,
28636
28746
  environmentId: options.environment || config.application.environmentId
28637
28747
  } : undefined;
28638
- if (await hasProjectReleaseManifest(configRoot)) {
28748
+ const legacyManifest = await hasProjectReleaseManifest(configRoot);
28749
+ const assetsOnly = args.assets_only === true || !application?.id && selectFrontendTarget(configRoot, config) !== null && !legacyManifest && !Object.values(config.targets ?? {}).some((target) => target.type === "edge_function");
28750
+ if (assetsOnly) {
28751
+ if (!selectFrontendTarget(configRoot, config)) {
28752
+ throw new Error("Static asset deployment requires a frontend configuration in supacloud.json");
28753
+ }
28754
+ const environmentId = options.environment?.trim() || application?.environmentId?.trim();
28755
+ if (!environmentId || !Check2(ApplicationIdSchema, environmentId)) {
28756
+ throw new Error("Static asset deployment requires SUPACLOUD_ENV");
28757
+ }
28758
+ await requireProjectDeploymentProtocol(http, projectRef, environmentId);
28759
+ const staged = await stageApplicationWebRelease(http, projectRef, environmentId, configRoot, args.skip_build === true, args.json === true, options.environmentVariables, true);
28760
+ if (!staged?.result)
28761
+ throw new Error("Static asset deployment did not produce a receipt");
28762
+ return staged.result;
28763
+ }
28764
+ if (legacyManifest) {
28639
28765
  throw new Error(`${DEPLOYMENT_UPGRADE} Replace deploy-manifest.json with the current application delivery configuration; no remote mutation was performed.`);
28640
28766
  }
28641
28767
  if (application?.id) {
@@ -28963,7 +29089,7 @@ var TEST_PROFILE = [
28963
29089
  "SUPACLOUD_API_URL=https://management.test.example.com",
28964
29090
  "SUPACLOUD_API_TOKEN=<test-management-api-token>",
28965
29091
  "SUPACLOUD_PROJECT_REF=<test-project-ref>",
28966
- "SUPACLOUD_APPLICATION_ID=<application-id>",
29092
+ "# Optional for executable application delivery: SUPACLOUD_APPLICATION_ID=<application-id>",
28967
29093
  ""
28968
29094
  ].join(`
28969
29095
  `);
@@ -28972,7 +29098,7 @@ var PRODUCTION_PROFILE = [
28972
29098
  "SUPACLOUD_API_URL=https://management.example.com",
28973
29099
  "SUPACLOUD_API_TOKEN=<production-management-api-token>",
28974
29100
  "SUPACLOUD_PROJECT_REF=<production-project-ref>",
28975
- "SUPACLOUD_APPLICATION_ID=<application-id>",
29101
+ "# Optional for executable application delivery: SUPACLOUD_APPLICATION_ID=<application-id>",
28976
29102
  ""
28977
29103
  ].join(`
28978
29104
  `);
@@ -29096,7 +29222,7 @@ async function initializeProject(request, options) {
29096
29222
  },
29097
29223
  next: [
29098
29224
  "cp .env.supacloud.test.example .env.supacloud.test",
29099
- "Set SUPACLOUD_APPLICATION_ID to the application's ID and configure its current SupaCloud delivery build.",
29225
+ "Configure frontend assets; set SUPACLOUD_APPLICATION_ID only for executable application delivery.",
29100
29226
  "supacloud env check",
29101
29227
  "supacloud --env test deploy"
29102
29228
  ]
@@ -29144,12 +29270,12 @@ function statusMissing(context) {
29144
29270
  }
29145
29271
  return ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
29146
29272
  }
29147
- function deployMissing(context, application) {
29273
+ function deployMissing(context, application, hasFrontend = false) {
29148
29274
  const missing = statusMissing(context);
29149
29275
  if (context.credentialScope !== "management") {
29150
29276
  return [...missing, "Management API context"];
29151
29277
  }
29152
- if (!Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
29278
+ if (!(hasFrontend && !context.applicationId && !application) && !Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
29153
29279
  missing.push("valid SUPACLOUD_APPLICATION_ID or supacloud.json application.id");
29154
29280
  }
29155
29281
  if (!Check2(ApplicationIdSchema, context.applicationEnvironmentId || application?.environmentId)) {
@@ -29169,7 +29295,8 @@ async function inspectProfile(profile) {
29169
29295
  throw error;
29170
29296
  });
29171
29297
  const config = record5(JSON.parse(configText));
29172
- const deploy = deployMissing(context, record5(config?.application));
29298
+ const hasFrontend = record5(config?.frontend) !== null || Object.values(record5(config?.targets) ?? {}).some((target) => record5(target)?.type === "frontend");
29299
+ const deploy = deployMissing(context, record5(config?.application), hasFrontend);
29173
29300
  return {
29174
29301
  name: profile.name,
29175
29302
  path: profile.path,
@@ -29265,7 +29392,7 @@ function registerDeveloperExperienceTools(server, options = {}) {
29265
29392
  // package.json
29266
29393
  var package_default = {
29267
29394
  name: "@supacloud/cli",
29268
- version: "0.96.0",
29395
+ version: "0.96.1",
29269
29396
  description: "Project-scoped CLI for SupaCloud users",
29270
29397
  type: "module",
29271
29398
  main: "./dist/index.js",
@@ -1,2 +1,2 @@
1
- export declare const 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.";
1
+ export declare const DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
2
2
  export declare function assertCurrentDeploymentInput(tool: string, input: unknown): void;
@@ -26,6 +26,7 @@ export declare const deployToolSchema: {
26
26
  ref: Type.TOptional<Type.TString>;
27
27
  cwd: Type.TOptional<Type.TString>;
28
28
  skip_build: Type.TOptional<Type.TBoolean>;
29
+ assets_only: Type.TOptional<Type.TBoolean>;
29
30
  json: Type.TOptional<Type.TBoolean>;
30
31
  };
31
32
  export declare function findDeployConfigRoot(startDirectory: string, environmentName?: string): Promise<string>;
@@ -15,7 +15,7 @@ export declare const environmentToolSchema: ToolSchema;
15
15
  declare function outputDirectoryFor(manifest: PackageManifest): string;
16
16
  declare function profileNameFromFile(name: string): string | null;
17
17
  declare function statusMissing(context: ResolvedContext): string[];
18
- declare function deployMissing(context: ResolvedContext, application?: Record<string, unknown> | null): string[];
18
+ declare function deployMissing(context: ResolvedContext, application?: Record<string, unknown> | null, hasFrontend?: boolean): string[];
19
19
  export declare function registerDeveloperExperienceTools(server: ToolServer, options?: DeveloperExperienceOptions): void;
20
20
  export declare const __internal: {
21
21
  outputDirectoryFor: typeof outputDirectoryFor;
@@ -46,6 +46,7 @@ export declare function uploadProjectWebRelease(http: FrontendReleaseHttp, proje
46
46
  export declare function uploadFrontendSource(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, archivePath: string): Promise<ToolResponse>;
47
47
  export declare function getActiveFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string): Promise<ToolResponse>;
48
48
  export declare function readFrontendReleaseAuthority(http: FrontendReleaseHttp, projectRef: string, deploymentId: string): Promise<ToolResponse>;
49
+ export declare function publishFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, archivePath: string, expectedTreeSha256: string): Promise<ToolResponse>;
49
50
  export declare function rollbackFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, releaseId?: string): Promise<ToolResponse>;
50
51
  export declare function activateFrontendRelease(http: FrontendReleaseHttp, input: {
51
52
  projectRef: string;
@@ -131,7 +131,7 @@ import { Type as Type2 } from "typebox";
131
131
  import { Value as Value2 } from "typebox/value";
132
132
 
133
133
  // src/shared/deployment-upgrade.ts
134
- 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.";
134
+ var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
135
135
  var removedFrontendActions = new Set([
136
136
  "deploy_git",
137
137
  "deploy_upload",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/cli",
3
- "version": "0.96.0",
3
+ "version": "0.96.1",
4
4
  "description": "Project-scoped CLI for SupaCloud users",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",