@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 +761 -73
- package/dist/shared/tools/app-tools.d.ts +13 -1
- package/dist/shared/tools/application-deploy-http-status.test.d.ts +1 -0
- package/dist/shared/tools/application-history.test.d.ts +1 -0
- package/dist/shared/tools/application-promotion-help.test.d.ts +1 -0
- package/dist/shared/tools/application-promotion.test.d.ts +1 -0
- package/dist/shared/tools/application-release-transfer.d.ts +8 -0
- package/dist/shared/tools/application-schemas.d.ts +1 -0
- package/dist/shared/tools/application-tools.d.ts +5 -2
- package/dist/shared/tools/release-backup-http-status.test.d.ts +1 -0
- package/package.json +3 -3
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
|
|
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_(
|
|
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
|
|
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:
|
|
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:
|
|
181509
|
-
baselineSha256:
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
|
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 && !
|
|
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
|
|
187619
|
-
activation_id: optional(ApplicationActivationIdSchema2, "[activate_release/reconcile_activation/retire_activation/rollback_release]
|
|
187620
|
-
expected_activation_id: optional(Union([ApplicationActivationIdSchema2, Null(), Literal("absent")]), "[activate_release/rollback_release] Current activation ID, or absent for first activation; selected
|
|
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
|
-
|
|
187625
|
-
|
|
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,
|
|
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 =
|
|
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
|
|
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, ...
|
|
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: "
|
|
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]
|
|
194073
|
-
configuration_id: "[deploy/rollback/preview]
|
|
194074
|
-
activation_id: "[deploy/rollback/reconcile/retire]
|
|
194075
|
-
expected_activation_id: "[deploy/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
|
|
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
|
-
...
|
|
195630
|
+
...remoteRequest,
|
|
195007
195631
|
action,
|
|
195008
195632
|
ref: request.ref ?? options.projectRef
|
|
195009
195633
|
};
|
|
195010
195634
|
validateToolArguments(APPLICATION_TOOL_SCHEMA, args);
|
|
195011
|
-
|
|
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;
|
|
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
|
-
|
|
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
|
|
196593
|
-
|
|
196594
|
-
|
|
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
|
-
|
|
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
|
|
196628
|
-
|
|
196629
|
-
|
|
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(), "[
|
|
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
|
|
197112
|
-
const
|
|
197113
|
-
|
|
197114
|
-
|
|
197115
|
-
|
|
197116
|
-
|
|
197117
|
-
|
|
197118
|
-
|
|
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
|
-
|
|
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
|
|
197124
|
-
|
|
197125
|
-
|
|
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
|
-
|
|
197130
|
-
backup: publicBackup(
|
|
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.
|
|
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.
|
|
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.
|
|
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>
|
|
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
|