@supacloud/cli 0.79.0 → 0.81.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
@@ -179093,11 +179093,13 @@ function resolveSupaCloudContext(env = process.env, cwd = process.cwd(), selecti
179093
179093
  var ACTION_POLICY = {
179094
179094
  deploy: { write: ["deploy"] },
179095
179095
  applications: {
179096
- read: ["list_releases", "get_release", "get_runtime", "get_deployment_evidence", "get_configuration", "get_rollback_snapshot", "logs", "get_preview_plan"],
179096
+ read: ["list_releases", "get_release", "get_runtime", "get_deployment_evidence", "get_configuration", "get_release_transfer_plan", "get_promotion_plan", "get_rollback_snapshot", "get_history", "get_deploy_plan", "logs", "get_preview_plan"],
179097
179097
  write: [
179098
179098
  "upload_release",
179099
179099
  "put_configuration",
179100
+ "transfer_release",
179100
179101
  "activate_release",
179102
+ "deploy_release",
179101
179103
  "rollback_release",
179102
179104
  "reconcile_activation",
179103
179105
  "retire_activation",
@@ -179177,7 +179179,7 @@ var ACTION_POLICY = {
179177
179179
  scheduled_functions: { read: ["list", "get"], write: ["create", "update", "delete"] },
179178
179180
  mutations: { read: ["status"] },
179179
179181
  release: {
179180
- read: ["logical_backup_list", "postgrest_status"],
179182
+ read: ["logical_backup_list", "logical_backup_status", "postgrest_status"],
179181
179183
  local: ["scope_inspect", "scope_rebind", "scope_create"],
179182
179184
  write: ["logical_backup_create", "logical_backup_restore", "postgrest_restart", "release_canary_fixture_stage_replay", "release_canary_fixture_disable_replay"]
179183
179185
  },
@@ -179200,8 +179202,8 @@ var ACTION_POLICY = {
179200
179202
  ai: { local: ["show_skill", "install_skill"] },
179201
179203
  app: {
179202
179204
  local: ["init", "generate", "dev", "watch", "verify-plan", "compile", "check", "graph", "explain", "export-tools", "context", "doctor", "fix", "plan", "build"],
179203
- read: ["status", "logs", "rollback-plan", "preview-plan"],
179204
- write: ["upload", "configure", "deploy", "rollback", "reconcile", "retire", "preview", "previews", "preview-status", "preview-cleanup"]
179205
+ read: ["status", "logs", "transfer-plan", "promote-plan", "rollback-plan", "history", "deploy-plan", "diff", "preview-plan"],
179206
+ write: ["upload", "configure", "transfer", "deploy", "rollback", "reconcile", "retire", "preview", "previews", "preview-status", "preview-cleanup"]
179205
179207
  },
179206
179208
  db: {
179207
179209
  local: ["context", "lint", "explain", "diff", "role_sql"],
@@ -180294,6 +180296,176 @@ var ApplicationRollbackSnapshotSchema = _Object_({
180294
180296
  active: Union([RollbackActivationSchema, Null()]),
180295
180297
  previous: Union([RollbackActivationSchema, Null()])
180296
180298
  }, { additionalProperties: false });
180299
+ // node_modules/@supacloud/delivery/src/application-deploy-plan.ts
180300
+ var CandidateSchema = _Object_({
180301
+ release_id: ApplicationReleaseIdSchema,
180302
+ configuration_id: ApplicationConfigurationIdSchema
180303
+ }, { additionalProperties: false });
180304
+ var ApplicationDeployPlanSchema = _Object_({
180305
+ schema: Literal("supacloud.application-deploy-plan.v1"),
180306
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
180307
+ application_id: ApplicationIdSchema,
180308
+ environment_id: ApplicationIdSchema,
180309
+ candidate: CandidateSchema,
180310
+ current: Union([_Object_({
180311
+ ...CandidateSchema.properties,
180312
+ activation_id: ApplicationActivationIdSchema
180313
+ }, { additionalProperties: false }), Null()]),
180314
+ expected_activation_id: Union([ApplicationActivationIdSchema, Null()]),
180315
+ action: Union([Literal("activate"), Literal("no-op")]),
180316
+ changes: _Object_({
180317
+ release: Boolean2(),
180318
+ configuration: Boolean2(),
180319
+ targets: _Object_({
180320
+ added: _Array_(String2()),
180321
+ removed: _Array_(String2()),
180322
+ changed: _Array_(String2())
180323
+ }, { additionalProperties: false })
180324
+ }, { additionalProperties: false }),
180325
+ migrations: _Object_({
180326
+ ledger_digest: ApplicationReleaseIdSchema,
180327
+ ledger_compatible: Boolean2(),
180328
+ project_migrations_applied: Boolean2(),
180329
+ operator_provisioning: Union([
180330
+ Literal("separate-verification-required"),
180331
+ Literal("not-declared")
180332
+ ])
180333
+ }, { additionalProperties: false }),
180334
+ compatibility: Literal("not-proven"),
180335
+ execution_performed: Literal(false)
180336
+ }, { additionalProperties: false });
180337
+ function parseApplicationDeployPlan(value) {
180338
+ if (!Check2(ApplicationDeployPlanSchema, value) || value.expected_activation_id !== (value.current?.activation_id ?? null) || value.changes.release !== (value.current?.release_id !== value.candidate.release_id) || value.changes.configuration !== (value.current?.configuration_id !== value.candidate.configuration_id) || value.migrations.project_migrations_applied && !value.migrations.ledger_compatible) {
180339
+ throw new Error("Invalid application deploy plan");
180340
+ }
180341
+ const noOp = value.current !== null && !value.changes.release && !value.changes.configuration && Object.values(value.changes.targets).every((names) => names.length === 0) && value.migrations.ledger_compatible && value.migrations.project_migrations_applied && value.migrations.operator_provisioning === "not-declared";
180342
+ if (value.action === "no-op" !== noOp)
180343
+ throw new Error("Invalid application deploy plan action");
180344
+ return value;
180345
+ }
180346
+ // node_modules/@supacloud/delivery/src/application-history.ts
180347
+ var scope = {
180348
+ project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
180349
+ application_id: ApplicationIdSchema,
180350
+ environment_id: ApplicationIdSchema
180351
+ };
180352
+ var timestamp = String2({ pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{6}Z$" });
180353
+ var ApplicationActivationHistoryPositionSchema = _Object_({
180354
+ completed_at: timestamp,
180355
+ activation_id: ApplicationActivationIdSchema
180356
+ }, { additionalProperties: false });
180357
+ var cursorSchema = _Object_({
180358
+ ...scope,
180359
+ ...ApplicationActivationHistoryPositionSchema.properties
180360
+ }, { additionalProperties: false });
180361
+ var ApplicationActivationHistoryCursorSchema = String2({
180362
+ pattern: "^[A-Za-z0-9_-]+$",
180363
+ maxLength: 1024,
180364
+ minLength: 1
180365
+ });
180366
+ var entrySchema = _Object_({
180367
+ ...ApplicationActivationHistoryPositionSchema.properties,
180368
+ release_id: ApplicationReleaseIdSchema,
180369
+ configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
180370
+ previous_activation_id: Union([ApplicationActivationIdSchema, Null()]),
180371
+ is_active: Boolean2()
180372
+ }, { additionalProperties: false });
180373
+ var ApplicationActivationHistorySchema = _Object_({
180374
+ schema: Literal("supacloud.application-activation-history.v1"),
180375
+ ...scope,
180376
+ active_activation_id: Union([ApplicationActivationIdSchema, Null()]),
180377
+ activations: _Array_(entrySchema, { maxItems: 100 }),
180378
+ next_cursor: Union([ApplicationActivationHistoryCursorSchema, Null()])
180379
+ }, { additionalProperties: false });
180380
+ function applicationHistoryTimestampMilliseconds(value) {
180381
+ const milliseconds = `${value.slice(0, 23)}Z`;
180382
+ if (!Check2(timestamp, value) || !Number.isFinite(Date.parse(milliseconds)) || new Date(milliseconds).toISOString() !== milliseconds)
180383
+ throw new Error("Invalid application history timestamp");
180384
+ return milliseconds;
180385
+ }
180386
+ function parseApplicationHistoryCursor(value, scope) {
180387
+ if (!Check2(ApplicationActivationHistoryCursorSchema, value))
180388
+ throw new Error("Invalid application history cursor");
180389
+ const bytes = Buffer.from(value, "base64url");
180390
+ if (bytes.toString("base64url") !== value)
180391
+ throw new Error("Invalid application history cursor");
180392
+ const cursor = JSON.parse(bytes.toString("utf8"));
180393
+ if (!Check2(cursorSchema, cursor) || cursor.project_ref !== scope.project_ref || cursor.application_id !== scope.application_id || cursor.environment_id !== scope.environment_id) {
180394
+ throw new Error("Invalid application history cursor");
180395
+ }
180396
+ applicationHistoryTimestampMilliseconds(cursor.completed_at);
180397
+ return { completed_at: cursor.completed_at, activation_id: cursor.activation_id };
180398
+ }
180399
+ function applicationHistoryPositionBefore(left, right) {
180400
+ return left.completed_at < right.completed_at || left.completed_at === right.completed_at && left.activation_id < right.activation_id;
180401
+ }
180402
+ function parseApplicationActivationHistory(value) {
180403
+ if (!Check2(ApplicationActivationHistorySchema, value))
180404
+ throw new Error("Invalid application activation history");
180405
+ const seen = new Set;
180406
+ let previous;
180407
+ for (const entry of value.activations) {
180408
+ applicationHistoryTimestampMilliseconds(entry.completed_at);
180409
+ if (seen.has(entry.activation_id) || previous && !applicationHistoryPositionBefore(entry, previous) || entry.previous_activation_id === entry.activation_id || entry.is_active !== (entry.activation_id === value.active_activation_id)) {
180410
+ throw new Error("Invalid application activation history");
180411
+ }
180412
+ seen.add(entry.activation_id);
180413
+ previous = entry;
180414
+ }
180415
+ if (value.next_cursor !== null) {
180416
+ const cursor = parseApplicationHistoryCursor(value.next_cursor, value);
180417
+ if (!previous || cursor.activation_id !== previous.activation_id || cursor.completed_at !== previous.completed_at) {
180418
+ throw new Error("Invalid application activation history");
180419
+ }
180420
+ }
180421
+ return structuredClone(value);
180422
+ }
180423
+ // node_modules/@supacloud/delivery/src/application-release-transfer.ts
180424
+ var projectRef = String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" });
180425
+ var source = _Object_({
180426
+ project_ref: projectRef,
180427
+ release_id: ApplicationReleaseIdSchema,
180428
+ manifest_sha256: ApplicationReleaseIdSchema
180429
+ }, { additionalProperties: false });
180430
+ var identity = {
180431
+ project_ref: projectRef,
180432
+ application_id: ApplicationIdSchema,
180433
+ source,
180434
+ candidate_release_id: ApplicationReleaseIdSchema
180435
+ };
180436
+ var ApplicationReleaseTransferPlanSchema = _Object_({
180437
+ schema: Literal("supacloud.application-release-transfer-plan.v1"),
180438
+ ...identity,
180439
+ action: Union([Literal("materialize"), Literal("no-op")]),
180440
+ execution_performed: Literal(false)
180441
+ }, { additionalProperties: false });
180442
+ var ApplicationReleaseTransferResultSchema = _Object_({
180443
+ schema: Literal("supacloud.application-release-transfer-result.v1"),
180444
+ ...identity,
180445
+ release: ApplicationReleaseRecordSchema,
180446
+ activation_performed: Literal(false)
180447
+ }, { additionalProperties: false });
180448
+ function assertIdentity(value) {
180449
+ if (value.source.release_id !== applicationReleaseId(value.source.project_ref, value.application_id, value.source.manifest_sha256) || value.candidate_release_id !== applicationReleaseId(value.project_ref, value.application_id, value.source.manifest_sha256)) {
180450
+ throw new Error("Invalid application release transfer identity");
180451
+ }
180452
+ }
180453
+ function parseApplicationReleaseTransferPlan(candidate) {
180454
+ if (!Check2(ApplicationReleaseTransferPlanSchema, candidate))
180455
+ throw new Error("Invalid application release transfer plan");
180456
+ assertIdentity(candidate);
180457
+ return candidate;
180458
+ }
180459
+ function parseApplicationReleaseTransferResult(candidate) {
180460
+ if (!Check2(ApplicationReleaseTransferResultSchema, candidate))
180461
+ throw new Error("Invalid application release transfer result");
180462
+ assertIdentity(candidate);
180463
+ const release = parseApplicationReleaseRecord(candidate.release);
180464
+ if (release.project_ref !== candidate.project_ref || release.application_id !== candidate.application_id || release.release_id !== candidate.candidate_release_id || release.manifest_sha256 !== candidate.source.manifest_sha256) {
180465
+ throw new Error("Invalid application release transfer result");
180466
+ }
180467
+ return candidate;
180468
+ }
180297
180469
  // node_modules/@supacloud/delivery/src/deployment-evidence.ts
180298
180470
  var closed3 = { additionalProperties: false };
180299
180471
  var sha256 = String2({ pattern: "^[a-f0-9]{64}$" });
@@ -180419,6 +180591,116 @@ function parseDeploymentEvidence(value) {
180419
180591
  }
180420
180592
  return structuredClone(value);
180421
180593
  }
180594
+ // node_modules/@supacloud/delivery/src/application-promotion.ts
180595
+ var closed4 = { additionalProperties: false };
180596
+ var projectRef2 = String2({ pattern: "^[a-z0-9-]{1,20}$" });
180597
+ var sha2562 = ApplicationReleaseIdSchema;
180598
+ var nullableActivation = Union([ApplicationActivationIdSchema, Null()]);
180599
+ var nullableDigest = Union([sha2562, Null()]);
180600
+ var observation = {
180601
+ activation_id: nullableActivation,
180602
+ receipt_confirmed: Boolean2(),
180603
+ ready: Boolean2(),
180604
+ smoke_verified: Boolean2(),
180605
+ evidence_sha256: nullableDigest,
180606
+ migration_ledger_digest: nullableDigest
180607
+ };
180608
+ var blocker = [
180609
+ "SOURCE_NOT_ACTIVE",
180610
+ "SOURCE_RECEIPT_UNCONFIRMED",
180611
+ "SOURCE_NOT_READY",
180612
+ "SOURCE_SMOKE_UNVERIFIED",
180613
+ "TARGET_CONFIGURATION_MISSING",
180614
+ "TARGET_CONFIGURATION_MISMATCH",
180615
+ "MIGRATION_PENDING",
180616
+ "MIGRATION_CONFLICT",
180617
+ "OPERATOR_PROVISIONING_REQUIRED",
180618
+ "BACKUP_REQUIRED"
180619
+ ];
180620
+ var ApplicationPromotionPlanSchema = _Object_({
180621
+ schema: Literal("supacloud.application-promotion-plan.v1"),
180622
+ project_ref: projectRef2,
180623
+ application_id: ApplicationIdSchema,
180624
+ environment_id: ApplicationIdSchema,
180625
+ manifest_sha256: sha2562,
180626
+ plan_sha256: sha2562,
180627
+ source: _Object_({
180628
+ project_ref: projectRef2,
180629
+ environment_id: ApplicationIdSchema,
180630
+ release_id: sha2562,
180631
+ ...observation
180632
+ }, closed4),
180633
+ target: _Object_({
180634
+ candidate_release_id: sha2562,
180635
+ current_release_id: Union([sha2562, Null()]),
180636
+ artifact_action: Union([Literal("materialize"), Literal("reuse")]),
180637
+ configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
180638
+ configuration: Union([ApplicationConfigurationViewSchema, Null()]),
180639
+ ...observation
180640
+ }, closed4),
180641
+ migrations: _Object_({
180642
+ ledger_digest: sha2562,
180643
+ ledger_compatible: Boolean2(),
180644
+ project_migrations_applied: Boolean2(),
180645
+ pending_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { maxItems: 4096, uniqueItems: true }),
180646
+ operator_provisioning_required: Boolean2()
180647
+ }, closed4),
180648
+ backup: _Object_({
180649
+ required: Boolean2(),
180650
+ confirmed: Literal(false)
180651
+ }, closed4),
180652
+ action: Union([Literal("promote"), Literal("no-op"), Literal("blocked")]),
180653
+ blockers: _Array_(Enum([...blocker]), {
180654
+ maxItems: blocker.length,
180655
+ uniqueItems: true
180656
+ }),
180657
+ steps: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 8, uniqueItems: true }),
180658
+ execution_performed: Literal(false),
180659
+ data_recovery: Literal("separate-required")
180660
+ }, closed4);
180661
+ function applicationPromotionPlanDigest(value) {
180662
+ return digest(canonical(value));
180663
+ }
180664
+ function applicationPromotionAction(value) {
180665
+ if (value.blockers.length > 0)
180666
+ return "blocked";
180667
+ return value.target.artifact_action === "reuse" && value.target.current_release_id === value.target.candidate_release_id && value.target.configuration !== null && value.target.activation_id !== null && value.target.receipt_confirmed && value.target.ready && value.target.smoke_verified && value.migrations.project_migrations_applied && !value.migrations.operator_provisioning_required && (!value.backup.required || value.backup.confirmed) ? "no-op" : "promote";
180668
+ }
180669
+ function applicationPromotionSteps(value) {
180670
+ if (value.action === "no-op")
180671
+ return [];
180672
+ return [
180673
+ ...value.blockers.some((code) => code.startsWith("SOURCE_")) ? ["verify-source"] : [],
180674
+ ...value.blockers.some((code) => code.startsWith("TARGET_CONFIGURATION_")) ? ["bind-target-configuration"] : [],
180675
+ ...value.blockers.includes("MIGRATION_CONFLICT") ? ["resolve-migration-conflicts"] : [],
180676
+ ...!value.backup.required || value.backup.confirmed ? [] : ["backup"],
180677
+ ...value.migrations.project_migrations_applied ? [] : ["review-and-apply-migrations"],
180678
+ ...value.migrations.operator_provisioning_required ? ["verify-operator-provisioning"] : [],
180679
+ ...value.action === "promote" ? [
180680
+ ...value.target.artifact_action === "materialize" ? ["transfer"] : [],
180681
+ "activate-with-cas",
180682
+ "verify-runtime-and-smoke"
180683
+ ] : []
180684
+ ];
180685
+ }
180686
+ function parseApplicationPromotionPlan(value) {
180687
+ if (!Check2(ApplicationPromotionPlanSchema, value))
180688
+ throw new Error("Invalid application promotion plan");
180689
+ const { plan_sha256: _planSha256, ...content } = value;
180690
+ if (value.migrations.project_migrations_applied && (!value.migrations.ledger_compatible || value.migrations.pending_versions.length > 0) || !value.source.activation_id && (value.source.ready || value.source.receipt_confirmed || value.source.smoke_verified) || !value.target.activation_id && (value.target.ready || value.target.receipt_confirmed || value.target.smoke_verified) || !value.blockers.length && (!value.source.ready || !value.source.receipt_confirmed || !value.source.smoke_verified || !value.source.activation_id || !value.target.configuration || !value.migrations.ledger_compatible)) {
180691
+ throw new Error("Invalid application promotion prerequisites");
180692
+ }
180693
+ if (value.backup.required !== !value.migrations.project_migrations_applied || [value.source, value.target].some((observation) => observation.smoke_verified && (observation.evidence_sha256 === null || observation.migration_ledger_digest === null)) || value.target.smoke_verified && value.target.migration_ledger_digest !== value.migrations.ledger_digest) {
180694
+ throw new Error("Invalid application promotion migration binding");
180695
+ }
180696
+ if (value.source.release_id !== applicationReleaseId(value.source.project_ref, value.application_id, value.manifest_sha256) || value.target.candidate_release_id !== applicationReleaseId(value.project_ref, value.application_id, value.manifest_sha256) || value.action !== applicationPromotionAction(content) || canonical(value.steps) !== canonical(applicationPromotionSteps(content)) || value.plan_sha256 !== applicationPromotionPlanDigest(content) || value.target.configuration !== null && (() => {
180697
+ const configuration = parseApplicationConfigurationView(value.target.configuration);
180698
+ return configuration.project_ref !== value.project_ref || configuration.application_id !== value.application_id || configuration.environment_id !== value.environment_id || configuration.configuration_id !== value.target.configuration_id;
180699
+ })()) {
180700
+ throw new Error("Invalid application promotion plan identity");
180701
+ }
180702
+ return structuredClone(value);
180703
+ }
180422
180704
  // node_modules/@supacloud/delivery/src/application-runtime-identity.ts
180423
180705
  var ApplicationRuntimeIdentitySchema = _Object_({
180424
180706
  schema: Literal("supacloud.application-runtime.v1"),
@@ -180465,7 +180747,7 @@ function parseApplicationReadinessReport(value) {
180465
180747
  return value;
180466
180748
  }
180467
180749
  // node_modules/@supacloud/delivery/src/delivery-migration-archive.ts
180468
- var entrySchema = _Object_({
180750
+ var entrySchema2 = _Object_({
180469
180751
  version: String2({ pattern: "^[1-9][0-9]{0,18}$" }),
180470
180752
  name: String2({ pattern: "^[A-Za-z][A-Za-z0-9_-]{0,127}$" }),
180471
180753
  executor: Union([Literal("project-migration"), Literal("operator-provisioning")]),
@@ -180479,7 +180761,7 @@ var archiveSchema = _Object_({
180479
180761
  compatibility: Literal("not-proven"),
180480
180762
  executionPerformed: Literal(false),
180481
180763
  dataRecovery: Literal("separate-required"),
180482
- migrations: _Array_(entrySchema, { minItems: 1, maxItems: 128 })
180764
+ migrations: _Array_(entrySchema2, { minItems: 1, maxItems: 128 })
180483
180765
  }, { additionalProperties: false });
180484
180766
  async function readDeliveryMigrationArchive(manifestPath, target) {
180485
180767
  try {
@@ -181426,7 +181708,7 @@ ALTER TABLE supacloud_commands.execution_receipts
181426
181708
  DROP COLUMN IF EXISTS recovery_attempts;
181427
181709
  `;
181428
181710
  var MAX_MIGRATION_VERSION = 9223372036854775807n;
181429
- function sha2562(value) {
181711
+ function sha2563(value) {
181430
181712
  return createHash22("sha256").update(value).digest("hex");
181431
181713
  }
181432
181714
  function normalizedSql(value) {
@@ -181495,7 +181777,7 @@ function planMigrationRebase(migrations, options, baselineSql) {
181495
181777
  file: migration.file,
181496
181778
  version: migration.version,
181497
181779
  name: migration.name,
181498
- sha256: sha2562(normalizedSql(migration.sql))
181780
+ sha256: sha2563(normalizedSql(migration.sql))
181499
181781
  }));
181500
181782
  return {
181501
181783
  version: 1,
@@ -181505,8 +181787,8 @@ function planMigrationRebase(migrations, options, baselineSql) {
181505
181787
  baselineMigration,
181506
181788
  retainedMigrations: retained.map((migration) => migration.file),
181507
181789
  archivedMigrations: archived.map((migration) => migration.file),
181508
- sourceHistorySha256: sha2562(JSON.stringify(sourceHistory)),
181509
- baselineSha256: sha2562(normalizedBaseline),
181790
+ sourceHistorySha256: sha2563(JSON.stringify(sourceHistory)),
181791
+ baselineSha256: sha2563(normalizedBaseline),
181510
181792
  warnings: [
181511
181793
  "The baseline must come from a schema-only snapshot of the verified target database.",
181512
181794
  "Data backfills, reference data and non-replayable side effects need a separate review.",
@@ -181542,7 +181824,7 @@ async function rebaseMigrations(options) {
181542
181824
  file: migration.file,
181543
181825
  version: migration.version,
181544
181826
  name: migration.name,
181545
- sha256: sha2562(normalizedSql(migration.sql))
181827
+ sha256: sha2563(normalizedSql(migration.sql))
181546
181828
  }))
181547
181829
  }, null, 2) + `
181548
181830
  `);
@@ -184444,7 +184726,7 @@ function clientId(value) {
184444
184726
  }
184445
184727
  return value;
184446
184728
  }
184447
- function projectRef(value) {
184729
+ function projectRef3(value) {
184448
184730
  if (typeof value !== "string" || !value.trim())
184449
184731
  throw new Error("'ref' is required");
184450
184732
  return projectRefPathSegment(value.trim(), "OAuth client");
@@ -184596,7 +184878,7 @@ function registerOAuthClientTools(server2, http) {
184596
184878
  client_id: optional(String2(), "[get/delete] Exact release-canary public OAuth client ID"),
184597
184879
  redirect_uri: optional(String2(), "[create/delete] Exact HTTPS or port-bound RFC 8252 loopback callback")
184598
184880
  }, async ({ action, ref, client_id, redirect_uri }) => {
184599
- const targetRef = projectRef(ref);
184881
+ const targetRef = projectRef3(ref);
184600
184882
  if (action === "list")
184601
184883
  return listReleaseCanaryClients(http, targetRef);
184602
184884
  if (action === "get")
@@ -187267,6 +187549,65 @@ var ApplicationActivationWriteSchema2 = ApplicationActivationWriteSchema;
187267
187549
  var ApplicationActivationResultSchema2 = ApplicationActivationResultSchema;
187268
187550
  var ApplicationActivationRetirementResultSchema2 = ApplicationActivationRetirementResultSchema;
187269
187551
  var ApplicationRollbackSnapshotSchema2 = ApplicationRollbackSnapshotSchema;
187552
+ var ApplicationActivationHistoryCursorSchema2 = ApplicationActivationHistoryCursorSchema;
187553
+
187554
+ // src/shared/tools/application-release-transfer.ts
187555
+ async function applicationReleaseTransfer(http, input, project) {
187556
+ const operation = `applications.${input.action}`;
187557
+ const identity = {
187558
+ project_ref: input.ref,
187559
+ application_id: input.id,
187560
+ source_ref: input.sourceRef,
187561
+ source_release_id: input.sourceReleaseId
187562
+ };
187563
+ const path = `/v1/projects/${project}/applications/${encodeURIComponent(input.id)}`;
187564
+ const query = new URLSearchParams({ source_ref: input.sourceRef, source_release_id: input.sourceReleaseId });
187565
+ const response = await http.get(`${path}/release-transfer-plan?${query}`, { maxJsonBytes: 65536, responseTimeoutMs: 30000 });
187566
+ if (!response.ok)
187567
+ return releaseControlFailure(operation, "HTTP_ERROR", response.transportError ? null : response.status, identity);
187568
+ let plan;
187569
+ try {
187570
+ if (response.status !== 200)
187571
+ throw new Error;
187572
+ plan = parseApplicationReleaseTransferPlan(response.data);
187573
+ if (plan.project_ref !== input.ref || plan.application_id !== input.id || plan.source.project_ref !== input.sourceRef || plan.source.release_id !== input.sourceReleaseId)
187574
+ throw new Error;
187575
+ } catch {
187576
+ return releaseControlFailure(operation, "INVALID_RESPONSE", response.status, identity);
187577
+ }
187578
+ if (input.action === "get_release_transfer_plan")
187579
+ return releaseControlSuccess(operation, { ...identity, plan });
187580
+ const safeIdentity = {
187581
+ ...identity,
187582
+ release_id: plan.candidate_release_id,
187583
+ manifest_sha256: plan.source.manifest_sha256
187584
+ };
187585
+ if (plan.action === "no-op")
187586
+ return releaseControlSuccess(operation, {
187587
+ ...safeIdentity,
187588
+ no_op: true,
187589
+ execution_performed: false,
187590
+ activation_performed: false,
187591
+ plan
187592
+ });
187593
+ const result = await http.postReleaseMutation(`${path}/release-transfers`, {
187594
+ source_ref: input.sourceRef,
187595
+ source_release_id: input.sourceReleaseId,
187596
+ expected_manifest_sha256: plan.source.manifest_sha256
187597
+ }, { timeoutMs: 120000 });
187598
+ if (!result.ok)
187599
+ return releaseControlMutationFailure(operation, result, safeIdentity);
187600
+ try {
187601
+ if (result.status !== 200)
187602
+ throw new Error;
187603
+ const receipt = parseApplicationReleaseTransferResult(result.data);
187604
+ if (receipt.project_ref !== input.ref || receipt.application_id !== input.id || receipt.source.project_ref !== input.sourceRef || receipt.source.release_id !== input.sourceReleaseId || receipt.candidate_release_id !== plan.candidate_release_id || receipt.source.manifest_sha256 !== plan.source.manifest_sha256)
187605
+ throw new Error;
187606
+ return releaseControlSuccess(operation, { ...safeIdentity, no_op: false, transfer: receipt });
187607
+ } catch {
187608
+ return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.status, safeIdentity);
187609
+ }
187610
+ }
187270
187611
 
187271
187612
  // src/shared/tools/application-preview-tools.ts
187272
187613
  var APPLICATION_PREVIEW_ACTIONS = [
@@ -187353,14 +187694,14 @@ var actionFields = {
187353
187694
  get_preview: ["preview_id", "wait", "timeout_seconds"],
187354
187695
  cleanup_preview: ["preview_id"]
187355
187696
  };
187356
- function timestamp(value) {
187697
+ function timestamp2(value) {
187357
187698
  return Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
187358
187699
  }
187359
187700
  function receipt(value, identity) {
187360
187701
  if (!Check2(receiptSchema, value) || value.project_ref !== identity.ref || value.application_id !== identity.id || value.environment_id !== identity.environment || identity.previewId && value.preview_id !== identity.previewId || value.resources.build_artifact.release_id !== value.release_id || value.resources.storage_namespace.namespace !== value.resources.database_branch.branch_ref) {
187361
187702
  throw new Error("Invalid preview receipt");
187362
187703
  }
187363
- if (value.expires_at !== null && !timestamp(value.expires_at) || value.created_at !== undefined && !timestamp(value.created_at) || value.updated_at !== undefined && !timestamp(value.updated_at) || value.expires_at !== null && value.created_at !== undefined && !Check2(ttlSecondsSchema, (Date.parse(value.expires_at) - Date.parse(value.created_at)) / 1000)) {
187704
+ if (value.expires_at !== null && !timestamp2(value.expires_at) || value.created_at !== undefined && !timestamp2(value.created_at) || value.updated_at !== undefined && !timestamp2(value.updated_at) || value.expires_at !== null && value.created_at !== undefined && !Check2(ttlSecondsSchema, (Date.parse(value.expires_at) - Date.parse(value.created_at)) / 1000)) {
187364
187705
  throw new Error("Invalid preview expiry");
187365
187706
  }
187366
187707
  if (value.status === "ready") {
@@ -187604,9 +187945,15 @@ var APPLICATION_TOOL_SCHEMA = {
187604
187945
  "get_deployment_evidence",
187605
187946
  "get_configuration",
187606
187947
  "put_configuration",
187948
+ "get_deploy_plan",
187949
+ "deploy_release",
187950
+ "get_release_transfer_plan",
187951
+ "transfer_release",
187952
+ "get_promotion_plan",
187607
187953
  "activate_release",
187608
187954
  "rollback_release",
187609
187955
  "get_rollback_snapshot",
187956
+ "get_history",
187610
187957
  "reconcile_activation",
187611
187958
  "retire_activation",
187612
187959
  ...APPLICATION_PREVIEW_ACTIONS,
@@ -187614,15 +187961,18 @@ var APPLICATION_TOOL_SCHEMA = {
187614
187961
  ]), "Action"),
187615
187962
  ref: withDescription(String2(), "Project ref"),
187616
187963
  id: withDescription(ApplicationIdSchema2, "Application ID"),
187617
- environment_id: optional(withDescription(ApplicationIdSchema2, "[get_runtime/get_configuration/put_configuration/get_rollback_snapshot/rollback_release] Environment ID")),
187618
- configuration_id: optional(ApplicationConfigurationIdSchema2, "[get_configuration/activate_release/rollback_release] Immutable revision; required for explicit activation"),
187619
- activation_id: optional(ApplicationActivationIdSchema2, "[activate_release/reconcile_activation/retire_activation/rollback_release] Explicit stable activation ID; generated for rollback if omitted"),
187620
- expected_activation_id: optional(Union([ApplicationActivationIdSchema2, Null(), Literal("absent")]), "[activate_release/rollback_release] Current activation ID, or absent for first activation; selected by platform for default rollback"),
187964
+ environment_id: optional(withDescription(ApplicationIdSchema2, "[get_runtime/get_configuration/put_configuration/get_deploy_plan/deploy_release/get_rollback_snapshot/rollback_release/get_history] Environment ID")),
187965
+ configuration_id: optional(ApplicationConfigurationIdSchema2, "[get_configuration/get_deploy_plan/deploy_release/activate_release/rollback_release/get_history] Immutable revision; required for deployment"),
187966
+ 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"),
187967
+ 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"),
187621
187968
  configuration_path: optional(String2(), "[put_configuration] Local configuration write JSON including revision and expected revision"),
187622
187969
  manifest_path: optional(String2(), "[upload_release] Local delivery.manifest.json"),
187623
- release_id: optional(ApplicationReleaseIdSchema2, "[get_release/activate_release/reconcile_activation/rollback_release] Immutable application release ID; platform selects previous for default rollback"),
187624
- cursor: optional(ApplicationReleaseIdSchema2, "[list_releases] Last release ID"),
187625
- limit: optional(Integer({ minimum: 1, maximum: 100 }), "[list_releases] Page size, default 50"),
187970
+ 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"),
187971
+ source_ref: optional(String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" }), "[get_release_transfer_plan/transfer_release] Source project ref"),
187972
+ source_release_id: optional(ApplicationReleaseIdSchema2, "[get_release_transfer_plan/transfer_release] Source immutable release ID"),
187973
+ source_environment_id: optional(ApplicationIdSchema2, "[get_promotion_plan] Source environment"),
187974
+ cursor: optional(Union([ApplicationReleaseIdSchema2, ApplicationActivationHistoryCursorSchema2]), "[list_releases/get_history] Returned page cursor"),
187975
+ limit: optional(Integer({ minimum: 1, maximum: 100 }), "[list_releases/get_history] Page size, default 50/20"),
187626
187976
  offset: optional(Integer({ minimum: 0, maximum: 1e6 }), "[logs] Result offset"),
187627
187977
  service: optional(String2(), "[logs] Application target/service filter"),
187628
187978
  search: optional(String2(), "[logs] Full-text log filter"),
@@ -187653,6 +188003,84 @@ function boundRelease(value, ref, id) {
187653
188003
  throw new Error("Unbound application release");
187654
188004
  return release;
187655
188005
  }
188006
+ async function readDeployPlan(http, args, project) {
188007
+ const ref = text(args, "ref"), id = text(args, "id"), environmentId = text(args, "environment_id");
188008
+ const releaseId = text(args, "release_id"), configurationId = text(args, "configuration_id");
188009
+ if (!Check2(ApplicationIdSchema2, environmentId) || !Check2(ApplicationReleaseIdSchema2, releaseId) || !Check2(ApplicationConfigurationIdSchema2, configurationId))
188010
+ throw new Error("Invalid deployment plan identity");
188011
+ const identity = {
188012
+ project_ref: ref,
188013
+ application_id: id,
188014
+ environment_id: environmentId,
188015
+ release_id: releaseId,
188016
+ configuration_id: configurationId
188017
+ };
188018
+ const query = new URLSearchParams({ release_id: releaseId, configuration_id: configurationId });
188019
+ const response = await http.get(`/v1/projects/${project}/applications/${encodeURIComponent(id)}/environments/${encodeURIComponent(environmentId)}/deploy-plan?${query}`, { maxJsonBytes: 65536, responseTimeoutMs: 30000 });
188020
+ const operation = `applications.${text(args, "action")}`;
188021
+ if (!response.ok)
188022
+ return { failure: releaseControlFailure(operation, "HTTP_ERROR", response.transportError ? null : response.status, identity) };
188023
+ let plan;
188024
+ try {
188025
+ if (response.status !== 200)
188026
+ throw new Error("Incomplete deployment plan response");
188027
+ plan = parseApplicationDeployPlan(response.data);
188028
+ if (plan.project_ref !== ref || plan.application_id !== id || plan.environment_id !== environmentId || plan.candidate.release_id !== releaseId || plan.candidate.configuration_id !== configurationId)
188029
+ throw new Error;
188030
+ } catch {
188031
+ return { failure: releaseControlFailure(operation, "INVALID_RESPONSE", response.status, identity) };
188032
+ }
188033
+ return { plan, identity };
188034
+ }
188035
+ async function deployAction(http, args, project) {
188036
+ const activationId = args["activation_id"], expected = args["expected_activation_id"];
188037
+ if (activationId !== undefined && !Check2(ApplicationActivationIdSchema2, activationId)) {
188038
+ throw new Error("Invalid application activation ID");
188039
+ }
188040
+ if (expected !== undefined && expected !== null && expected !== "absent" && !Check2(ApplicationActivationIdSchema2, expected))
188041
+ throw new Error("Invalid expected activation ID");
188042
+ if (activationId !== undefined && expected !== undefined) {
188043
+ return activationAction(http, { ...args, action: "activate_release" }, project, {
188044
+ operation: "applications.deploy_release",
188045
+ configuration_id: args["configuration_id"],
188046
+ expected_activation_id: expected === "absent" ? null : expected
188047
+ });
188048
+ }
188049
+ const observed = await readDeployPlan(http, args, project);
188050
+ if (observed.failure)
188051
+ return observed.failure;
188052
+ const { plan, identity } = observed;
188053
+ if (expected !== undefined && (expected === "absent" ? null : expected) !== plan.expected_activation_id) {
188054
+ return releaseControlFailure("applications.deploy_release", "HTTP_ERROR", 409, {
188055
+ ...identity,
188056
+ reason: "EXPECTED_ACTIVATION_CONFLICT",
188057
+ expected_activation_id: plan.expected_activation_id
188058
+ });
188059
+ }
188060
+ if (plan.action === "no-op")
188061
+ return releaseControlSuccess("applications.deploy_release", {
188062
+ ...identity,
188063
+ no_op: true,
188064
+ execution_performed: false,
188065
+ activation_id: plan.current.activation_id,
188066
+ expected_activation_id: plan.expected_activation_id,
188067
+ plan,
188068
+ ...activationId === undefined ? {} : { requested_activation_id: activationId }
188069
+ });
188070
+ const selectedId = activationId ?? crypto.randomUUID();
188071
+ if (selectedId === plan.expected_activation_id)
188072
+ throw new Error("Deployment requires a new activation ID");
188073
+ return activationAction(http, {
188074
+ ...args,
188075
+ action: "activate_release",
188076
+ activation_id: selectedId,
188077
+ expected_activation_id: plan.expected_activation_id
188078
+ }, project, {
188079
+ operation: "applications.deploy_release",
188080
+ configuration_id: args["configuration_id"],
188081
+ expected_activation_id: plan.expected_activation_id
188082
+ });
188083
+ }
187656
188084
  async function configurationAction(http, args, project) {
187657
188085
  const action = text(args, "action"), ref = text(args, "ref"), id = text(args, "id");
187658
188086
  const environmentId = text(args, "environment_id"), operation = `applications.${action}`;
@@ -187699,7 +188127,7 @@ async function configurationAction(http, args, project) {
187699
188127
  return releaseControlFailure(operation, action === "put_configuration" ? "OUTCOME_UNKNOWN" : "INVALID_RESPONSE", result.status, identity);
187700
188128
  }
187701
188129
  }
187702
- async function activationAction(http, args, project, rollback) {
188130
+ async function activationAction(http, args, project, selection) {
187703
188131
  const action = text(args, "action"), ref = text(args, "ref"), id = text(args, "id");
187704
188132
  const environmentId = text(args, "environment_id"), activationId = text(args, "activation_id");
187705
188133
  const releaseId = args["release_id"] === undefined ? undefined : text(args, "release_id");
@@ -187709,7 +188137,7 @@ async function activationAction(http, args, project, rollback) {
187709
188137
  if (!Check2(ApplicationIdSchema2, environmentId) || !Check2(ApplicationActivationIdSchema2, activationId) || action !== "retire_activation" && !Check2(ApplicationReleaseIdSchema2, releaseId)) {
187710
188138
  throw new Error("Invalid application activation identity");
187711
188139
  }
187712
- const operation = rollback ? "applications.rollback_release" : `applications.${action}`;
188140
+ const operation = selection?.operation ?? `applications.${action}`;
187713
188141
  const path = `/v1/projects/${project}/applications/${encodeURIComponent(id)}/environments/${encodeURIComponent(environmentId)}/activations`;
187714
188142
  const identity = {
187715
188143
  project_ref: ref,
@@ -187718,7 +188146,11 @@ async function activationAction(http, args, project, rollback) {
187718
188146
  activation_id: activationId,
187719
188147
  ...releaseId ? { release_id: releaseId } : {}
187720
188148
  };
187721
- const safeState = { ...identity, ...rollback ?? {} };
188149
+ const selectedState = selection ? {
188150
+ configuration_id: selection.configuration_id,
188151
+ expected_activation_id: selection.expected_activation_id
188152
+ } : {};
188153
+ const safeState = { ...identity, ...selectedState };
187722
188154
  let body = {};
187723
188155
  if (action === "activate_release") {
187724
188156
  body = {
@@ -187745,7 +188177,7 @@ async function activationAction(http, args, project, rollback) {
187745
188177
  if (!Check2(ApplicationActivationResultSchema2, result.data) || Object.entries(identity).some(([key, value]) => Reflect.get(result.data, key) !== value) || action === "reconcile_activation" && !result.data.replayed) {
187746
188178
  return releaseControlFailure(operation, "OUTCOME_UNKNOWN", result.status, safeState);
187747
188179
  }
187748
- return releaseControlSuccess(operation, { ...result.data, ...rollback ?? {} });
188180
+ return releaseControlSuccess(operation, { ...result.data, ...selectedState });
187749
188181
  }
187750
188182
  async function rollbackAction(http, args, project) {
187751
188183
  const ref = text(args, "ref"), id = text(args, "id"), environmentId = text(args, "environment_id");
@@ -187794,10 +188226,38 @@ async function rollbackAction(http, args, project) {
187794
188226
  configuration_id: configurationId,
187795
188227
  expected_activation_id: expectedActivationId
187796
188228
  }, project, {
188229
+ operation: "applications.rollback_release",
187797
188230
  configuration_id: configurationId,
187798
188231
  expected_activation_id: expectedActivationId === "absent" ? null : expectedActivationId
187799
188232
  });
187800
188233
  }
188234
+ async function historyAction(http, args, project) {
188235
+ const ref = text(args, "ref"), id = text(args, "id"), environmentId = text(args, "environment_id");
188236
+ if (!Check2(ApplicationIdSchema2, environmentId))
188237
+ throw new Error("Invalid environment ID");
188238
+ const limit = args["limit"] ?? 20, cursor = args["cursor"];
188239
+ if (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1 || limit > 100 || cursor !== undefined && typeof cursor !== "string")
188240
+ throw new Error("Invalid history page");
188241
+ const query = new URLSearchParams({ limit: String(limit) });
188242
+ const scope = { project_ref: ref, application_id: id, environment_id: environmentId };
188243
+ const before = typeof cursor === "string" ? parseApplicationHistoryCursor(cursor, scope) : null;
188244
+ if (typeof cursor === "string")
188245
+ query.set("cursor", cursor);
188246
+ const operation = "applications.get_history";
188247
+ const response = await http.get(`/v1/projects/${project}/applications/${encodeURIComponent(id)}/environments/${encodeURIComponent(environmentId)}/history?${query}`, { maxJsonBytes: 262144, responseTimeoutMs: 30000 });
188248
+ if (!response.ok)
188249
+ return releaseControlFailure(operation, "HTTP_ERROR", response.transportError ? null : response.status, scope);
188250
+ try {
188251
+ if (response.status !== 200)
188252
+ throw new Error;
188253
+ const history = parseApplicationActivationHistory(response.data);
188254
+ if (history.project_ref !== ref || history.application_id !== id || history.environment_id !== environmentId || history.activations.length > limit || history.next_cursor !== null && history.activations.length !== limit || before && history.activations.some((entry) => !applicationHistoryPositionBefore(entry, before)))
188255
+ throw new Error;
188256
+ return releaseControlSuccess(operation, { project_ref: ref, application_id: id, environment_id: environmentId, history });
188257
+ } catch {
188258
+ return releaseControlFailure(operation, "INVALID_RESPONSE", response.status, scope);
188259
+ }
188260
+ }
187801
188261
  function registerApplicationTools(server2, http) {
187802
188262
  registerTool(server2, "applications", "Store, inspect and explicitly activate immutable HTTP/Worker application releases. Upload does not activate a release.", APPLICATION_TOOL_SCHEMA, async (args) => {
187803
188263
  const action = text(args, "action"), ref = text(args, "ref"), id = text(args, "id");
@@ -187806,9 +188266,63 @@ function registerApplicationTools(server2, http) {
187806
188266
  throw new Error("Invalid application ID");
187807
188267
  const path = `/v1/projects/${project}/applications/${encodeURIComponent(id)}/releases`;
187808
188268
  const operation = `applications.${action}`;
188269
+ if (action === "get_promotion_plan") {
188270
+ const environmentId = text(args, "environment_id");
188271
+ const sourceRef = text(args, "source_ref"), sourceEnvironmentId = text(args, "source_environment_id");
188272
+ const sourceReleaseId = text(args, "source_release_id");
188273
+ if (!/^[a-z0-9-]{1,20}$/.test(sourceRef) || !Check2(ApplicationReleaseIdSchema2, sourceReleaseId) || !Check2(ApplicationIdSchema2, environmentId) || !Check2(ApplicationIdSchema2, sourceEnvironmentId)) {
188274
+ throw new Error("Invalid promotion environment");
188275
+ }
188276
+ const query = new URLSearchParams({
188277
+ source_ref: sourceRef,
188278
+ source_environment_id: sourceEnvironmentId,
188279
+ source_release_id: sourceReleaseId
188280
+ });
188281
+ if (typeof args["configuration_id"] === "string")
188282
+ query.set("configuration_id", args["configuration_id"]);
188283
+ const result = await http.get(`/v1/projects/${project}/applications/${encodeURIComponent(id)}/environments/${encodeURIComponent(environmentId)}/promotion-plan?${query}`, { maxJsonBytes: 262144, responseTimeoutMs: 30000 });
188284
+ const identity = {
188285
+ project_ref: ref,
188286
+ application_id: id,
188287
+ environment_id: environmentId,
188288
+ source_ref: sourceRef,
188289
+ source_environment_id: sourceEnvironmentId,
188290
+ source_release_id: sourceReleaseId
188291
+ };
188292
+ if (!result.ok)
188293
+ return releaseControlFailure(operation, "HTTP_ERROR", result.status, identity);
188294
+ try {
188295
+ if (result.status !== 200)
188296
+ throw new Error;
188297
+ const plan = parseApplicationPromotionPlan(result.data);
188298
+ if (plan.project_ref !== ref || plan.application_id !== id || plan.environment_id !== environmentId || plan.source.project_ref !== sourceRef || plan.source.environment_id !== sourceEnvironmentId || plan.source.release_id !== sourceReleaseId || args["configuration_id"] !== undefined && plan.target.configuration_id !== args["configuration_id"]) {
188299
+ throw new Error;
188300
+ }
188301
+ return releaseControlSuccess(operation, { ...identity, plan });
188302
+ } catch {
188303
+ return releaseControlFailure(operation, "INVALID_RESPONSE", result.status, identity);
188304
+ }
188305
+ }
188306
+ if (action === "get_release_transfer_plan" || action === "transfer_release") {
188307
+ return applicationReleaseTransfer(http, {
188308
+ action,
188309
+ ref,
188310
+ id,
188311
+ sourceRef: text(args, "source_ref"),
188312
+ sourceReleaseId: text(args, "source_release_id")
188313
+ }, project);
188314
+ }
188315
+ if (action === "get_deploy_plan") {
188316
+ const observed = await readDeployPlan(http, args, project);
188317
+ return observed.failure ?? releaseControlSuccess(operation, { ...observed.identity, plan: observed.plan });
188318
+ }
188319
+ if (action === "deploy_release")
188320
+ return deployAction(http, args, project);
187809
188321
  if (action === "rollback_release" || action === "get_rollback_snapshot") {
187810
188322
  return rollbackAction(http, args, project);
187811
188323
  }
188324
+ if (action === "get_history")
188325
+ return historyAction(http, args, project);
187812
188326
  if (APPLICATION_PREVIEW_ACTIONS.some((value) => value === action)) {
187813
188327
  return applicationPreviewAction(http, args, project);
187814
188328
  }
@@ -194052,11 +194566,17 @@ async function applyScaffoldWrites(plan) {
194052
194566
  // src/shared/tools/app-tools.ts
194053
194567
  var REMOTE_APP_ACTIONS = {
194054
194568
  upload: "upload_release",
194569
+ "transfer-plan": "get_release_transfer_plan",
194570
+ "promote-plan": "get_promotion_plan",
194571
+ transfer: "transfer_release",
194055
194572
  configure: "put_configuration",
194056
- deploy: "activate_release",
194573
+ deploy: "deploy_release",
194574
+ "deploy-plan": "get_deploy_plan",
194575
+ diff: "get_deploy_plan",
194057
194576
  status: "get_runtime",
194058
194577
  rollback: "rollback_release",
194059
194578
  "rollback-plan": "get_rollback_snapshot",
194579
+ history: "get_history",
194060
194580
  reconcile: "reconcile_activation",
194061
194581
  retire: "retire_activation",
194062
194582
  logs: "logs",
@@ -194067,22 +194587,27 @@ var REMOTE_APP_ACTIONS = {
194067
194587
  "preview-cleanup": "cleanup_preview"
194068
194588
  };
194069
194589
  var REMOTE_APP_DESCRIPTIONS = {
194070
- ref: "[upload/configure/deploy/status/rollback/rollback-plan/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Project ref (defaults to context)",
194071
- id: "[upload/configure/deploy/status/rollback/rollback-plan/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Application ID",
194072
- environment_id: "[configure/deploy/status/rollback/rollback-plan/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Environment ID",
194073
- configuration_id: "[deploy/rollback/preview] Required for deploy/preview/explicit rollback; platform selects for default rollback",
194074
- activation_id: "[deploy/rollback/reconcile/retire] Required explicit activation ID; generated for rollback if omitted",
194075
- expected_activation_id: "[deploy/rollback] Required for deploy/explicit rollback; platform selects current CAS for default rollback",
194590
+ ref: "[upload/configure/transfer-plan/transfer/promote-plan/deploy/deploy-plan/diff/status/rollback/rollback-plan/history/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Project ref (defaults to context)",
194591
+ id: "[upload/configure/transfer-plan/transfer/promote-plan/deploy/deploy-plan/diff/status/rollback/rollback-plan/history/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Application ID",
194592
+ environment_id: "[configure/promote-plan/deploy/deploy-plan/diff/status/rollback/rollback-plan/history/reconcile/retire/preview-plan/preview/previews/preview-status/preview-cleanup] Target environment ID",
194593
+ configuration_id: "[promote-plan/deploy/deploy-plan/diff/rollback/preview] Immutable target configuration revision; required for deployment/preview; platform selects for default rollback",
194594
+ activation_id: "[deploy/rollback/reconcile/retire] Stable activation ID; auto-generated for deploy/rollback if omitted",
194595
+ expected_activation_id: "[deploy/rollback] Auto-selected from verified state; supply with activation_id for an exact retry",
194076
194596
  configuration_path: "[configure] Configuration write JSON including revision and expected revision",
194077
194597
  manifest_path: "[upload] Local delivery.manifest.json",
194078
- release_id: "[deploy/rollback/reconcile/preview-plan/preview] Required for deploy/reconcile/preview; defaults to journal-selected previous for rollback",
194598
+ release_id: "[deploy/deploy-plan/diff/rollback/reconcile/preview-plan/preview] Required for deployment/preview; defaults to journal-selected previous for rollback",
194599
+ source_ref: "[transfer-plan/transfer/promote-plan] Source project ref",
194600
+ source_release_id: "[transfer-plan/transfer/promote-plan] Source immutable release ID",
194601
+ source_environment_id: "[promote-plan] Source environment ID",
194079
194602
  preview_id: "[preview-status/preview-cleanup] Preview receipt ID",
194080
194603
  branch_ref: "[preview-plan] Proposed branch ref; preview assigns its own",
194081
194604
  branch_name: "[preview] Branch display name",
194082
194605
  data_mode: "[preview-plan/preview] Default schema_only; full_clone copies rows",
194083
194606
  ttl_seconds: "[preview-plan/preview] Lifetime from 300 to 604800 seconds; creation defaults to the platform TTL",
194084
194607
  wait: "[preview/preview-status] Wait for verified readiness of the selected preview",
194085
- timeout_seconds: "[preview/preview-status] Observation budget with --wait, from 1 to 3600 seconds (default 300)"
194608
+ timeout_seconds: "[preview/preview-status] Observation budget with --wait, from 1 to 3600 seconds (default 300)",
194609
+ cursor: "[history] Returned page cursor",
194610
+ limit: "[history] Page size, default 20 (1-100)"
194086
194611
  };
194087
194612
  var { action: _remoteAction, ...remoteFields } = APPLICATION_TOOL_SCHEMA;
194088
194613
  var REMOTE_APP_SCHEMA = Partial(_Object_(remoteFields)).properties;
@@ -194981,6 +195506,99 @@ async function runDelivery(args) {
194981
195506
  const result = await buildDeliveryProject(options, loaded.delivery);
194982
195507
  return textResult(JSON.stringify(result, null, 2), !result.ok);
194983
195508
  }
195509
+ function formatReleaseTransfer(result) {
195510
+ if (result.isError)
195511
+ return result;
195512
+ try {
195513
+ const payload = JSON.parse(result.content[0]?.text ?? "");
195514
+ if (!payload || typeof payload !== "object" || !("ok" in payload) || payload.ok !== true)
195515
+ return result;
195516
+ const plan = "plan" in payload ? parseApplicationReleaseTransferPlan(payload.plan) : null;
195517
+ const receipt = !plan && "transfer" in payload ? parseApplicationReleaseTransferResult(payload.transfer) : null;
195518
+ const data = plan ?? receipt;
195519
+ if (!data)
195520
+ return result;
195521
+ return textResult([
195522
+ `${data.project_ref}/${data.application_id}: ${plan ? plan.action === "no-op" ? "No changes" : "Transfer required" : "Artifact transferred"}`,
195523
+ `Source: ${data.source.project_ref} / ${data.source.release_id}`,
195524
+ `Target release: ${data.candidate_release_id}`,
195525
+ `Manifest: ${data.source.manifest_sha256}`,
195526
+ "Activation: not performed"
195527
+ ].join(`
195528
+ `));
195529
+ } catch {
195530
+ return result;
195531
+ }
195532
+ }
195533
+ var historyReceiptSchema = _Object_({
195534
+ schema: Literal(RELEASE_CONTROL_RESPONSE_SCHEMA),
195535
+ ok: Literal(true),
195536
+ operation: Literal("applications.get_history"),
195537
+ project_ref: String2(),
195538
+ application_id: String2(),
195539
+ environment_id: String2(),
195540
+ history: ApplicationActivationHistorySchema
195541
+ }, { additionalProperties: false });
195542
+ function historyText(result, request, projectRef) {
195543
+ if (result.isError)
195544
+ return result;
195545
+ try {
195546
+ if (result.content.length !== 1 || result.content[0].text.length > 262144)
195547
+ throw new Error;
195548
+ const receipt = JSON.parse(result.content[0].text);
195549
+ if (!Check2(historyReceiptSchema, receipt))
195550
+ throw new Error;
195551
+ const history = parseApplicationActivationHistory(receipt.history);
195552
+ if (history.project_ref !== projectRef || history.application_id !== request.id || history.environment_id !== request.environment_id || receipt.project_ref !== history.project_ref || receipt.application_id !== history.application_id || receipt.environment_id !== history.environment_id)
195553
+ throw new Error;
195554
+ const lines = [
195555
+ `Activation History: ${history.project_ref}/${history.application_id}/${history.environment_id}`,
195556
+ `Active activation: ${history.active_activation_id ?? "none"}`,
195557
+ ""
195558
+ ];
195559
+ if (history.activations.length === 0)
195560
+ lines.push("No successful activations on this page.");
195561
+ else {
195562
+ lines.push(`${"Completed (UTC)".padEnd(29)} ${"State".padEnd(7)} ${"Activation ID".padEnd(36)} Release (12)`);
195563
+ for (const entry of history.activations)
195564
+ lines.push(`${entry.completed_at.padEnd(29)} ${(entry.is_active ? "current" : "-").padEnd(7)} ${entry.activation_id} ${entry.release_id.slice(0, 12)}`);
195565
+ }
195566
+ if (history.next_cursor)
195567
+ lines.push("", `Next cursor: ${history.next_cursor}`);
195568
+ return textResult(lines.join(`
195569
+ `));
195570
+ } catch {
195571
+ return releaseControlFailure("applications.get_history", "INVALID_RESPONSE", null);
195572
+ }
195573
+ }
195574
+ function formatRemoteDeployPlan(result) {
195575
+ if (result.isError)
195576
+ return result;
195577
+ try {
195578
+ const payload = JSON.parse(result.content[0]?.text ?? "");
195579
+ if (!payload || typeof payload !== "object" || !("ok" in payload) || payload.ok !== true || !("plan" in payload))
195580
+ return result;
195581
+ const plan = parseApplicationDeployPlan(payload.plan);
195582
+ const names = (values, prefix) => values.map((name) => `${prefix}${name}`);
195583
+ const targets = [
195584
+ ...names(plan.changes.targets.added, "+"),
195585
+ ...names(plan.changes.targets.removed, "-"),
195586
+ ...names(plan.changes.targets.changed, "~")
195587
+ ];
195588
+ return textResult([
195589
+ `${plan.project_ref}/${plan.application_id} [${plan.environment_id}]: ${plan.action === "no-op" ? "No changes" : "Activation required"}`,
195590
+ `Release: ${plan.candidate.release_id} (${plan.changes.release ? "changed" : "unchanged"})`,
195591
+ `Configuration: ${plan.candidate.configuration_id} (${plan.changes.configuration ? "changed" : "unchanged"})`,
195592
+ `Targets: ${targets.length ? targets.join(", ") : "unchanged"}`,
195593
+ `Migrations: ${!plan.migrations.ledger_compatible ? "ledger conflict" : plan.migrations.project_migrations_applied ? "applied" : "pending"}`,
195594
+ `Provisioning: ${plan.migrations.operator_provisioning}`,
195595
+ `Expected activation: ${plan.expected_activation_id ?? "absent"}`
195596
+ ].join(`
195597
+ `));
195598
+ } catch {
195599
+ return result;
195600
+ }
195601
+ }
194984
195602
  async function runAppTool(request, options = {}) {
194985
195603
  if (request.dry_run !== undefined && request["dry-run"] !== undefined || request.register_in !== undefined && request["register-in"] !== undefined || request.database_url !== undefined && request["database-url"] !== undefined) {
194986
195604
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "Do not combine hyphenated and underscored aliases of the same flag");
@@ -194997,18 +195615,45 @@ async function runAppTool(request, options = {}) {
194997
195615
  if (request.database_url !== undefined && request.action !== "dev" && request.action !== "watch") {
194998
195616
  throw new ScaffoldError("SCAFFOLD_OPTION_INVALID", "--database-url applies only to app dev --profile integration");
194999
195617
  }
195618
+ if (request.json !== undefined && request.action !== "history" && request.action !== "transfer-plan" && request.action !== "transfer" && request.action !== "promote-plan") {
195619
+ throw new Error("--json applies only to app history, transfer-plan, transfer or promote-plan");
195620
+ }
195621
+ if (request.json !== undefined && request.format === "text")
195622
+ throw new Error("--json and --format text cannot be combined");
195000
195623
  if (Object.hasOwn(REMOTE_APP_ACTIONS, request.action)) {
195001
195624
  const delegate = options.getApplications?.();
195002
195625
  if (!delegate)
195003
195626
  return textResult("App remote actions require a Management API context.", true);
195004
195627
  const action = REMOTE_APP_ACTIONS[request.action];
195628
+ const { format, json, ...remoteRequest } = request;
195005
195629
  const args = {
195006
- ...request,
195630
+ ...remoteRequest,
195007
195631
  action,
195008
195632
  ref: request.ref ?? options.projectRef
195009
195633
  };
195010
195634
  validateToolArguments(APPLICATION_TOOL_SCHEMA, args);
195011
- return delegate(args);
195635
+ const result = await delegate(args);
195636
+ if (request.action === "history" && format !== "json" && json !== true) {
195637
+ return historyText(result, request, args.ref);
195638
+ }
195639
+ if ((request.action === "deploy-plan" || request.action === "diff") && format !== "json") {
195640
+ return formatRemoteDeployPlan(result);
195641
+ }
195642
+ if (request.action === "promote-plan" && !result.isError && format !== "json" && !json) {
195643
+ const payload = JSON.parse(result.content[0]?.text ?? "");
195644
+ if (!payload || typeof payload !== "object" || !("plan" in payload))
195645
+ return result;
195646
+ const plan = parseApplicationPromotionPlan(payload.plan);
195647
+ return textResult([
195648
+ `${plan.project_ref}/${plan.application_id}/${plan.environment_id}: ${plan.action}`,
195649
+ `Source: ${plan.source.project_ref}/${plan.source.environment_id}`,
195650
+ ...plan.blockers.length ? [`Blocked: ${plan.blockers.join(", ")}`] : [],
195651
+ ...plan.steps.length ? [`Next: ${plan.steps.join(" -> ")}`] : [],
195652
+ "Execution: not performed"
195653
+ ].join(`
195654
+ `));
195655
+ }
195656
+ return (request.action === "transfer-plan" || request.action === "transfer") && format !== "json" && !json ? formatReleaseTransfer(result) : result;
195012
195657
  }
195013
195658
  switch (request.action) {
195014
195659
  case "verify-plan": {
@@ -195082,10 +195727,16 @@ function registerAppTools(server2, options = {}) {
195082
195727
  "build",
195083
195728
  "upload",
195084
195729
  "configure",
195730
+ "transfer-plan",
195731
+ "transfer",
195732
+ "promote-plan",
195085
195733
  "deploy",
195734
+ "deploy-plan",
195735
+ "diff",
195086
195736
  "status",
195087
195737
  "rollback",
195088
195738
  "rollback-plan",
195739
+ "history",
195089
195740
  "reconcile",
195090
195741
  "retire",
195091
195742
  "logs",
@@ -195094,7 +195745,7 @@ function registerAppTools(server2, options = {}) {
195094
195745
  "previews",
195095
195746
  "preview-status",
195096
195747
  "preview-cleanup"
195097
- ]), "App action; upload/configure only prepare, rollback activates the journal-selected previous release without schema downgrade"),
195748
+ ]), "App action; transfer reuses a verified release without build or activation; local plan is topology-only, deploy-plan/diff observe remote state, deploy skips verified no-op, rollback never downgrades schema"),
195098
195749
  kind: optional(stringEnum(["module", "command", "query", "controller", "job", "contract", "resource"]), "[generate] Scaffold kind"),
195099
195750
  template: optional(stringEnum(["minimal", "http", "command", "edge"]), "[init] Minimal application by default; explicit http/command/edge recipes"),
195100
195751
  name: optional(String2(), "[init/generate] Project or object name"),
@@ -195109,7 +195760,8 @@ function registerAppTools(server2, options = {}) {
195109
195760
  include: optional(String2(), "[dev/compile/check] Comma-separated glob patterns for source files"),
195110
195761
  out_dir: optional(String2(), "[dev/compile/plan/build/export-tools] Output directory (default: configured outDir)"),
195111
195762
  strict: optional(Boolean2(), "[dev/compile/check] Promote warnings to errors"),
195112
- format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/graph/export-tools] Output format (default: text)"),
195763
+ format: optional(stringEnum(["text", "json"]), "[dev/generate/compile/check/plan/deploy-plan/diff/history/promote-plan/graph/export-tools] Output format (default: text)"),
195764
+ json: optional(Boolean2(), "[history/transfer-plan/transfer/promote-plan] Preserve or return the full machine-readable receipt"),
195113
195765
  profile: optional(stringEnum(["fast", "integration"]), "[dev] Run dev or dev:integration; integration verifies an explicit loopback database"),
195114
195766
  once: optional(Boolean2(), "[dev] Validate and report once without watching"),
195115
195767
  watch: optional(Boolean2(), "[dev] Watch for changes (default: true; --once disables)"),
@@ -196550,7 +197202,8 @@ function validProjectRef(ref) {
196550
197202
  return SAFE_PROJECT_REF.test(ref);
196551
197203
  }
196552
197204
  function backupBelongsToProject(backupId, projectRef) {
196553
- return BACKUP_ID.test(backupId) && backupId.startsWith(`logical-full_${projectRef}_`);
197205
+ const prefix = `logical-full_${projectRef}_`;
197206
+ return BACKUP_ID.test(backupId) && backupId.startsWith(prefix) && /^[a-f0-9]{32}$/.test(backupId.slice(prefix.length));
196554
197207
  }
196555
197208
  function verifiedBackup(value, projectRef) {
196556
197209
  if (!isRecord6(value) || typeof value.backup_id !== "string" || !backupBelongsToProject(value.backup_id, projectRef) || value.project_ref !== projectRef || typeof value.database !== "string" || !SAFE_DATABASE.test(value.database) || value.kind !== "logical-full" || !canonicalTimestamp4(value.created_at) || !canonicalTimestamp4(value.completed_at) || new Date(value.completed_at).valueOf() < new Date(value.created_at).valueOf() || typeof value.bytes !== "number" || !Number.isSafeInteger(value.bytes) || value.bytes <= 0 || typeof value.sha256 !== "string" || !SHA256.test(value.sha256))
@@ -196589,16 +197242,11 @@ function publicBackup(backup) {
196589
197242
  function equalBackup(left, right) {
196590
197243
  return left.backup_id === right.backup_id && left.project_ref === right.project_ref && left.database === right.database && left.kind === right.kind && left.created_at === right.created_at && left.completed_at === right.completed_at && left.bytes === right.bytes && left.sha256 === right.sha256;
196591
197244
  }
196592
- function newlyCreatedBackup(before, after) {
196593
- const afterById = new Map(after.map((backup) => [backup.backup_id, backup]));
196594
- for (const previous of before) {
196595
- const current = afterById.get(previous.backup_id);
196596
- if (!current || !equalBackup(previous, current))
196597
- return null;
197245
+ function requiredBackupId(value, projectRef) {
197246
+ if (typeof value !== "string" || !backupBelongsToProject(value, projectRef)) {
197247
+ throw new Error("'backup_id' must identify a logical-full backup for 'ref'");
196598
197248
  }
196599
- const known = new Set(before.map((backup) => backup.backup_id));
196600
- const additions = after.filter((backup) => !known.has(backup.backup_id));
196601
- return additions.length === 1 ? additions[0] : null;
197249
+ return value;
196602
197250
  }
196603
197251
  function restoreRequest(projectRef, backupId, expectedSha256, restoreConfirmation) {
196604
197252
  if (typeof backupId !== "string" || !backupBelongsToProject(backupId, projectRef)) {
@@ -196624,11 +197272,27 @@ function httpFailure(operation, response) {
196624
197272
  }
196625
197273
  return releaseControlFailure(operation, "HTTP_ERROR", response.transportError ? null : response.status);
196626
197274
  }
196627
- function mutationFailure(operation, response) {
196628
- if (response.responseReadError || response.transportError || response.status === 408 || response.status >= 500) {
196629
- return releaseControlFailure(operation, "OUTCOME_UNKNOWN", response.transportError ? null : response.status);
197275
+ function mutationOutcomeUnknown(response) {
197276
+ return Boolean(response.responseReadError || response.transportError || response.status === 408 || response.status >= 500 || response.status >= 200 && response.status < 300 && response.status !== 200);
197277
+ }
197278
+ function mutationFailure(operation, response, safeState = {}) {
197279
+ if (mutationOutcomeUnknown(response)) {
197280
+ return releaseControlFailure(operation, "OUTCOME_UNKNOWN", response.transportError ? null : response.status, safeState);
196630
197281
  }
196631
- return releaseControlFailure(operation, "HTTP_ERROR", response.status);
197282
+ return releaseControlFailure(operation, "HTTP_ERROR", response.status, safeState);
197283
+ }
197284
+ async function readBackup(http, projectRef, backupId) {
197285
+ let response;
197286
+ try {
197287
+ response = await http.get(`${endpoint(projectRef)}/database/backups/logical/${backupId}`, {
197288
+ maxJsonBytes: MUTATION_MAX_BYTES,
197289
+ responseTimeoutMs: RELEASE_READ_RESPONSE_TIMEOUT_MS
197290
+ });
197291
+ } catch {
197292
+ response = { ok: false, status: 0, data: null, transportError: true };
197293
+ }
197294
+ const candidate = response.ok && response.status === 200 && isRecord6(response.data) ? verifiedBackup(response.data.backup, projectRef) : null;
197295
+ return { response, backup: candidate?.backup_id === backupId ? candidate : null };
196632
197296
  }
196633
197297
  async function readInventory(http, projectRef) {
196634
197298
  const response = await http.get(`${endpoint(projectRef)}/database/backups/logical`, {
@@ -197041,6 +197705,7 @@ function registerReleaseTools(server2, http, options = {}) {
197041
197705
  const localActions = ["scope_inspect", "scope_rebind", "scope_create"];
197042
197706
  const remoteActions = [
197043
197707
  "logical_backup_list",
197708
+ "logical_backup_status",
197044
197709
  "logical_backup_create",
197045
197710
  "logical_backup_restore",
197046
197711
  "postgrest_status",
@@ -197063,7 +197728,7 @@ function registerReleaseTools(server2, http, options = {}) {
197063
197728
  web: optional(Boolean2(), "[scope_create] Whether web assets are included in release scope"),
197064
197729
  dry_run: optional(Boolean2(), "[scope_rebind] Perform calculation and validation without writing files"),
197065
197730
  cwd: optional(String2(), "[scope_inspect/scope_rebind/scope_create] Base directory for relative file and git resolution"),
197066
- backup_id: optional(String2(), "[logical_backup_restore] Exact verified logical-full backup ID from the selected project inventory"),
197731
+ backup_id: optional(String2(), "[logical_backup_create/status/restore] Stable project-bound backup ID; create generates one when omitted"),
197067
197732
  expected_sha256: optional(String2(), "[logical_backup_restore] Exact lowercase SHA-256 from the selected project inventory"),
197068
197733
  restore_confirmation: optional(String2(), "[logical_backup_restore] Exact RESTORE_PROJECT:<ref>:<backup_id>:<sha256> confirmation"),
197069
197734
  subject: optional(String2(), "[release_canary_fixture_stage_replay/disable_replay] Exact central subject UUID"),
@@ -197108,28 +197773,47 @@ function registerReleaseTools(server2, http, options = {}) {
197108
197773
  });
197109
197774
  }
197110
197775
  if (action === "logical_backup_create") {
197111
- const before = await readInventory(http, projectRef);
197112
- const beforeFailure = readInventoryFailure("release.logical_backup.create", before);
197113
- if (beforeFailure)
197114
- return beforeFailure;
197115
- const mutation = await http.postReleaseMutation(`${endpoint(projectRef)}/database/backups/logical`, {}, {
197116
- timeoutMs: BACKUP_TIMEOUT_MS
197117
- });
197118
- const after = await readInventory(http, projectRef);
197776
+ const backupId = requiredBackupId(backup_id ?? `logical-full_${projectRef}_${crypto.randomUUID().replaceAll("-", "")}`, projectRef);
197777
+ const state = { project_ref: projectRef, backup_id: backupId };
197778
+ let mutation;
197779
+ try {
197780
+ mutation = await http.postReleaseMutation(`${endpoint(projectRef)}/database/backups/logical`, { backup_id: backupId }, { timeoutMs: BACKUP_TIMEOUT_MS });
197781
+ } catch {
197782
+ mutation = { ok: false, status: 0, data: null, transportError: true };
197783
+ }
197119
197784
  if (!mutation.ok || mutation.status !== 200) {
197120
- return mutationFailure("release.logical_backup.create", mutation);
197785
+ if (mutationOutcomeUnknown(mutation)) {
197786
+ const observed = await readBackup(http, projectRef, backupId);
197787
+ if (observed.backup)
197788
+ return releaseControlFailure("release.logical_backup.create", "OUTCOME_UNKNOWN", mutation.transportError ? null : mutation.status, {
197789
+ ...state,
197790
+ backup: publicBackup(observed.backup),
197791
+ backup_verified: true,
197792
+ creation_confirmed: false
197793
+ });
197794
+ }
197795
+ return mutationFailure("release.logical_backup.create", mutation, state);
197121
197796
  }
197122
197797
  const responseBackup = isRecord6(mutation.data) ? verifiedBackup(mutation.data.backup, projectRef) : null;
197123
- const afterFailure = readInventoryFailure("release.logical_backup.create", after);
197124
- const addedBackup = after.inventory && newlyCreatedBackup(before.inventory, after.inventory);
197125
- if (!responseBackup || afterFailure || !addedBackup || !equalBackup(responseBackup, addedBackup)) {
197126
- return releaseControlFailure("release.logical_backup.create", "OUTCOME_UNKNOWN", mutation.status);
197798
+ const after = await readBackup(http, projectRef, backupId);
197799
+ if (!responseBackup || responseBackup.backup_id !== backupId || !after.backup || !equalBackup(responseBackup, after.backup)) {
197800
+ return releaseControlFailure("release.logical_backup.create", "OUTCOME_UNKNOWN", mutation.status, state);
197127
197801
  }
197128
197802
  return releaseControlSuccess("release.logical_backup.create", {
197129
- project_ref: projectRef,
197130
- backup: publicBackup(addedBackup)
197803
+ ...state,
197804
+ backup: publicBackup(after.backup)
197131
197805
  });
197132
197806
  }
197807
+ if (action === "logical_backup_status") {
197808
+ const backupId = requiredBackupId(backup_id, projectRef);
197809
+ const read = await readBackup(http, projectRef, backupId);
197810
+ const state = { project_ref: projectRef, backup_id: backupId };
197811
+ if (!read.response.ok || read.response.status !== 200) {
197812
+ const code = read.response.responseReadError || read.response.status >= 200 && read.response.status < 300 ? "INVALID_RESPONSE" : "HTTP_ERROR";
197813
+ return releaseControlFailure("release.logical_backup.status", code, read.response.transportError ? null : read.response.status, state);
197814
+ }
197815
+ return read.backup ? releaseControlSuccess("release.logical_backup.status", { ...state, backup: publicBackup(read.backup) }) : releaseControlFailure("release.logical_backup.status", "INVALID_RESPONSE", read.response.status, state);
197816
+ }
197133
197817
  if (action === "logical_backup_restore") {
197134
197818
  const request = restoreRequest(projectRef, backup_id, expected_sha256, restore_confirmation);
197135
197819
  const before = await readInventory(http, projectRef);
@@ -198661,7 +199345,7 @@ function registerRemoteDevTools(server2, options = {}) {
198661
199345
  // package.json
198662
199346
  var package_default = {
198663
199347
  name: "@supacloud/cli",
198664
- version: "0.79.0",
199348
+ version: "0.81.0",
198665
199349
  description: "Project-scoped CLI for SupaCloud users",
198666
199350
  type: "module",
198667
199351
  main: "./dist/index.js",
@@ -198713,14 +199397,14 @@ var package_default = {
198713
199397
  },
198714
199398
  dependencies: {
198715
199399
  "@supacloud/compiler": "^0.43.0",
198716
- "@supacloud/delivery": "0.9.0",
199400
+ "@supacloud/delivery": "0.11.0",
198717
199401
  "@supacloud/db": "0.16.0",
198718
199402
  fflate: "^0.8.3",
198719
199403
  typebox: "1.3.34"
198720
199404
  },
198721
199405
  overrides: {
198722
199406
  "@supacloud/contracts": "0.8.0",
198723
- "@supacloud/delivery": "0.9.0",
199407
+ "@supacloud/delivery": "0.11.0",
198724
199408
  "@graphql-tools/utils": "^12.0.3"
198725
199409
  },
198726
199410
  devDependencies: {
@@ -198941,6 +199625,7 @@ EXAMPLES
198941
199625
  ${preferredCommand} project logs --log_type database
198942
199626
  ${preferredCommand} project task_stats
198943
199627
  ${preferredCommand} release logical_backup_create --ref abc123
199628
+ ${preferredCommand} release logical_backup_status --ref abc123 --backup_id <backup_id>
198944
199629
  ${preferredCommand} release logical_backup_restore --ref abc123 --backup_id <backup_id> --expected_sha256 <sha256> --restore_confirmation RESTORE_PROJECT:abc123:<backup_id>:<sha256>
198945
199630
  ${preferredCommand} release postgrest_status --ref abc123
198946
199631
  ${preferredCommand} release postgrest_restart --ref abc123
@@ -198981,8 +199666,11 @@ EXAMPLES
198981
199666
  ${preferredCommand} app build --root .
198982
199667
  ${preferredCommand} app upload --ref abc123 --id orders --manifest_path generated/delivery/delivery.manifest.json
198983
199668
  ${preferredCommand} app configure --ref abc123 --id orders --environment_id test --configuration_path configuration.json
198984
- ${preferredCommand} app deploy --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid> --activation_id <uuid> --expected_activation_id absent
199669
+ ${preferredCommand} app deploy-plan --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid>
199670
+ ${preferredCommand} app diff --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid>
199671
+ ${preferredCommand} app deploy --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid>
198985
199672
  ${preferredCommand} app status --ref abc123 --id orders --environment_id test
199673
+ ${preferredCommand} --env production app promote-plan --id orders --environment_id production --source_ref staging --source_environment_id staging --source_release_id <sha256>
198986
199674
  ${preferredCommand} app preview-plan --ref abc123 --id orders --environment_id test --release_id <sha256> --branch_ref preview-orders
198987
199675
  ${preferredCommand} app preview --ref abc123 --id orders --environment_id test --release_id <sha256> --configuration_id <uuid> --ttl_seconds 3600 --wait
198988
199676
  ${preferredCommand} app previews --ref abc123 --id orders --environment_id test