@supacloud/cli 0.84.0 → 0.86.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/README.md CHANGED
@@ -310,6 +310,26 @@ legacy `.env` fallback. Core URL, credential, and project-ref values are not
310
310
  filled by mixing sources. If `SUPACLOUD_ENV` is set without a complete process
311
311
  context, it strictly selects `.env.supacloud.<value>`.
312
312
 
313
+ For one-command deployments, declare public build variables explicitly in the
314
+ target configuration:
315
+
316
+ ```json
317
+ {
318
+ "targets": {
319
+ "web": {
320
+ "type": "frontend",
321
+ "root": "apps/web",
322
+ "id": "web",
323
+ "buildEnv": ["VITE_API_URL", "VITE_SUPABASE_ANON_KEY"]
324
+ }
325
+ }
326
+ }
327
+ ```
328
+
329
+ `buildEnv` is an allowlist. The selected profile values are injected only into
330
+ the local build command; values are never printed, undeclared values are not
331
+ passed through, and platform credentials or runtime secrets are rejected.
332
+
313
333
  The two credential scopes are separate. Management-backed remote commands use
314
334
  only `SUPACLOUD_API_URL` + `SUPACLOUD_API_TOKEN`. An application profile using
315
335
  `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY` can be auto-linked for `status`,
@@ -884,11 +904,12 @@ whether the body is empty and the configured header names. Update receipts bind
884
904
  delete receipts return the matched revision as `deleted_updated_at`.
885
905
 
886
906
  For secret writes, `--from-env` accepts a comma-separated list of environment
887
- variable names. The CLI reads each non-empty value from its own process
888
- environment, so command arguments contain names only and values are never
889
- printed. Names must be unique shell-style identifiers (`[A-Za-z_][A-Za-z0-9_]*`,
890
- up to 256 characters). Missing or empty values fail before any HTTP request.
891
- Do not combine `--from-env` with the compatibility `--secrets` input.
907
+ variable names. The CLI reads each non-empty value from the currently selected
908
+ profile source, such as `.env.supacloud.test` selected by `--env test`; command
909
+ arguments contain names only and values are never printed. Names must be unique
910
+ shell-style identifiers (`[A-Za-z_][A-Za-z0-9_]*`, up to 256 characters).
911
+ Missing or empty values fail before any HTTP request. Do not combine
912
+ `--from-env` with the compatibility `--secrets` input.
892
913
 
893
914
  Branch promotion is migration-first. `branch promotion_plan` prints pending
894
915
  versions, names, statement counts, and checksums without echoing SQL into terminal
package/dist/index.js CHANGED
@@ -9144,6 +9144,7 @@ function resolveSupaCloudContext(env = process.env, cwd = process.cwd(), selecti
9144
9144
  credentialScope: core.credentialScope,
9145
9145
  source: source.kind,
9146
9146
  sourcePath: source.path,
9147
+ environmentVariables: source.values,
9147
9148
  insecureTls
9148
9149
  };
9149
9150
  }
@@ -9153,7 +9154,7 @@ var ACTION_POLICY = {
9153
9154
  deploy: { write: ["deploy"] },
9154
9155
  applications: {
9155
9156
  read: ["list_releases", "get_release", "get_runtime", "get_deployment_evidence", "get_configuration", "get_release_transfer_plan", "get_promotion_plan", "get_promotion_status", "get_rollback_snapshot", "get_history", "get_deploy_plan", "logs", "get_preview_plan", "list_previews", "get_preview"],
9156
- write: ["upload_release", "put_configuration", "transfer_release", "promote_application", "reconcile_promotion", "create_preview", "reconcile_preview", "cleanup_preview", "activate_release", "deploy_release", "rollback_release", "reconcile_activation", "retire_activation"]
9157
+ write: ["upload_release", "put_configuration", "release_application", "transfer_release", "promote_application", "reconcile_promotion", "create_preview", "reconcile_preview", "cleanup_preview", "activate_release", "deploy_release", "rollback_release", "reconcile_activation", "retire_activation"]
9157
9158
  },
9158
9159
  project: {
9159
9160
  read: ["get", "endpoints", "health", "logs", "api_keys", "settings", "tasks", "task_detail", "task_stats", "dlq", "background_settings"],
@@ -9249,7 +9250,7 @@ var ACTION_POLICY = {
9249
9250
  app: {
9250
9251
  local: ["init", "generate", "dev", "watch", "verify-plan", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
9251
9252
  read: ["status", "logs", "transfer-plan", "promote-plan", "rollback-plan", "history", "deploy-plan", "diff", "promote-status", "preview-plan", "previews", "preview-list", "preview-status"],
9252
- write: ["upload", "configure", "transfer", "promote", "promote-reconcile", "deploy", "rollback", "reconcile", "retire", "preview", "preview-create", "preview-reconcile", "preview-cleanup"]
9253
+ write: ["release", "upload", "configure", "transfer", "promote", "promote-reconcile", "deploy", "rollback", "reconcile", "retire", "preview", "preview-create", "preview-reconcile", "preview-cleanup"]
9253
9254
  },
9254
9255
  db: {
9255
9256
  local: ["context", "lint", "explain", "diff", "role_sql"],
@@ -10477,6 +10478,37 @@ function parseApplicationDeployPlan(value) {
10477
10478
  throw new Error("Invalid application deploy plan action");
10478
10479
  return value;
10479
10480
  }
10481
+ // node_modules/@supacloud/delivery/src/application-release-operation.ts
10482
+ var closed3 = { additionalProperties: false };
10483
+ var nullableActivation = Union([ApplicationActivationIdSchema, Null()]);
10484
+ var ApplicationReleaseRequestSchema = _Object_({
10485
+ release_id: ApplicationReleaseIdSchema,
10486
+ configuration_id: Optional(ApplicationConfigurationIdSchema),
10487
+ configuration_write: Optional(ApplicationConfigurationWriteSchema),
10488
+ activation_id: Optional(ApplicationActivationIdSchema),
10489
+ expected_activation_id: Optional(nullableActivation),
10490
+ expected_plan_sha256: Optional(ApplicationReleaseIdSchema)
10491
+ }, closed3);
10492
+ var ApplicationReleaseResultSchema = _Object_({
10493
+ schema: Literal("supacloud.application-release.v1"),
10494
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
10495
+ application_id: ApplicationIdSchema,
10496
+ environment_id: ApplicationIdSchema,
10497
+ release_id: ApplicationReleaseIdSchema,
10498
+ configuration_id: ApplicationConfigurationIdSchema,
10499
+ activation_id: ApplicationActivationIdSchema,
10500
+ expected_activation_id: nullableActivation,
10501
+ plan_sha256: ApplicationReleaseIdSchema,
10502
+ action: Union([Literal("activate"), Literal("no-op")]),
10503
+ replayed: Boolean2(),
10504
+ execution_performed: Boolean2()
10505
+ }, closed3);
10506
+ function parseApplicationReleaseResult(value) {
10507
+ if (!Check2(ApplicationReleaseResultSchema, value)) {
10508
+ throw new Error("Invalid application release result");
10509
+ }
10510
+ return structuredClone(value);
10511
+ }
10480
10512
  // node_modules/@supacloud/delivery/src/application-history.ts
10481
10513
  var scope = {
10482
10514
  project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
@@ -10561,7 +10593,7 @@ var phaseStatus = Union([
10561
10593
  Literal("failed"),
10562
10594
  Literal("cleaned")
10563
10595
  ]);
10564
- var closed3 = { additionalProperties: false };
10596
+ var closed4 = { additionalProperties: false };
10565
10597
  var ApplicationPreviewReceiptSchema = _Object_({
10566
10598
  schema: Literal("supacloud.application-preview.v1"),
10567
10599
  preview_id: String2({ pattern: "^[a-f0-9-]{8,64}$" }),
@@ -10581,46 +10613,46 @@ var ApplicationPreviewReceiptSchema = _Object_({
10581
10613
  Literal("cleaned")
10582
10614
  ]),
10583
10615
  resources: _Object_({
10584
- build_artifact: _Object_({ status: phaseStatus, release_id: ApplicationReleaseIdSchema }, closed3),
10616
+ build_artifact: _Object_({ status: phaseStatus, release_id: ApplicationReleaseIdSchema }, closed4),
10585
10617
  database_branch: _Object_({
10586
10618
  status: phaseStatus,
10587
10619
  branch_ref: String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" }),
10588
10620
  data_mode: Union([Literal("schema_only"), Literal("full_clone")])
10589
- }, closed3),
10621
+ }, closed4),
10590
10622
  queue_namespace: _Object_({
10591
10623
  status: phaseStatus,
10592
10624
  namespace: String2({ minLength: 1, maxLength: 128 })
10593
- }, closed3),
10625
+ }, closed4),
10594
10626
  storage_namespace: _Object_({
10595
10627
  status: phaseStatus,
10596
10628
  namespace: String2({ minLength: 1, maxLength: 128 })
10597
- }, closed3),
10629
+ }, closed4),
10598
10630
  test_secret: _Object_({
10599
10631
  status: phaseStatus,
10600
10632
  name: String2({ minLength: 1, maxLength: 128 }),
10601
10633
  value_issued: Literal(false)
10602
- }, closed3),
10634
+ }, closed4),
10603
10635
  configuration_revision: _Object_({
10604
10636
  status: phaseStatus,
10605
10637
  configuration_id: Union([ApplicationConfigurationIdSchema, Null()])
10606
- }, closed3),
10638
+ }, closed4),
10607
10639
  application_activation: _Object_({
10608
10640
  status: phaseStatus,
10609
10641
  activation_id: Union([ApplicationActivationIdSchema, Null()])
10610
- }, closed3),
10642
+ }, closed4),
10611
10643
  smoke_test: _Object_({
10612
10644
  status: phaseStatus,
10613
10645
  checks: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 32 }),
10614
10646
  passed: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 32 }),
10615
10647
  failed: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 32 })
10616
- }, closed3)
10617
- }, closed3),
10648
+ }, closed4)
10649
+ }, closed4),
10618
10650
  cleanup: _Object_({
10619
10651
  required: Boolean2(),
10620
10652
  completed: Boolean2(),
10621
10653
  error: Union([String2({ minLength: 1, maxLength: 128 }), Null()])
10622
- }, closed3)
10623
- }, closed3);
10654
+ }, closed4)
10655
+ }, closed4);
10624
10656
  function applicationPreviewBranchRef(previewId) {
10625
10657
  if (!/^[a-f0-9-]{8,64}$/.test(previewId))
10626
10658
  throw new Error("Invalid preview ID");
@@ -10673,7 +10705,7 @@ function parseApplicationReleaseTransferResult(candidate) {
10673
10705
  return candidate;
10674
10706
  }
10675
10707
  // node_modules/@supacloud/delivery/src/deployment-evidence.ts
10676
- var closed4 = { additionalProperties: false };
10708
+ var closed5 = { additionalProperties: false };
10677
10709
  var sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
10678
10710
  var isoDate = String2({ minLength: 20, maxLength: 40 });
10679
10711
  var status = Union([
@@ -10700,19 +10732,19 @@ var DatabaseProviderSchema = _Object_({
10700
10732
  Literal("not-proven"),
10701
10733
  Literal("failed")
10702
10734
  ])
10703
- }, closed4),
10735
+ }, closed5),
10704
10736
  backup: _Object_({
10705
10737
  status,
10706
10738
  latest_success_at: Union([isoDate, Null()]),
10707
10739
  freshness_seconds: Union([Integer({ minimum: 0 }), Null()])
10708
- }, closed4),
10740
+ }, closed5),
10709
10741
  recovery: _Object_({
10710
10742
  status,
10711
10743
  drill_id: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
10712
10744
  rpo_seconds: Union([Integer({ minimum: 0 }), Null()]),
10713
10745
  rto_seconds: Union([Integer({ minimum: 0 }), Null()])
10714
- }, closed4)
10715
- }, closed4);
10746
+ }, closed5)
10747
+ }, closed5);
10716
10748
  var componentName = Union([
10717
10749
  Literal("management-api"),
10718
10750
  Literal("web-console"),
@@ -10730,7 +10762,7 @@ var DeploymentComponentEvidenceSchema = _Object_({
10730
10762
  status,
10731
10763
  health_check: Union([String2({ minLength: 1, maxLength: 256 }), Null()]),
10732
10764
  checked_at: Union([isoDate, Null()])
10733
- }, closed4);
10765
+ }, closed5);
10734
10766
  var DeploymentEvidenceSchema = _Object_({
10735
10767
  schema: Literal(DEPLOYMENT_EVIDENCE_SCHEMA),
10736
10768
  status: evidenceStatus,
@@ -10739,33 +10771,33 @@ var DeploymentEvidenceSchema = _Object_({
10739
10771
  project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
10740
10772
  application_id: ApplicationIdSchema,
10741
10773
  environment_id: ApplicationIdSchema
10742
- }, closed4),
10774
+ }, closed5),
10743
10775
  source: _Object_({
10744
10776
  commit_sha: Union([String2({ pattern: "^[0-9a-f]{7,64}$" }), Null()]),
10745
10777
  manifest_sha256: sha256,
10746
10778
  contract_schema: Union([String2({ minLength: 1, maxLength: 128 }), Null()]),
10747
10779
  environment_binding_version: Union([sha256, Null()])
10748
- }, closed4),
10780
+ }, closed5),
10749
10781
  database: DatabaseProviderSchema,
10750
10782
  components: _Array_(DeploymentComponentEvidenceSchema, { minItems: 1, maxItems: 32 }),
10751
10783
  activation: _Object_({
10752
10784
  release_id: ApplicationReleaseIdSchema,
10753
10785
  configuration_id: ApplicationConfigurationIdSchema,
10754
10786
  activation_id: ApplicationConfigurationIdSchema
10755
- }, closed4),
10787
+ }, closed5),
10756
10788
  health: _Object_({
10757
10789
  status,
10758
10790
  checked_at: Union([isoDate, Null()]),
10759
10791
  authenticated_smoke: status
10760
- }, closed4),
10792
+ }, closed5),
10761
10793
  rollback: _Object_({
10762
10794
  release_id: Union([ApplicationReleaseIdSchema, Null()]),
10763
10795
  configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
10764
10796
  status: Union([Literal("ready"), Literal("not-ready"), Literal("unknown")]),
10765
10797
  result: Union([status, Null()])
10766
- }, closed4),
10798
+ }, closed5),
10767
10799
  notes: _Array_(String2({ minLength: 1, maxLength: 512 }), { maxItems: 32 })
10768
- }, closed4);
10800
+ }, closed5);
10769
10801
  function isIsoDate(value) {
10770
10802
  return Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
10771
10803
  }
@@ -10798,13 +10830,13 @@ function parseDeploymentEvidence(value) {
10798
10830
  return structuredClone(value);
10799
10831
  }
10800
10832
  // node_modules/@supacloud/delivery/src/application-promotion.ts
10801
- var closed5 = { additionalProperties: false };
10833
+ var closed6 = { additionalProperties: false };
10802
10834
  var projectRef2 = String2({ pattern: "^[a-z0-9-]{1,20}$" });
10803
10835
  var sha2562 = ApplicationReleaseIdSchema;
10804
- var nullableActivation = Union([ApplicationActivationIdSchema, Null()]);
10836
+ var nullableActivation2 = Union([ApplicationActivationIdSchema, Null()]);
10805
10837
  var nullableDigest = Union([sha2562, Null()]);
10806
10838
  var observation = {
10807
- activation_id: nullableActivation,
10839
+ activation_id: nullableActivation2,
10808
10840
  receipt_confirmed: Boolean2(),
10809
10841
  ready: Boolean2(),
10810
10842
  smoke_verified: Boolean2(),
@@ -10835,7 +10867,7 @@ var ApplicationPromotionPlanSchema = _Object_({
10835
10867
  environment_id: ApplicationIdSchema,
10836
10868
  release_id: sha2562,
10837
10869
  ...observation
10838
- }, closed5),
10870
+ }, closed6),
10839
10871
  target: _Object_({
10840
10872
  candidate_release_id: sha2562,
10841
10873
  current_release_id: Union([sha2562, Null()]),
@@ -10843,18 +10875,18 @@ var ApplicationPromotionPlanSchema = _Object_({
10843
10875
  configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
10844
10876
  configuration: Union([ApplicationConfigurationViewSchema, Null()]),
10845
10877
  ...observation
10846
- }, closed5),
10878
+ }, closed6),
10847
10879
  migrations: _Object_({
10848
10880
  ledger_digest: sha2562,
10849
10881
  ledger_compatible: Boolean2(),
10850
10882
  project_migrations_applied: Boolean2(),
10851
10883
  pending_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { maxItems: 4096, uniqueItems: true }),
10852
10884
  operator_provisioning_required: Boolean2()
10853
- }, closed5),
10885
+ }, closed6),
10854
10886
  backup: _Object_({
10855
10887
  required: Boolean2(),
10856
10888
  confirmed: Literal(false)
10857
- }, closed5),
10889
+ }, closed6),
10858
10890
  action: Union([Literal("promote"), Literal("no-op"), Literal("blocked")]),
10859
10891
  blockers: _Array_(Enum([...blocker]), {
10860
10892
  maxItems: blocker.length,
@@ -10863,7 +10895,7 @@ var ApplicationPromotionPlanSchema = _Object_({
10863
10895
  steps: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 8, uniqueItems: true }),
10864
10896
  execution_performed: Literal(false),
10865
10897
  data_recovery: Literal("separate-required")
10866
- }, closed5);
10898
+ }, closed6);
10867
10899
  function applicationPromotionPlanDigest(value) {
10868
10900
  return digest(canonical(value));
10869
10901
  }
@@ -15832,7 +15864,7 @@ Actions: list, upsert, delete`, {
15832
15864
  action: withDescription(stringEnum(["list", "upsert", "delete"]), "Action"),
15833
15865
  ref: withDescription(String2(), "Project ref"),
15834
15866
  secrets: withDescription(secretsSchema, "[upsert] Secret list as JSON array or KEY=VALUE,KEY2=VALUE2"),
15835
- "from-env": withDescription(environmentSecretNamesSchema, "[upsert] Comma-separated environment variable names; values are read from this CLI process"),
15867
+ "from-env": withDescription(environmentSecretNamesSchema, "[upsert] Comma-separated environment variable names; values are read from the selected CLI environment"),
15836
15868
  name: optional(String2(), "[delete] Secret name to delete")
15837
15869
  }, async (args) => {
15838
15870
  const { action, ref, secrets, name } = args;
@@ -16810,6 +16842,7 @@ var ApplicationActivationRetirementResultSchema2 = ApplicationActivationRetireme
16810
16842
  var ApplicationRollbackSnapshotSchema2 = ApplicationRollbackSnapshotSchema;
16811
16843
  var ApplicationActivationHistoryCursorSchema2 = ApplicationActivationHistoryCursorSchema;
16812
16844
  var ApplicationPromotionPlanSchema2 = ApplicationPromotionPlanSchema;
16845
+ var ApplicationReleaseRequestSchema2 = ApplicationReleaseRequestSchema;
16813
16846
 
16814
16847
  // src/shared/mutation-protocol.ts
16815
16848
  import { createHash as createHash6 } from "node:crypto";
@@ -17049,7 +17082,7 @@ async function fetchMutationStatus(http, ref, mutationId) {
17049
17082
  }
17050
17083
 
17051
17084
  // src/shared/tools/application-workflow-schemas.ts
17052
- var closed6 = { additionalProperties: false };
17085
+ var closed7 = { additionalProperties: false };
17053
17086
  var ref5 = String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" });
17054
17087
  var uuid = ApplicationActivationIdSchema2;
17055
17088
  var nullableUuid = Union([uuid, Null()]);
@@ -17063,7 +17096,7 @@ var ApplicationPromotionResultSchema = _Object_({
17063
17096
  plan_sha256: ApplicationReleaseIdSchema2,
17064
17097
  action: Literal("promote"),
17065
17098
  replayed: Boolean2()
17066
- }, closed6);
17099
+ }, closed7);
17067
17100
  var ApplicationPromotionStatusSchema = _Object_({
17068
17101
  ...scope2,
17069
17102
  mutation: Unknown(),
@@ -17082,8 +17115,8 @@ var ApplicationPromotionStatusSchema = _Object_({
17082
17115
  configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]),
17083
17116
  backup_id: Union([String2({ pattern: "^logical-full_[a-z0-9-]{1,20}_[a-f0-9]{32}$" }), Null()]),
17084
17117
  data_recovery: Literal("separate-required")
17085
- }, closed6)
17086
- }, closed6);
17118
+ }, closed7)
17119
+ }, closed7);
17087
17120
  var phase = Union([Literal("pending"), Literal("ready"), Literal("failed"), Literal("cleaned")]);
17088
17121
  var previewId = String2({ pattern: "^[a-f0-9-]{8,64}$" });
17089
17122
  var name = String2({ minLength: 1, maxLength: 256 });
@@ -17102,35 +17135,35 @@ var ApplicationPreviewReceiptSchema2 = _Object_({
17102
17135
  Literal("cleaned")
17103
17136
  ]),
17104
17137
  resources: _Object_({
17105
- build_artifact: _Object_({ status: phase, release_id: ApplicationReleaseIdSchema2 }, closed6),
17138
+ build_artifact: _Object_({ status: phase, release_id: ApplicationReleaseIdSchema2 }, closed7),
17106
17139
  database_branch: _Object_({
17107
17140
  status: phase,
17108
17141
  branch_ref: ref5,
17109
17142
  data_mode: Union([Literal("schema_only"), Literal("full_clone")])
17110
- }, closed6),
17111
- queue_namespace: _Object_({ status: phase, namespace: name }, closed6),
17112
- storage_namespace: _Object_({ status: phase, namespace: name }, closed6),
17113
- test_secret: _Object_({ status: phase, name, value_issued: Literal(false) }, closed6),
17114
- configuration_revision: _Object_({ status: phase, configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]) }, closed6),
17115
- application_activation: _Object_({ status: phase, activation_id: nullableUuid }, closed6),
17116
- smoke_test: _Object_({ status: phase, checks, passed: checks, failed: checks }, closed6)
17117
- }, closed6),
17143
+ }, closed7),
17144
+ queue_namespace: _Object_({ status: phase, namespace: name }, closed7),
17145
+ storage_namespace: _Object_({ status: phase, namespace: name }, closed7),
17146
+ test_secret: _Object_({ status: phase, name, value_issued: Literal(false) }, closed7),
17147
+ configuration_revision: _Object_({ status: phase, configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]) }, closed7),
17148
+ application_activation: _Object_({ status: phase, activation_id: nullableUuid }, closed7),
17149
+ smoke_test: _Object_({ status: phase, checks, passed: checks, failed: checks }, closed7)
17150
+ }, closed7),
17118
17151
  cleanup: _Object_({
17119
17152
  required: Boolean2(),
17120
17153
  completed: Boolean2(),
17121
17154
  error: Union([String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }), Null()])
17122
- }, closed6),
17155
+ }, closed7),
17123
17156
  branch_name: Optional(String2({ minLength: 1, maxLength: 80 })),
17124
17157
  queue_name: Optional(name),
17125
17158
  test_secret_name: Optional(name),
17126
17159
  source_configuration_id: Optional(Union([ApplicationConfigurationIdSchema2, Null()])),
17127
17160
  created_at: Optional(timestamp2),
17128
17161
  updated_at: Optional(timestamp2)
17129
- }, closed6);
17162
+ }, closed7);
17130
17163
  var previewListSchema = _Object_({
17131
17164
  ...scope2,
17132
17165
  previews: _Array_(ApplicationPreviewReceiptSchema2, { maxItems: 1000 })
17133
- }, closed6);
17166
+ }, closed7);
17134
17167
  function assertScope(value, identity) {
17135
17168
  if (value.project_ref !== identity.project_ref || value.application_id !== identity.application_id || value.environment_id !== identity.environment_id)
17136
17169
  throw new Error("Application workflow scope mismatch");
@@ -17597,6 +17630,7 @@ var APPLICATION_TOOL_SCHEMA = {
17597
17630
  "put_configuration",
17598
17631
  "get_deploy_plan",
17599
17632
  "deploy_release",
17633
+ "release_application",
17600
17634
  "get_release_transfer_plan",
17601
17635
  "transfer_release",
17602
17636
  "get_promotion_plan",
@@ -17624,6 +17658,7 @@ var APPLICATION_TOOL_SCHEMA = {
17624
17658
  activation_id: optional(ApplicationActivationIdSchema2, "[deploy_release/activate_release/reconcile_activation/retire_activation/rollback_release/get_history] Stable activation ID; generated for automatic deployment/rollback if omitted"),
17625
17659
  expected_activation_id: optional(Union([ApplicationActivationIdSchema2, Null(), Literal("absent")]), "[deploy_release/activate_release/rollback_release] Current activation ID, or absent for first activation; selected from verified plan for automatic deployment"),
17626
17660
  configuration_path: optional(String2(), "[put_configuration] Local configuration write JSON including revision and expected revision"),
17661
+ configuration_write: optional(Unknown(), "[release_application] Parsed immutable configuration write"),
17627
17662
  manifest_path: optional(String2(), "[upload_release] Local delivery.manifest.json"),
17628
17663
  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"),
17629
17664
  source_ref: optional(String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" }), "[get_release_transfer_plan/transfer_release] Source project ref"),
@@ -17983,6 +18018,61 @@ function registerApplicationTools(server, http) {
17983
18018
  const observed = await readDeployPlan(http, args, project);
17984
18019
  return observed.failure ?? releaseControlSuccess(operation, { ...observed.identity, plan: observed.plan });
17985
18020
  }
18021
+ if (action === "release_application") {
18022
+ const environmentId = text(args, "environment_id");
18023
+ const releaseId = text(args, "release_id");
18024
+ if (!Check2(ApplicationIdSchema2, environmentId) || !Check2(ApplicationReleaseIdSchema2, releaseId)) {
18025
+ throw new Error("Invalid application release identity");
18026
+ }
18027
+ const configurationId = args["configuration_id"];
18028
+ const activationId = args["activation_id"];
18029
+ const expectedActivationId = args["expected_activation_id"];
18030
+ if (configurationId !== undefined && !Check2(ApplicationConfigurationIdSchema2, configurationId)) {
18031
+ throw new Error("Invalid application configuration ID");
18032
+ }
18033
+ if (activationId !== undefined && !Check2(ApplicationActivationIdSchema2, activationId)) {
18034
+ throw new Error("Invalid application activation ID");
18035
+ }
18036
+ if (expectedActivationId !== undefined && expectedActivationId !== null && expectedActivationId !== "absent" && !Check2(ApplicationActivationIdSchema2, expectedActivationId)) {
18037
+ throw new Error("Invalid expected activation ID");
18038
+ }
18039
+ const configurationWrite = args["configuration_write"];
18040
+ const parsedConfigurationWrite = configurationWrite === undefined ? undefined : parseApplicationConfigurationWrite(configurationWrite);
18041
+ const requestedConfigurationId = configurationId ?? parsedConfigurationWrite?.configuration_id;
18042
+ const body = {
18043
+ release_id: releaseId,
18044
+ ...configurationId === undefined ? {} : { configuration_id: configurationId },
18045
+ ...configurationWrite === undefined ? {} : { configuration_write: configurationWrite },
18046
+ ...activationId === undefined ? {} : { activation_id: activationId },
18047
+ ...expectedActivationId === undefined ? {} : {
18048
+ expected_activation_id: expectedActivationId === "absent" ? null : expectedActivationId
18049
+ }
18050
+ };
18051
+ if (!Check2(ApplicationReleaseRequestSchema2, body)) {
18052
+ throw new Error("Invalid application release request");
18053
+ }
18054
+ const result = await http.post(`/v1/projects/${project}/applications/${encodeURIComponent(id)}/environments/${encodeURIComponent(environmentId)}/release`, body, { timeoutMs: 120000, maxJsonBytes: 65536, responseTimeoutMs: 30000 });
18055
+ const identity = {
18056
+ project_ref: ref,
18057
+ application_id: id,
18058
+ environment_id: environmentId,
18059
+ release_id: releaseId,
18060
+ ...configurationId === undefined ? {} : { configuration_id: configurationId },
18061
+ ...activationId === undefined ? {} : { activation_id: activationId }
18062
+ };
18063
+ if (!result.ok)
18064
+ return releaseControlMutationFailure(operation, result, identity);
18065
+ try {
18066
+ if (result.status !== 200)
18067
+ throw new Error;
18068
+ const release = parseApplicationReleaseResult(result.data);
18069
+ if (release.project_ref !== ref || release.application_id !== id || release.environment_id !== environmentId || release.release_id !== releaseId || requestedConfigurationId !== undefined && release.configuration_id !== requestedConfigurationId || activationId !== undefined && release.activation_id !== activationId)
18070
+ throw new Error;
18071
+ return releaseControlSuccess(operation, release);
18072
+ } catch {
18073
+ return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.status, identity);
18074
+ }
18075
+ }
17986
18076
  if (action === "deploy_release")
17987
18077
  return deployAction(http, args, project);
17988
18078
  if (action === "rollback_release" || action === "get_rollback_snapshot") {
@@ -21016,7 +21106,7 @@ var starter_metadata_default = {
21016
21106
  }
21017
21107
  },
21018
21108
  elysia: {
21019
- version: "0.29.0"
21109
+ version: "0.29.1"
21020
21110
  },
21021
21111
  commands: {
21022
21112
  version: "0.9.1"
@@ -24419,14 +24509,14 @@ var REMOTE_APP_ACTIONS = {
24419
24509
  "preview-reconcile": "reconcile_preview"
24420
24510
  };
24421
24511
  var REMOTE_APP_DESCRIPTIONS = {
24422
- ref: "[upload/configure/transfer-plan/transfer/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Project ref (defaults to context)",
24423
- id: "[upload/configure/transfer-plan/transfer/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Application ID",
24424
- environment_id: "[configure/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Target environment ID",
24425
- configuration_id: "[promote-plan/diff/promote/preview-plan/preview/preview-create/deploy/deploy-plan/rollback] Immutable target configuration revision",
24512
+ ref: "[release/upload/configure/transfer-plan/transfer/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Project ref (defaults to context)",
24513
+ id: "[release/upload/configure/transfer-plan/transfer/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Application ID",
24514
+ environment_id: "[release/configure/promote-plan/diff/promote/promote-status/promote-reconcile/preview-plan/preview/previews/preview-list/preview-create/preview-status/preview-reconcile/preview-cleanup/deploy/deploy-plan/status/rollback/rollback-plan/history/reconcile/retire] Target environment ID",
24515
+ configuration_id: "[release/promote-plan/diff/promote/preview-plan/preview/preview-create/deploy/deploy-plan/rollback] Immutable target configuration revision",
24426
24516
  activation_id: "[deploy/rollback/reconcile/retire] Required explicit activation ID",
24427
24517
  expected_activation_id: "[deploy/rollback] Required current activation ID, or absent for first activation",
24428
- configuration_path: "[configure] Configuration write JSON including revision and expected revision",
24429
- manifest_path: "[upload] Local delivery.manifest.json",
24518
+ configuration_path: "[release/configure] Configuration write JSON including revision and expected revision",
24519
+ manifest_path: "[release/upload] Local delivery.manifest.json",
24430
24520
  release_id: "[preview-plan/preview/preview-create/deploy/deploy-plan/diff/rollback/reconcile] Required immutable application release ID",
24431
24521
  source_ref: "[transfer-plan/transfer/promote-plan/diff/promote] Source project ref",
24432
24522
  source_release_id: "[transfer-plan/transfer/promote-plan/diff/promote] Source immutable release ID",
@@ -25340,6 +25430,171 @@ async function runDelivery(args) {
25340
25430
  const result = await buildDeliveryProject(options, loaded.delivery);
25341
25431
  return textResult(JSON.stringify(result, null, 2), !result.ok);
25342
25432
  }
25433
+ function resultObject(result) {
25434
+ try {
25435
+ const value = JSON.parse(result.content[0]?.text ?? "");
25436
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
25437
+ } catch {
25438
+ return;
25439
+ }
25440
+ }
25441
+ function resultErrorCode(result, fallback) {
25442
+ const payload = resultObject(result);
25443
+ const error = payload?.error;
25444
+ const errorRecord = error !== null && typeof error === "object" && !Array.isArray(error) ? error : undefined;
25445
+ return typeof errorRecord?.code === "string" ? errorRecord.code : fallback;
25446
+ }
25447
+ function releasePhaseFailure(phase, result, completed) {
25448
+ const phaseResult = resultObject(result);
25449
+ const upload = completed.upload !== null && typeof completed.upload === "object" && !Array.isArray(completed.upload) ? completed.upload : undefined;
25450
+ const configure = completed.configure !== null && typeof completed.configure === "object" && !Array.isArray(completed.configure) ? completed.configure : undefined;
25451
+ const releaseId = typeof upload?.release_id === "string" ? upload.release_id : undefined;
25452
+ const configurationId = typeof configure?.configuration_id === "string" ? configure.configuration_id : undefined;
25453
+ const payload = {
25454
+ schema: RELEASE_CONTROL_RESPONSE_SCHEMA,
25455
+ ok: false,
25456
+ operation: "applications.release",
25457
+ phase,
25458
+ phases: completed,
25459
+ error: { code: resultErrorCode(result, phase === "build" ? "BUILD_FAILED" : "PHASE_FAILED") },
25460
+ ...releaseId === undefined ? {} : { release_id: releaseId },
25461
+ ...configurationId === undefined ? {} : { configuration_id: configurationId },
25462
+ ...phaseResult === undefined ? {} : { phase_result: phaseResult }
25463
+ };
25464
+ if (phaseResult?.activation_id !== undefined)
25465
+ payload.activation_id = phaseResult.activation_id;
25466
+ if (phaseResult?.expected_activation_id !== undefined) {
25467
+ payload.expected_activation_id = phaseResult.expected_activation_id;
25468
+ }
25469
+ return textResult(JSON.stringify(payload, null, 2), true);
25470
+ }
25471
+ function releaseField(payload, container, field) {
25472
+ const value = payload?.[container];
25473
+ if (value === null || typeof value !== "object" || Array.isArray(value))
25474
+ return;
25475
+ const record = value;
25476
+ return typeof record[field] === "string" ? record[field] : undefined;
25477
+ }
25478
+ async function runAppRelease(request, options, delegate) {
25479
+ const ref = request.ref ?? options.projectRef;
25480
+ const id = request.id?.trim();
25481
+ const environmentId = request.environment_id?.trim();
25482
+ if (!ref || !id || !environmentId) {
25483
+ throw new Error("app release requires --ref, --id and --environment_id (ref may come from context)");
25484
+ }
25485
+ if (!Check2(ApplicationIdSchema2, id) || !Check2(ApplicationIdSchema2, environmentId)) {
25486
+ throw new Error("app release requires valid --id and --environment_id");
25487
+ }
25488
+ if (request.configuration_id !== undefined && !Check2(ApplicationConfigurationIdSchema2, request.configuration_id)) {
25489
+ throw new Error("app release requires a valid --configuration_id");
25490
+ }
25491
+ if (request.configuration_path !== undefined && request.configuration_id !== undefined) {
25492
+ throw new Error("app release accepts either --configuration_path or --configuration_id, not both");
25493
+ }
25494
+ if (request.configuration_path === undefined && request.configuration_id === undefined) {
25495
+ throw new Error("app release requires --configuration_path or --configuration_id");
25496
+ }
25497
+ if (request.activation_id !== undefined || request.expected_activation_id !== undefined) {
25498
+ throw new Error("app release generates one activation identity; use app deploy for an exact retry");
25499
+ }
25500
+ const root = resolve17(request.root || process.cwd());
25501
+ const completed = {};
25502
+ let manifestPath;
25503
+ let buildReceipt;
25504
+ if (request.skip_build === true) {
25505
+ if (request.manifest_path === undefined) {
25506
+ throw new Error("app release --skip_build requires --manifest_path");
25507
+ }
25508
+ manifestPath = resolve17(root, request.manifest_path);
25509
+ completed.build = { skipped: true, manifest_path: manifestPath };
25510
+ } else {
25511
+ const built = await runDelivery({ ...request, action: "build", root, format: "json" });
25512
+ buildReceipt = resultObject(built);
25513
+ if (built.isError || !buildReceipt?.ok || buildReceipt.manifest === null || buildReceipt.manifest === undefined) {
25514
+ return releasePhaseFailure("build", built, completed);
25515
+ }
25516
+ const loaded = await loadSupacloudConfig(root);
25517
+ const resolved = resolveSupacloudConfig(loaded, root);
25518
+ manifestPath = join13(resolved.outDir, "delivery", "delivery.manifest.json");
25519
+ completed.build = {
25520
+ ok: true,
25521
+ manifest_path: manifestPath,
25522
+ written: Array.isArray(buildReceipt.written) ? buildReceipt.written.length : 0
25523
+ };
25524
+ }
25525
+ const uploadArgs = {
25526
+ action: "upload_release",
25527
+ ref,
25528
+ id,
25529
+ manifest_path: manifestPath
25530
+ };
25531
+ validateToolArguments(APPLICATION_TOOL_SCHEMA, uploadArgs);
25532
+ const uploaded = await delegate(uploadArgs);
25533
+ const uploadReceipt = resultObject(uploaded);
25534
+ if (uploaded.isError || !uploadReceipt?.ok) {
25535
+ return releasePhaseFailure("upload", uploaded, completed);
25536
+ }
25537
+ const releaseId = releaseField(uploadReceipt, "release", "release_id");
25538
+ if (!releaseId)
25539
+ return releasePhaseFailure("upload", releaseControlFailure("applications.upload_release", "INVALID_RESPONSE", null, { project_ref: ref, application_id: id }), completed);
25540
+ completed.upload = { ok: true, release_id: releaseId };
25541
+ let configurationId = request.configuration_id;
25542
+ let configurationWrite;
25543
+ const activationId = crypto.randomUUID();
25544
+ if (request.configuration_path !== undefined) {
25545
+ const configurationPath = resolve17(root, request.configuration_path);
25546
+ try {
25547
+ configurationWrite = parseApplicationConfigurationWrite(await Bun.file(configurationPath).json());
25548
+ configurationId = configurationWrite.configuration_id;
25549
+ } catch {
25550
+ return releasePhaseFailure("configure", releaseControlFailure("applications.release_application", "INVALID_RESPONSE", null, { project_ref: ref, application_id: id, environment_id: environmentId }), completed);
25551
+ }
25552
+ completed.configure = { delegated: true, configuration_id: configurationId };
25553
+ } else {
25554
+ completed.configure = { delegated: true, configuration_id: configurationId };
25555
+ }
25556
+ const deployArgs = {
25557
+ action: "release_application",
25558
+ ref,
25559
+ id,
25560
+ environment_id: environmentId,
25561
+ release_id: releaseId,
25562
+ configuration_id: configurationId,
25563
+ activation_id: activationId,
25564
+ ...configurationWrite === undefined ? {} : { configuration_write: configurationWrite }
25565
+ };
25566
+ validateToolArguments(APPLICATION_TOOL_SCHEMA, deployArgs);
25567
+ const deployed = await delegate(deployArgs);
25568
+ const deployReceipt = resultObject(deployed);
25569
+ if (deployed.isError || !deployReceipt?.ok) {
25570
+ return releasePhaseFailure("deploy", deployed, completed);
25571
+ }
25572
+ completed.deploy = deployReceipt;
25573
+ const result = {
25574
+ schema: RELEASE_CONTROL_RESPONSE_SCHEMA,
25575
+ ok: true,
25576
+ operation: "applications.release",
25577
+ project_ref: ref,
25578
+ application_id: id,
25579
+ environment_id: environmentId,
25580
+ release_id: releaseId,
25581
+ configuration_id: configurationId,
25582
+ manifest_path: manifestPath,
25583
+ build: buildReceipt ? completed.build : { skipped: true, manifest_path: manifestPath },
25584
+ phases: completed,
25585
+ no_op: deployReceipt.action === "no-op" || deployReceipt.no_op === true,
25586
+ execution_performed: deployReceipt.execution_performed === true,
25587
+ ...typeof deployReceipt.activation_id === "string" ? { activation_id: deployReceipt.activation_id } : {}
25588
+ };
25589
+ return request.format === "json" || request.json === true ? textResult(JSON.stringify(result, null, 2)) : textResult([
25590
+ `${ref}/${id}/${environmentId}: ${result.no_op ? "no-op" : "released"}`,
25591
+ `Release: ${releaseId}`,
25592
+ `Configuration: ${configurationId}`,
25593
+ `Activation: ${result.activation_id ?? "not performed"}`,
25594
+ `Build: ${request.skip_build ? "skipped" : "completed"}`
25595
+ ].join(`
25596
+ `));
25597
+ }
25343
25598
  function formatReleaseTransfer(result) {
25344
25599
  if (result.isError)
25345
25600
  return result;
@@ -25610,7 +25865,7 @@ async function runAppTool(request, options = {}) {
25610
25865
  if (request.database_url !== undefined && request.action !== "dev" && request.action !== "watch") {
25611
25866
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--database-url applies only to app dev --profile integration");
25612
25867
  }
25613
- if (request.json !== undefined && !Object.hasOwn(REMOTE_APP_ACTIONS, request.action) && request.action !== "promote")
25868
+ if (request.json !== undefined && !Object.hasOwn(REMOTE_APP_ACTIONS, request.action) && request.action !== "promote" && request.action !== "release")
25614
25869
  throw new Error("--json applies only to remote app actions");
25615
25870
  if (request.json && request.format === "text")
25616
25871
  throw new Error("--json and --format text cannot be combined");
@@ -25620,6 +25875,12 @@ async function runAppTool(request, options = {}) {
25620
25875
  return textResult("App remote actions require a Management API context.", true);
25621
25876
  return runPromotion(request, options, delegate);
25622
25877
  }
25878
+ if (request.action === "release") {
25879
+ const delegate = options.getApplications?.();
25880
+ if (!delegate)
25881
+ return textResult("App remote actions require a Management API context.", true);
25882
+ return runAppRelease(request, options, delegate);
25883
+ }
25623
25884
  if (Object.hasOwn(REMOTE_APP_ACTIONS, request.action)) {
25624
25885
  const delegate = options.getApplications?.();
25625
25886
  if (!delegate)
@@ -25716,6 +25977,7 @@ function registerAppTools(server, options = {}) {
25716
25977
  "fix",
25717
25978
  "plan",
25718
25979
  "build",
25980
+ "release",
25719
25981
  "upload",
25720
25982
  "configure",
25721
25983
  "transfer-plan",
@@ -25753,11 +26015,11 @@ function registerAppTools(server, options = {}) {
25753
26015
  "dry-run": optional(Boolean2(), "[generate] CLI alias of dry_run"),
25754
26016
  register_in: optional(String2(), "[generate] Existing parent module file for module/resource; uses the compiler AST editor"),
25755
26017
  "register-in": optional(String2(), "[generate] CLI alias of register_in"),
25756
- root: optional(String2(), "[dev/plan/build/compile/check] Project directory containing supacloud.config.ts (default: current directory)"),
26018
+ root: optional(String2(), "[dev/plan/build/release/compile/check] Project directory containing supacloud.config.ts (default: current directory)"),
25757
26019
  include: optional(String2(), "[dev/compile/check] Comma-separated glob patterns for source files"),
25758
26020
  out_dir: optional(String2(), "[dev/compile/plan/build/export-tools] Output directory (default: configured outDir)"),
25759
26021
  strict: optional(Boolean2(), "[dev/compile/check] Promote warnings to errors"),
25760
- format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/deploy-plan/diff/history/promote-plan/graph/export-tools] Output format (default: text)"),
26022
+ format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/release/deploy-plan/diff/history/promote-plan/graph/export-tools] Output format (default: text)"),
25761
26023
  json: optional(Boolean2(), "[history/transfer-plan/transfer/promote-plan] Preserve or return the full machine-readable receipt"),
25762
26024
  profile: optional(stringEnum(["fast", "integration"]), "[dev] Run dev or dev:integration; integration verifies an explicit loopback database"),
25763
26025
  once: optional(Boolean2(), "[dev] Validate and report once without watching"),
@@ -25766,7 +26028,8 @@ function registerAppTools(server, options = {}) {
25766
26028
  "database-url": optional(String2(), "[dev] CLI alias of database_url"),
25767
26029
  target: optional(String2(), "[explain/context/verify-plan] Provider class name / token name / command name / job name / module name"),
25768
26030
  fix: optional(String2(), "[fix] Path to a DiagnosticFix JSON file produced by `doctor --format json`"),
25769
- write: optional(Boolean2(), "[fix] Write the fix to disk (default: preview only)")
26031
+ write: optional(Boolean2(), "[fix] Write the fix to disk (default: preview only)"),
26032
+ skip_build: optional(Boolean2(), "[release] Reuse --manifest_path instead of running the local delivery build")
25770
26033
  }, (request) => runAppTool(request, options));
25771
26034
  }
25772
26035
  var APP_ALIAS_ACTIONS = ["generate", "compile", "check", "graph", "explain", "context", "doctor", "fix"];
@@ -27675,6 +27938,14 @@ import { createHash as createHash9 } from "node:crypto";
27675
27938
  import { tmpdir as tmpdir3 } from "node:os";
27676
27939
  import { basename as basename8, dirname as dirname11, join as join17, relative as relative10, resolve as resolve22, sep as sep5 } from "node:path";
27677
27940
  var MAX_SOURCE_BYTES = 256 * 1024 * 1024;
27941
+ var PUBLIC_BUILD_ENV_PREFIXES = ["PUBLIC_", "VITE_", "NEXT_PUBLIC_", "NUXT_PUBLIC_", "ASTRO_PUBLIC_"];
27942
+ var SENSITIVE_BUILD_ENV = /(?:^|_)(?:PASSWORD|PASS|SECRET|TOKEN|KEY|CREDENTIAL|AUTHORIZATION|COOKIE|SESSION)(?:_|$)|(?:DATABASE_URL|DATABASE_URI|CONNECTION_STRING|DSN|PRIVATE_KEY)/i;
27943
+ function isPublicBuildEnv(name) {
27944
+ return PUBLIC_BUILD_ENV_PREFIXES.some((prefix) => name.startsWith(prefix));
27945
+ }
27946
+ function isProtectedBuildEnv(name) {
27947
+ return name.startsWith("SUPACLOUD_") || name === "SUPABASE_SERVICE_ROLE_KEY" || name === "SUPABASE_ACCESS_TOKEN" || name === "MANAGEMENT_API_URL" || name === "MANAGEMENT_API_TOKEN";
27948
+ }
27678
27949
  var deployToolSchema = {
27679
27950
  ref: optional(String2(), "Project ref (defaults to the linked project)"),
27680
27951
  target: optional(String2(), "Named deploy target from supacloud.json"),
@@ -27745,6 +28016,26 @@ function optionalBoolean(value, field) {
27745
28016
  throw new Error(`supacloud.json ${field} must be a boolean`);
27746
28017
  return value;
27747
28018
  }
28019
+ function optionalStringArray(value, field) {
28020
+ if (value === undefined)
28021
+ return;
28022
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item.trim())) {
28023
+ throw new Error(`supacloud.json ${field} must be an array of non-empty strings`);
28024
+ }
28025
+ return value.map((item) => item.trim()).map((name) => {
28026
+ if (!/^[A-Z_][A-Z0-9_]*$/.test(name)) {
28027
+ throw new Error(`supacloud.json ${field} must contain uppercase environment variable names`);
28028
+ }
28029
+ const isPublic = isPublicBuildEnv(name);
28030
+ if (SENSITIVE_BUILD_ENV.test(name) && !isPublic) {
28031
+ throw new Error(`supacloud.json ${field} cannot include sensitive variable '${name}'; use runtime secrets instead`);
28032
+ }
28033
+ if (isProtectedBuildEnv(name)) {
28034
+ throw new Error(`supacloud.json ${field} cannot include platform credential '${name}'`);
28035
+ }
28036
+ return name;
28037
+ });
28038
+ }
27748
28039
  function deployTargetConfig(candidate, name) {
27749
28040
  const value = record4(candidate);
27750
28041
  if (!value || value.type !== "frontend" && value.type !== "edge_function") {
@@ -27761,6 +28052,7 @@ function deployTargetConfig(candidate, name) {
27761
28052
  slug: optionalText(value.slug, `targets.${name}.slug`),
27762
28053
  buildCommand: optionalText(value.buildCommand, `targets.${name}.buildCommand`),
27763
28054
  outputDirectory: optionalText(value.outputDirectory, `targets.${name}.outputDirectory`),
28055
+ buildEnv: optionalStringArray(value.buildEnv, `targets.${name}.buildEnv`),
27764
28056
  bundleDirectory: optionalText(value.bundleDirectory, `targets.${name}.bundleDirectory`),
27765
28057
  entrypoint: optionalText(value.entrypoint, `targets.${name}.entrypoint`),
27766
28058
  verifyJwt: optionalBoolean(value.verifyJwt, `targets.${name}.verifyJwt`),
@@ -27786,7 +28078,8 @@ async function readDeployConfig(configRoot) {
27786
28078
  id: optionalText(frontend.id, "frontend.id"),
27787
28079
  root: optionalText(frontend.root, "frontend.root"),
27788
28080
  buildCommand: optionalText(frontend.buildCommand, "frontend.buildCommand"),
27789
- outputDirectory: optionalText(frontend.outputDirectory, "frontend.outputDirectory")
28081
+ outputDirectory: optionalText(frontend.outputDirectory, "frontend.outputDirectory"),
28082
+ buildEnv: optionalStringArray(frontend.buildEnv, "frontend.buildEnv")
27790
28083
  } : undefined
27791
28084
  };
27792
28085
  }
@@ -27857,7 +28150,8 @@ function selectTarget(configRoot, invocationDirectory, config, requestedName) {
27857
28150
  root: config.frontend?.root,
27858
28151
  id: config.frontend?.id,
27859
28152
  buildCommand: config.frontend?.buildCommand,
27860
- outputDirectory: config.frontend?.outputDirectory
28153
+ outputDirectory: config.frontend?.outputDirectory,
28154
+ buildEnv: config.frontend?.buildEnv
27861
28155
  }]];
27862
28156
  if (targets.length === 0)
27863
28157
  throw new Error("supacloud.json defines no deploy targets");
@@ -27905,10 +28199,28 @@ function resolveInsideProject(projectDirectory, candidate, allowRoot = false) {
27905
28199
  }
27906
28200
  return resolved;
27907
28201
  }
27908
- async function runBuild(command, cwd, json) {
28202
+ function createBuildEnvironment(names, environmentVariables) {
28203
+ const selectedNames = [...new Set(names || [])].sort();
28204
+ const selectedNameSet = new Set(selectedNames);
28205
+ const values = environmentVariables ?? process.env;
28206
+ const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => !isProtectedBuildEnv(name) && (!isPublicBuildEnv(name) || selectedNameSet.has(name)) && (!SENSITIVE_BUILD_ENV.test(name) || isPublicBuildEnv(name))));
28207
+ const missing = selectedNames.filter((name) => !values[name]?.trim());
28208
+ for (const name of selectedNames) {
28209
+ const value = values[name];
28210
+ if (value !== undefined)
28211
+ env[name] = value;
28212
+ }
28213
+ return { env, names: selectedNames, missing };
28214
+ }
28215
+ function assertBuildEnvironment(build, skipBuild) {
28216
+ if (!skipBuild && build.missing.length > 0) {
28217
+ throw new Error(`Missing build environment variables: ${build.missing.join(", ")}`);
28218
+ }
28219
+ }
28220
+ async function runBuild(command, cwd, environment, json) {
27909
28221
  const child = Bun.spawn(["sh", "-c", command], {
27910
28222
  cwd,
27911
- env: process.env,
28223
+ env: environment,
27912
28224
  stdio: ["inherit", json ? 2 : "inherit", "inherit"]
27913
28225
  });
27914
28226
  const exitCode = await child.exited;
@@ -28036,6 +28348,7 @@ function registerDeployTools(server, http, options = {}) {
28036
28348
  throw new Error(`Deploy target '${target.name}' root is not a regular directory: ${projectDirectory}`);
28037
28349
  }
28038
28350
  const requestedId = String(args.id || target.config.id || "").trim() || undefined;
28351
+ const build = createBuildEnvironment(target.config.buildEnv, options.environmentVariables);
28039
28352
  const report = phaseReporter(args.json === true);
28040
28353
  report("inspect", `${target.name} (${projectRef})`);
28041
28354
  if (target.config.type === "edge_function") {
@@ -28073,14 +28386,17 @@ function registerDeployTools(server, http, options = {}) {
28073
28386
  project_ref: projectRef,
28074
28387
  slug,
28075
28388
  build_command: args.skip_build === true ? null : buildCommand,
28389
+ build_env: build.names,
28390
+ missing_build_env: build.missing,
28076
28391
  bundle_directory: bundleDirectory,
28077
28392
  expected_active_version: activeVersion,
28078
28393
  expected_activation_id: activationId
28079
28394
  }, null, 2) }] };
28080
28395
  }
28396
+ assertBuildEnvironment(build, args.skip_build === true);
28081
28397
  if (args.skip_build !== true) {
28082
28398
  report("build", buildCommand);
28083
- await runBuild(buildCommand, projectDirectory, args.json === true);
28399
+ await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28084
28400
  } else {
28085
28401
  report("build", "skipped");
28086
28402
  }
@@ -28130,12 +28446,15 @@ function registerDeployTools(server, http, options = {}) {
28130
28446
  project_ref: projectRef,
28131
28447
  deployment_id: selected.id,
28132
28448
  build_command: args.skip_build === true ? null : buildCommand,
28449
+ build_env: build.names,
28450
+ missing_build_env: build.missing,
28133
28451
  output_directory: outputDirectory
28134
28452
  }, null, 2) }] };
28135
28453
  }
28454
+ assertBuildEnvironment(build, args.skip_build === true);
28136
28455
  if (args.skip_build !== true) {
28137
28456
  report("build", buildCommand);
28138
- await runBuild(buildCommand, projectDirectory, args.json === true);
28457
+ await runBuild(buildCommand, projectDirectory, build.env, args.json === true);
28139
28458
  } else {
28140
28459
  report("build", "skipped");
28141
28460
  }
@@ -28523,7 +28842,7 @@ function registerRemoteDevTools(server, options = {}) {
28523
28842
  // package.json
28524
28843
  var package_default = {
28525
28844
  name: "@supacloud/cli",
28526
- version: "0.84.0",
28845
+ version: "0.86.0",
28527
28846
  description: "Project-scoped CLI for SupaCloud users",
28528
28847
  type: "module",
28529
28848
  main: "./dist/index.js",
@@ -28576,13 +28895,13 @@ var package_default = {
28576
28895
  },
28577
28896
  dependencies: {
28578
28897
  "@supacloud/compiler": "^0.43.0",
28579
- "@supacloud/delivery": "0.13.0",
28898
+ "@supacloud/delivery": "0.14.0",
28580
28899
  "@supacloud/db": "0.16.0",
28581
28900
  typebox: "1.3.34"
28582
28901
  },
28583
28902
  overrides: {
28584
28903
  "@supacloud/contracts": "0.8.0",
28585
- "@supacloud/delivery": "0.13.0",
28904
+ "@supacloud/delivery": "0.14.0",
28586
28905
  "@graphql-tools/utils": "^12.0.3"
28587
28906
  },
28588
28907
  devDependencies: {
@@ -28842,6 +29161,7 @@ EXAMPLES
28842
29161
  ${preferredCommand} app compile --root .
28843
29162
  ${preferredCommand} app plan --root . --format json
28844
29163
  ${preferredCommand} app build --root .
29164
+ ${preferredCommand} --env test app release --id orders --environment_id test --configuration_path configuration.json
28845
29165
  ${preferredCommand} app upload --ref abc123 --id orders --manifest_path generated/delivery/delivery.manifest.json
28846
29166
  ${preferredCommand} app configure --ref abc123 --id orders --environment_id test --configuration_path configuration.json
28847
29167
  ${preferredCommand} app deploy-plan --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid>
@@ -29110,7 +29430,7 @@ function createCliTools(context, confirmProduction) {
29110
29430
  assign(captureTools((server) => registerAuthTools(server, http)));
29111
29431
  assign(captureTools((server) => registerOAuthClientTools(server, http)));
29112
29432
  assign(captureTools((server) => registerStorageTools(server, http)));
29113
- const advancedTools = captureTools((server) => registerAdvancedTools(server, http, process.env, {
29433
+ const advancedTools = captureTools((server) => registerAdvancedTools(server, http, context.environmentVariables, {
29114
29434
  readOnly: context.readOnly
29115
29435
  }));
29116
29436
  assign(advancedTools);
@@ -29134,6 +29454,7 @@ function createCliTools(context, confirmProduction) {
29134
29454
  environment: context.environment,
29135
29455
  projectRef: context.projectRef || undefined,
29136
29456
  cwd: process.cwd(),
29457
+ environmentVariables: context.environmentVariables,
29137
29458
  edgeFunctionDeploy: advancedTools.edge_functions?.callback
29138
29459
  })));
29139
29460
  assign(captureTools((server) => registerGatewayTools(server, http, {
@@ -21,6 +21,7 @@ export interface ResolvedContext {
21
21
  credentialScope: ContextCredentialScope;
22
22
  source: ContextSourceKind;
23
23
  sourcePath: string | null;
24
+ environmentVariables: Readonly<Record<string, string>>;
24
25
  insecureTls: boolean;
25
26
  }
26
27
  export declare function resolveSupaCloudContext(env?: NodeJS.ProcessEnv, cwd?: string, selection?: ContextSelection): ResolvedContext;
@@ -36,7 +36,7 @@ export interface AppToolOptions {
36
36
  onDevProgress?: (result: ToolResult) => void;
37
37
  }
38
38
  export interface AppToolArguments {
39
- action: "init" | "generate" | "dev" | "watch" | "verify-plan" | "compile" | "check" | "graph" | "explain" | "export-tools" | "context" | "doctor" | "fix" | "plan" | "build" | "promote" | keyof typeof REMOTE_APP_ACTIONS;
39
+ action: "init" | "generate" | "dev" | "watch" | "verify-plan" | "compile" | "check" | "graph" | "explain" | "export-tools" | "context" | "doctor" | "fix" | "plan" | "build" | "release" | "promote" | keyof typeof REMOTE_APP_ACTIONS;
40
40
  ref?: string;
41
41
  id?: string;
42
42
  environment_id?: string;
@@ -45,6 +45,8 @@ export interface AppToolArguments {
45
45
  expected_activation_id?: string | null;
46
46
  configuration_path?: string;
47
47
  manifest_path?: string;
48
+ /** `app release`: reuse an existing configuration revision instead of writing configuration_path. */
49
+ skip_build?: boolean;
48
50
  release_id?: string;
49
51
  source_ref?: string;
50
52
  source_release_id?: string;
@@ -152,3 +152,37 @@ export declare const ApplicationPromotionPlanSchema: import("typebox").TObject<{
152
152
  execution_performed: import("typebox").TLiteral<false>;
153
153
  data_recovery: import("typebox").TLiteral<"separate-required">;
154
154
  }>;
155
+ export declare const ApplicationReleaseRequestSchema: import("typebox").TObject<{
156
+ release_id: import("typebox").TString;
157
+ configuration_id: import("typebox").TOptional<import("typebox").TString>;
158
+ configuration_write: import("typebox").TOptional<import("typebox").TObject<{
159
+ configuration_id: import("typebox").TString;
160
+ expected_configuration_id: import("typebox").TUnion<[import("typebox").TString, import("typebox").TNull]>;
161
+ configuration: import("typebox").TObject<{
162
+ bun_version: import("typebox").TString;
163
+ targets: import("typebox").TArray<import("typebox").TObject<{
164
+ name: import("typebox").TString;
165
+ kind: import("typebox").TUnion<[import("typebox").TLiteral<"http">, import("typebox").TLiteral<"worker">]>;
166
+ hosts: import("typebox").TArray<import("typebox").TString>;
167
+ environment: import("typebox").TRecord<"^.*$", import("typebox").TString>;
168
+ }>>;
169
+ }>;
170
+ }>>;
171
+ activation_id: import("typebox").TOptional<import("typebox").TString>;
172
+ expected_activation_id: import("typebox").TOptional<import("typebox").TUnion<[import("typebox").TString, import("typebox").TNull]>>;
173
+ expected_plan_sha256: import("typebox").TOptional<import("typebox").TString>;
174
+ }>;
175
+ export declare const ApplicationReleaseResultSchema: import("typebox").TObject<{
176
+ schema: import("typebox").TLiteral<"supacloud.application-release.v1">;
177
+ project_ref: import("typebox").TString;
178
+ application_id: import("typebox").TString;
179
+ environment_id: import("typebox").TString;
180
+ release_id: import("typebox").TString;
181
+ configuration_id: import("typebox").TString;
182
+ activation_id: import("typebox").TString;
183
+ expected_activation_id: import("typebox").TUnion<[import("typebox").TString, import("typebox").TNull]>;
184
+ plan_sha256: import("typebox").TString;
185
+ action: import("typebox").TUnion<[import("typebox").TLiteral<"activate">, import("typebox").TLiteral<"no-op">]>;
186
+ replayed: import("typebox").TBoolean;
187
+ execution_performed: import("typebox").TBoolean;
188
+ }>;
@@ -9,7 +9,7 @@ export declare const APPLICATION_TOOL_SCHEMA: {
9
9
  ttl_seconds: Type.TOptional<Type.TInteger>;
10
10
  wait: Type.TOptional<Type.TBoolean>;
11
11
  timeout_seconds: Type.TOptional<Type.TInteger>;
12
- action: Type.TEnum<("list_releases" | "get_release" | "upload_release" | "activate_release" | "logs" | "get_runtime" | "get_deployment_evidence" | "get_configuration" | "get_release_transfer_plan" | "get_promotion_plan" | "get_promotion_status" | "get_rollback_snapshot" | "get_history" | "get_deploy_plan" | "get_preview_plan" | "list_previews" | "get_preview" | "put_configuration" | "transfer_release" | "promote_application" | "reconcile_promotion" | "create_preview" | "reconcile_preview" | "cleanup_preview" | "deploy_release" | "rollback_release" | "reconcile_activation" | "retire_activation")[]>;
12
+ action: Type.TEnum<("list_releases" | "get_release" | "upload_release" | "activate_release" | "logs" | "get_runtime" | "get_deployment_evidence" | "get_configuration" | "get_release_transfer_plan" | "get_promotion_plan" | "get_promotion_status" | "get_rollback_snapshot" | "get_history" | "get_deploy_plan" | "get_preview_plan" | "list_previews" | "get_preview" | "put_configuration" | "release_application" | "transfer_release" | "promote_application" | "reconcile_promotion" | "create_preview" | "reconcile_preview" | "cleanup_preview" | "deploy_release" | "rollback_release" | "reconcile_activation" | "retire_activation")[]>;
13
13
  ref: Type.TString;
14
14
  id: Type.TString;
15
15
  environment_id: Type.TOptional<Type.TString>;
@@ -17,6 +17,7 @@ export declare const APPLICATION_TOOL_SCHEMA: {
17
17
  activation_id: Type.TOptional<Type.TString>;
18
18
  expected_activation_id: Type.TOptional<Type.TUnion<[Type.TString, Type.TNull, Type.TLiteral<"absent">]>>;
19
19
  configuration_path: Type.TOptional<Type.TString>;
20
+ configuration_write: Type.TOptional<Type.TUnknown>;
20
21
  manifest_path: Type.TOptional<Type.TString>;
21
22
  release_id: Type.TOptional<Type.TString>;
22
23
  source_ref: Type.TOptional<Type.TString>;
@@ -5,6 +5,7 @@ interface DeployToolOptions {
5
5
  projectRef?: string;
6
6
  environment?: string | null;
7
7
  cwd?: string;
8
+ environmentVariables?: Readonly<Record<string, string>>;
8
9
  edgeFunctionDeploy?: (args: Record<string, unknown>) => Promise<ToolResponse>;
9
10
  }
10
11
  interface ToolResponse {
@@ -28,6 +29,11 @@ export declare const deployToolSchema: {
28
29
  json: Type.TOptional<Type.TBoolean>;
29
30
  };
30
31
  export declare function findDeployConfigRoot(startDirectory: string): Promise<string>;
32
+ export declare function createBuildEnvironment(names: string[] | undefined, environmentVariables: Readonly<Record<string, string>> | undefined): {
33
+ env: NodeJS.ProcessEnv;
34
+ names: string[];
35
+ missing: string[];
36
+ };
31
37
  export declare function createFrontendArchive(outputDirectory: string): Promise<{
32
38
  archivePath: string;
33
39
  sha256: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supacloud/cli",
3
- "version": "0.84.0",
3
+ "version": "0.86.0",
4
4
  "description": "Project-scoped CLI for SupaCloud users",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -53,13 +53,13 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "@supacloud/compiler": "^0.43.0",
56
- "@supacloud/delivery": "0.13.0",
56
+ "@supacloud/delivery": "0.14.0",
57
57
  "@supacloud/db": "0.16.0",
58
58
  "typebox": "1.3.34"
59
59
  },
60
60
  "overrides": {
61
61
  "@supacloud/contracts": "0.8.0",
62
- "@supacloud/delivery": "0.13.0",
62
+ "@supacloud/delivery": "0.14.0",
63
63
  "@graphql-tools/utils": "^12.0.3"
64
64
  },
65
65
  "devDependencies": {