@supacloud/cli 0.96.0 → 0.96.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -4
- package/dist/index.js +338 -66
- package/dist/shared/deployment-upgrade.d.ts +1 -1
- package/dist/shared/tools/deploy-tools.d.ts +1 -0
- package/dist/shared/tools/developer-experience-tools.d.ts +1 -1
- package/dist/shared/tools/frontend-release-control.d.ts +1 -0
- package/dist/tool-runtime.js +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -26,11 +26,15 @@ supacloud --env test deploy
|
|
|
26
26
|
overwriting an existing project configuration. `env list` and `env check` are
|
|
27
27
|
local-only, redact credentials, and provide stable JSON with `--json` for CI or
|
|
28
28
|
AI tooling. The real `.env.supacloud.*` files are added to `.gitignore`.
|
|
29
|
-
Fill in
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
Fill in the Management credentials and project/environment in the selected profile.
|
|
30
|
+
Static frontends need only `frontend` build configuration; no application binding
|
|
31
|
+
or backend delivery build is required. Set `SUPACLOUD_APPLICATION_ID` only for
|
|
32
|
+
executable application delivery. Upgrade the CLI with
|
|
32
33
|
`npm install -g @supacloud/cli@latest` and upgrade the SupaCloud server together.
|
|
33
34
|
`deploy` checks the server protocol before building or uploading.
|
|
35
|
+
Use `frontend.name` to select exactly one named site in each environment when
|
|
36
|
+
deployment IDs differ. A missing or ambiguous name fails before upload; it never
|
|
37
|
+
falls back to another site.
|
|
34
38
|
|
|
35
39
|
## Application Starter
|
|
36
40
|
|
|
@@ -645,7 +649,12 @@ FA-owned business features are documented in
|
|
|
645
649
|
and `--dry_run` are removed. Put build settings in `supacloud.json`; use
|
|
646
650
|
`app deploy-plan` for read-only review. Historical project-specific manifests
|
|
647
651
|
and standalone Function targets must move to application delivery configuration.
|
|
648
|
-
The CLI rejects them rather than falling back to a partial Web deployment.
|
|
652
|
+
The CLI rejects them rather than silently falling back to a partial Web deployment.
|
|
653
|
+
For an intentional Web-only release in a mixed repository, use
|
|
654
|
+
`supacloud --env test deploy --assets_only`. This preserves historical manifests,
|
|
655
|
+
Functions, schedules and migrations without invoking application compilation.
|
|
656
|
+
Static publication reuses immutable archives, pre-upload CAS, mutation receipts
|
|
657
|
+
and exact post-activation readback. It never retries a conflicting activation.
|
|
649
658
|
|
|
650
659
|
The legacy `.env` fallback is unclassified and therefore does not enable the
|
|
651
660
|
production confirmation gate. Production automation must select a `prod` or
|
package/dist/index.js
CHANGED
|
@@ -8767,7 +8767,7 @@ function outcomeUnknownGuidance(text) {
|
|
|
8767
8767
|
}
|
|
8768
8768
|
|
|
8769
8769
|
// src/shared/deployment-upgrade.ts
|
|
8770
|
-
var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment
|
|
8770
|
+
var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
|
|
8771
8771
|
var removedFrontendActions = new Set([
|
|
8772
8772
|
"deploy_git",
|
|
8773
8773
|
"deploy_upload",
|
|
@@ -10925,12 +10925,157 @@ function parseDeploymentEvidence(value) {
|
|
|
10925
10925
|
}
|
|
10926
10926
|
return structuredClone(value);
|
|
10927
10927
|
}
|
|
10928
|
-
// node_modules/@supacloud/delivery/src/
|
|
10928
|
+
// node_modules/@supacloud/delivery/src/delivery-tuple.ts
|
|
10929
|
+
var sha2563 = String2({ pattern: "^[a-f0-9]{64}$" });
|
|
10930
|
+
var commit = String2({ pattern: "^(?:[a-f0-9]{40}|[a-f0-9]{64})$" });
|
|
10931
|
+
var isoDate2 = String2({ minLength: 20, maxLength: 40 });
|
|
10932
|
+
var DELIVERY_TUPLE_SCHEMA = "supacloud.fa-delivery-tuple.v1";
|
|
10933
|
+
var FaDeliveryTupleSchema = _Object_({
|
|
10934
|
+
schema: Literal(DELIVERY_TUPLE_SCHEMA),
|
|
10935
|
+
customer: Literal("xigu-fa"),
|
|
10936
|
+
fa_commit: commit,
|
|
10937
|
+
cli: _Object_({
|
|
10938
|
+
version: String2({ pattern: "^\\d+\\.\\d+\\.\\d+$" })
|
|
10939
|
+
}, { additionalProperties: false }),
|
|
10940
|
+
platform_commit: commit,
|
|
10941
|
+
edge_runtime: _Object_({
|
|
10942
|
+
version: String2({ minLength: 1, maxLength: 128 }),
|
|
10943
|
+
artifact_sha256: sha2563
|
|
10944
|
+
}, { additionalProperties: false }),
|
|
10945
|
+
compatibility_window: _Object_({
|
|
10946
|
+
contract_schema: String2({ minLength: 1, maxLength: 128 }),
|
|
10947
|
+
starts_at: isoDate2,
|
|
10948
|
+
ends_at: isoDate2,
|
|
10949
|
+
old_client_supported: Boolean2(),
|
|
10950
|
+
partial_deployment_supported: Boolean2()
|
|
10951
|
+
}, { additionalProperties: false })
|
|
10952
|
+
}, { additionalProperties: false });
|
|
10953
|
+
// node_modules/@supacloud/delivery/src/contract-matrix.ts
|
|
10929
10954
|
var closed6 = { additionalProperties: false };
|
|
10955
|
+
var sha2564 = String2({ pattern: "^[a-f0-9]{64}$" });
|
|
10956
|
+
var generation = Union([Literal("old"), Literal("new")]);
|
|
10957
|
+
var versions = _Object_({ old: sha2564, new: sha2564 }, closed6);
|
|
10958
|
+
var CONTRACT_MATRIX_SCHEMA = "supacloud.consumer-contract-matrix.v1";
|
|
10959
|
+
var FA_CONTRACT_SCENARIOS = [
|
|
10960
|
+
"missing-display-field",
|
|
10961
|
+
"missing-authority-field",
|
|
10962
|
+
"added-field",
|
|
10963
|
+
"legacy-envelope",
|
|
10964
|
+
"lost-write-response",
|
|
10965
|
+
"downgrade"
|
|
10966
|
+
];
|
|
10967
|
+
var ConsumerContractMatrixSchema = _Object_({
|
|
10968
|
+
schema: Literal(CONTRACT_MATRIX_SCHEMA),
|
|
10969
|
+
customer: Literal("xigu-fa"),
|
|
10970
|
+
baseline_tuple_sha256: sha2564,
|
|
10971
|
+
candidate_tuple_sha256: sha2564,
|
|
10972
|
+
artifacts: _Object_({ frontend: versions, functions: versions, database: versions }, closed6),
|
|
10973
|
+
cases: _Array_(_Object_({
|
|
10974
|
+
frontend: generation,
|
|
10975
|
+
functions: generation,
|
|
10976
|
+
database: generation,
|
|
10977
|
+
scenarios: _Array_(_Object_({
|
|
10978
|
+
name: Enum(FA_CONTRACT_SCENARIOS),
|
|
10979
|
+
expected: Union([Literal("compatible"), Literal("blocked-safely")])
|
|
10980
|
+
}, closed6), { minItems: FA_CONTRACT_SCENARIOS.length, maxItems: FA_CONTRACT_SCENARIOS.length })
|
|
10981
|
+
}, closed6), { minItems: 8, maxItems: 8 })
|
|
10982
|
+
}, closed6);
|
|
10983
|
+
// node_modules/@supacloud/delivery/src/fa-stability.ts
|
|
10984
|
+
var closed7 = { additionalProperties: false };
|
|
10985
|
+
var hash3 = String2({ pattern: "^[a-f0-9]{64}$" });
|
|
10986
|
+
var label = String2({ minLength: 1, maxLength: 256, pattern: "\\S" });
|
|
10987
|
+
var timestamp2 = String2({ minLength: 24, maxLength: 24 });
|
|
10988
|
+
var count = Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER });
|
|
10989
|
+
var environment2 = Union([Literal("test"), Literal("production")]);
|
|
10990
|
+
var FA_REQUIRED_ACCEPTANCE = {
|
|
10991
|
+
login: "real-browser",
|
|
10992
|
+
permissions: "real-http",
|
|
10993
|
+
upload: "real-http",
|
|
10994
|
+
"async-task": "real-worker",
|
|
10995
|
+
deploy: "real-http",
|
|
10996
|
+
"database-migration": "real-database",
|
|
10997
|
+
schedule: "real-worker",
|
|
10998
|
+
rollback: "real-drill",
|
|
10999
|
+
"error-policy": "real-http",
|
|
11000
|
+
"alert-delivery": "real-drill"
|
|
11001
|
+
};
|
|
11002
|
+
var FA_BUSINESS_OPERATIONS = ["login", "permissions", "upload", "async-task", "report", "deploy"];
|
|
11003
|
+
var operation = Enum(FA_BUSINESS_OPERATIONS);
|
|
11004
|
+
var proof = _Object_({
|
|
11005
|
+
path: String2({ pattern: "^[A-Za-z0-9_-][A-Za-z0-9_./-]{0,255}$" }),
|
|
11006
|
+
sha256: hash3
|
|
11007
|
+
}, closed7);
|
|
11008
|
+
var FaBusinessObservationSchema = _Object_({
|
|
11009
|
+
id: String2({ pattern: "^[A-Za-z0-9_-]{1,128}$" }),
|
|
11010
|
+
tuple_sha256: hash3,
|
|
11011
|
+
operation,
|
|
11012
|
+
started_at: timestamp2,
|
|
11013
|
+
finished_at: timestamp2,
|
|
11014
|
+
outcome: Enum(["success", "failure", "timeout", "unknown"]),
|
|
11015
|
+
attempts: Integer({ minimum: 1, maximum: 1000 }),
|
|
11016
|
+
rollbacks: count
|
|
11017
|
+
}, closed7);
|
|
11018
|
+
var FaServiceObjectivesSchema = _Object_({
|
|
11019
|
+
status: Literal("approved"),
|
|
11020
|
+
owner: label,
|
|
11021
|
+
approval_reference: label,
|
|
11022
|
+
approved_at: timestamp2,
|
|
11023
|
+
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
11024
|
+
environment: environment2,
|
|
11025
|
+
alert_route: label,
|
|
11026
|
+
window_hours: Number2({ exclusiveMinimum: 0, maximum: 8760 }),
|
|
11027
|
+
max_evidence_age_hours: Number2({ exclusiveMinimum: 0, maximum: 168 }),
|
|
11028
|
+
operations: _Array_(_Object_({
|
|
11029
|
+
operation,
|
|
11030
|
+
minimum_samples: Integer({ minimum: 1, maximum: Number.MAX_SAFE_INTEGER }),
|
|
11031
|
+
availability_percent: Number2({ exclusiveMinimum: 0, maximum: 100 }),
|
|
11032
|
+
p95_ms: Number2({ exclusiveMinimum: 0, maximum: Number.MAX_SAFE_INTEGER })
|
|
11033
|
+
}, closed7), { minItems: FA_BUSINESS_OPERATIONS.length, maxItems: FA_BUSINESS_OPERATIONS.length })
|
|
11034
|
+
}, closed7);
|
|
11035
|
+
var FaStabilityEvidenceSchema = _Object_({
|
|
11036
|
+
schema: Literal("supacloud.fa-stability-evidence.v1"),
|
|
11037
|
+
environment: environment2,
|
|
11038
|
+
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
11039
|
+
tuple_sha256: hash3,
|
|
11040
|
+
matrix_sha256: hash3,
|
|
11041
|
+
objectives_sha256: hash3,
|
|
11042
|
+
recorded_at: timestamp2,
|
|
11043
|
+
window_start: timestamp2,
|
|
11044
|
+
window_end: timestamp2,
|
|
11045
|
+
reviewed_by: label,
|
|
11046
|
+
review_reference: label,
|
|
11047
|
+
acceptance: _Array_(_Object_({
|
|
11048
|
+
id: Enum(Object.keys(FA_REQUIRED_ACCEPTANCE)),
|
|
11049
|
+
execution: Enum([
|
|
11050
|
+
"real-browser",
|
|
11051
|
+
"real-http",
|
|
11052
|
+
"real-worker",
|
|
11053
|
+
"real-database",
|
|
11054
|
+
"real-drill",
|
|
11055
|
+
"local-fake"
|
|
11056
|
+
]),
|
|
11057
|
+
passed: Boolean2(),
|
|
11058
|
+
measured_at: timestamp2,
|
|
11059
|
+
proof
|
|
11060
|
+
}, closed7), { minItems: 10, maxItems: 10 }),
|
|
11061
|
+
matrix: _Array_(_Object_({
|
|
11062
|
+
combination: label,
|
|
11063
|
+
scenario: label,
|
|
11064
|
+
outcome: Union([Literal("compatible"), Literal("blocked-safely")]),
|
|
11065
|
+
execution: Union([Literal("real-http-and-database"), Literal("local-fake")]),
|
|
11066
|
+
passed: Boolean2(),
|
|
11067
|
+
measured_at: timestamp2,
|
|
11068
|
+
proof
|
|
11069
|
+
}, closed7), { minItems: 48, maxItems: 48 }),
|
|
11070
|
+
observation: proof,
|
|
11071
|
+
alert: _Object_({ route: label, acknowledged_by: label, delivered_at: timestamp2 }, closed7)
|
|
11072
|
+
}, closed7);
|
|
11073
|
+
// node_modules/@supacloud/delivery/src/application-promotion.ts
|
|
11074
|
+
var closed8 = { additionalProperties: false };
|
|
10930
11075
|
var projectRef2 = String2({ pattern: "^[a-z0-9-]{1,20}$" });
|
|
10931
|
-
var
|
|
11076
|
+
var sha2565 = ApplicationReleaseIdSchema;
|
|
10932
11077
|
var nullableActivation2 = Union([ApplicationActivationIdSchema, Null()]);
|
|
10933
|
-
var nullableDigest = Union([
|
|
11078
|
+
var nullableDigest = Union([sha2565, Null()]);
|
|
10934
11079
|
var observation = {
|
|
10935
11080
|
activation_id: nullableActivation2,
|
|
10936
11081
|
receipt_confirmed: Boolean2(),
|
|
@@ -10956,33 +11101,33 @@ var ApplicationPromotionPlanSchema = _Object_({
|
|
|
10956
11101
|
project_ref: projectRef2,
|
|
10957
11102
|
application_id: ApplicationIdSchema,
|
|
10958
11103
|
environment_id: ApplicationIdSchema,
|
|
10959
|
-
manifest_sha256:
|
|
10960
|
-
plan_sha256:
|
|
11104
|
+
manifest_sha256: sha2565,
|
|
11105
|
+
plan_sha256: sha2565,
|
|
10961
11106
|
source: _Object_({
|
|
10962
11107
|
project_ref: projectRef2,
|
|
10963
11108
|
environment_id: ApplicationIdSchema,
|
|
10964
|
-
release_id:
|
|
11109
|
+
release_id: sha2565,
|
|
10965
11110
|
...observation
|
|
10966
|
-
},
|
|
11111
|
+
}, closed8),
|
|
10967
11112
|
target: _Object_({
|
|
10968
|
-
candidate_release_id:
|
|
10969
|
-
current_release_id: Union([
|
|
11113
|
+
candidate_release_id: sha2565,
|
|
11114
|
+
current_release_id: Union([sha2565, Null()]),
|
|
10970
11115
|
artifact_action: Union([Literal("materialize"), Literal("reuse")]),
|
|
10971
11116
|
configuration_id: Union([ApplicationConfigurationIdSchema, Null()]),
|
|
10972
11117
|
configuration: Union([ApplicationConfigurationViewSchema, Null()]),
|
|
10973
11118
|
...observation
|
|
10974
|
-
},
|
|
11119
|
+
}, closed8),
|
|
10975
11120
|
migrations: _Object_({
|
|
10976
|
-
ledger_digest:
|
|
11121
|
+
ledger_digest: sha2565,
|
|
10977
11122
|
ledger_compatible: Boolean2(),
|
|
10978
11123
|
project_migrations_applied: Boolean2(),
|
|
10979
11124
|
pending_versions: _Array_(String2({ pattern: "^\\d{1,20}$" }), { maxItems: 4096, uniqueItems: true }),
|
|
10980
11125
|
operator_provisioning_required: Boolean2()
|
|
10981
|
-
},
|
|
11126
|
+
}, closed8),
|
|
10982
11127
|
backup: _Object_({
|
|
10983
11128
|
required: Boolean2(),
|
|
10984
11129
|
confirmed: Literal(false)
|
|
10985
|
-
},
|
|
11130
|
+
}, closed8),
|
|
10986
11131
|
action: Union([Literal("promote"), Literal("no-op"), Literal("blocked")]),
|
|
10987
11132
|
blockers: _Array_(Enum([...blocker]), {
|
|
10988
11133
|
maxItems: blocker.length,
|
|
@@ -10991,7 +11136,7 @@ var ApplicationPromotionPlanSchema = _Object_({
|
|
|
10991
11136
|
steps: _Array_(String2({ minLength: 1, maxLength: 64 }), { maxItems: 8, uniqueItems: true }),
|
|
10992
11137
|
execution_performed: Literal(false),
|
|
10993
11138
|
data_recovery: Literal("separate-required")
|
|
10994
|
-
},
|
|
11139
|
+
}, closed8);
|
|
10995
11140
|
function applicationPromotionPlanDigest(value) {
|
|
10996
11141
|
return digest(canonical(value));
|
|
10997
11142
|
}
|
|
@@ -16350,6 +16495,39 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
|
|
|
16350
16495
|
}
|
|
16351
16496
|
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
|
|
16352
16497
|
}
|
|
16498
|
+
async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath) {
|
|
16499
|
+
const endpoint = releaseEndpoint(projectRef, deploymentId);
|
|
16500
|
+
const archive = await verifiedArchive(archivePath);
|
|
16501
|
+
let response;
|
|
16502
|
+
try {
|
|
16503
|
+
response = await http.postBinary(endpoint, {
|
|
16504
|
+
stream: archiveStream(archive),
|
|
16505
|
+
byteLength: archive.sizeBytes
|
|
16506
|
+
}, {
|
|
16507
|
+
contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
|
|
16508
|
+
contentLength: archive.sizeBytes,
|
|
16509
|
+
contentSha256: archive.sha256,
|
|
16510
|
+
maxJsonBytes: RESPONSE_MAX_BYTES,
|
|
16511
|
+
timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
|
|
16512
|
+
responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
|
|
16513
|
+
});
|
|
16514
|
+
} finally {
|
|
16515
|
+
await archive.handle.close();
|
|
16516
|
+
}
|
|
16517
|
+
const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
|
|
16518
|
+
if (!release) {
|
|
16519
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
|
|
16520
|
+
return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
|
|
16521
|
+
}
|
|
16522
|
+
return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
|
|
16523
|
+
}
|
|
16524
|
+
const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
|
|
16525
|
+
const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
|
|
16526
|
+
if (!verified || verified.tree_sha256 !== release.tree_sha256) {
|
|
16527
|
+
return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", readback.status);
|
|
16528
|
+
}
|
|
16529
|
+
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release: verified });
|
|
16530
|
+
}
|
|
16353
16531
|
async function uploadProjectWebRelease(http, projectRef, environmentId, deploymentId, archivePath) {
|
|
16354
16532
|
const endpoint = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/web-release?deployment_id=${encodeURIComponent(deploymentId)}`;
|
|
16355
16533
|
const archive = await verifiedArchive(archivePath);
|
|
@@ -16404,6 +16582,16 @@ async function uploadProjectWebRelease(http, projectRef, environmentId, deployme
|
|
|
16404
16582
|
await archive.handle.close();
|
|
16405
16583
|
}
|
|
16406
16584
|
}
|
|
16585
|
+
async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadStatus) {
|
|
16586
|
+
const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
|
|
16587
|
+
maxJsonBytes: RESPONSE_MAX_BYTES
|
|
16588
|
+
});
|
|
16589
|
+
const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
|
|
16590
|
+
if (!release) {
|
|
16591
|
+
return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
|
|
16592
|
+
}
|
|
16593
|
+
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
|
|
16594
|
+
}
|
|
16407
16595
|
function stableJson(candidate) {
|
|
16408
16596
|
if (candidate === null || typeof candidate !== "object")
|
|
16409
16597
|
return JSON.stringify(candidate);
|
|
@@ -16523,6 +16711,57 @@ async function getActiveFrontendRelease(http, projectRef, deploymentId) {
|
|
|
16523
16711
|
const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
|
|
16524
16712
|
return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
|
|
16525
16713
|
}
|
|
16714
|
+
async function publishFrontendRelease(http, projectRef, deploymentId, archivePath, expectedTreeSha256) {
|
|
16715
|
+
const authority = await readActiveFrontendRelease(http, projectRef, deploymentId);
|
|
16716
|
+
if ("failure" in authority)
|
|
16717
|
+
return authority.failure;
|
|
16718
|
+
const inventory = authority.inventory;
|
|
16719
|
+
const current = inventory.releases[0];
|
|
16720
|
+
if (current?.tree_sha256 === expectedTreeSha256) {
|
|
16721
|
+
return toolResponse({
|
|
16722
|
+
operation: "frontend.deploy",
|
|
16723
|
+
project_ref: projectRef,
|
|
16724
|
+
deployment_id: deploymentId,
|
|
16725
|
+
active_release_id: inventory.active_release_id,
|
|
16726
|
+
activation_id: inventory.active_activation_id,
|
|
16727
|
+
release: current,
|
|
16728
|
+
unchanged: true
|
|
16729
|
+
});
|
|
16730
|
+
}
|
|
16731
|
+
const uploaded = await uploadFrontendRelease(http, projectRef, deploymentId, archivePath);
|
|
16732
|
+
if (uploaded.isError)
|
|
16733
|
+
return uploaded;
|
|
16734
|
+
const value = JSON.parse(uploaded.content[0].text);
|
|
16735
|
+
const envelope = value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
16736
|
+
const candidate = envelope?.release;
|
|
16737
|
+
const release = candidate && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
|
|
16738
|
+
if (!release || release.tree_sha256 !== expectedTreeSha256 || typeof release.release_id !== "string" || !RELEASE_ID_PATTERN.test(release.release_id)) {
|
|
16739
|
+
return releaseFailure("frontend.deploy", "INVALID_RESPONSE", 200);
|
|
16740
|
+
}
|
|
16741
|
+
const mutationId = crypto.randomUUID();
|
|
16742
|
+
const activated = await activateFrontendRelease(http, {
|
|
16743
|
+
projectRef,
|
|
16744
|
+
deploymentId,
|
|
16745
|
+
releaseId: release.release_id,
|
|
16746
|
+
mutationId,
|
|
16747
|
+
expectedActiveReleaseId: inventory.active_release_id ?? "absent",
|
|
16748
|
+
expectedActivationId: inventory.active_activation_id ?? "absent"
|
|
16749
|
+
});
|
|
16750
|
+
const activatedPayload = JSON.parse(activated.content[0].text);
|
|
16751
|
+
const active = activatedPayload.release;
|
|
16752
|
+
const treeMismatch = !activated.isError && (!active || typeof active !== "object" || !("tree_sha256" in active) || active.tree_sha256 !== expectedTreeSha256);
|
|
16753
|
+
return {
|
|
16754
|
+
...toolResponse({
|
|
16755
|
+
...treeMismatch ? { ok: false, error: { code: "OUTCOME_UNKNOWN", http_status: 200 } } : activatedPayload,
|
|
16756
|
+
operation: "frontend.deploy",
|
|
16757
|
+
mutation_id: mutationId,
|
|
16758
|
+
target_release_id: release.release_id,
|
|
16759
|
+
previous_release_id: inventory.active_release_id,
|
|
16760
|
+
previous_activation_id: inventory.active_activation_id
|
|
16761
|
+
}),
|
|
16762
|
+
...activated.isError || treeMismatch ? { isError: true } : {}
|
|
16763
|
+
};
|
|
16764
|
+
}
|
|
16526
16765
|
async function rollbackFrontendRelease(http, projectRef, deploymentId, releaseId) {
|
|
16527
16766
|
if (releaseId !== undefined && !RELEASE_ID_PATTERN.test(releaseId)) {
|
|
16528
16767
|
throw new Error("'release_id' must be a SHA-256 digest");
|
|
@@ -17097,12 +17336,12 @@ async function fetchMutationStatus(http, ref, mutationId) {
|
|
|
17097
17336
|
}
|
|
17098
17337
|
|
|
17099
17338
|
// src/shared/tools/application-workflow-schemas.ts
|
|
17100
|
-
var
|
|
17339
|
+
var closed9 = { additionalProperties: false };
|
|
17101
17340
|
var ref5 = String2({ pattern: "^[A-Za-z0-9_-]{1,20}$" });
|
|
17102
17341
|
var uuid = ApplicationActivationIdSchema2;
|
|
17103
17342
|
var nullableUuid = Union([uuid, Null()]);
|
|
17104
17343
|
var nullableDigest2 = Union([ApplicationReleaseIdSchema2, Null()]);
|
|
17105
|
-
var
|
|
17344
|
+
var timestamp3 = String2({ pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$" });
|
|
17106
17345
|
var scope2 = { project_ref: ref5, application_id: ApplicationIdSchema2, environment_id: ApplicationIdSchema2 };
|
|
17107
17346
|
var ApplicationPromotionResultSchema = _Object_({
|
|
17108
17347
|
...scope2,
|
|
@@ -17111,7 +17350,7 @@ var ApplicationPromotionResultSchema = _Object_({
|
|
|
17111
17350
|
plan_sha256: ApplicationReleaseIdSchema2,
|
|
17112
17351
|
action: Literal("promote"),
|
|
17113
17352
|
replayed: Boolean2()
|
|
17114
|
-
},
|
|
17353
|
+
}, closed9);
|
|
17115
17354
|
var ApplicationPromotionStatusSchema = _Object_({
|
|
17116
17355
|
...scope2,
|
|
17117
17356
|
mutation: Unknown(),
|
|
@@ -17130,8 +17369,8 @@ var ApplicationPromotionStatusSchema = _Object_({
|
|
|
17130
17369
|
configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]),
|
|
17131
17370
|
backup_id: Union([String2({ pattern: "^logical-full_[a-z0-9-]{1,20}_[a-f0-9]{32}$" }), Null()]),
|
|
17132
17371
|
data_recovery: Literal("separate-required")
|
|
17133
|
-
},
|
|
17134
|
-
},
|
|
17372
|
+
}, closed9)
|
|
17373
|
+
}, closed9);
|
|
17135
17374
|
var phase = Union([Literal("pending"), Literal("ready"), Literal("failed"), Literal("cleaned")]);
|
|
17136
17375
|
var previewId = String2({ pattern: "^[a-f0-9-]{8,64}$" });
|
|
17137
17376
|
var name = String2({ minLength: 1, maxLength: 256 });
|
|
@@ -17141,7 +17380,7 @@ var ApplicationPreviewReceiptSchema2 = _Object_({
|
|
|
17141
17380
|
...scope2,
|
|
17142
17381
|
preview_id: previewId,
|
|
17143
17382
|
release_id: ApplicationReleaseIdSchema2,
|
|
17144
|
-
expires_at: Union([
|
|
17383
|
+
expires_at: Union([timestamp3, Null()]),
|
|
17145
17384
|
status: Union([
|
|
17146
17385
|
Literal("planned"),
|
|
17147
17386
|
Literal("provisioning"),
|
|
@@ -17150,35 +17389,35 @@ var ApplicationPreviewReceiptSchema2 = _Object_({
|
|
|
17150
17389
|
Literal("cleaned")
|
|
17151
17390
|
]),
|
|
17152
17391
|
resources: _Object_({
|
|
17153
|
-
build_artifact: _Object_({ status: phase, release_id: ApplicationReleaseIdSchema2 },
|
|
17392
|
+
build_artifact: _Object_({ status: phase, release_id: ApplicationReleaseIdSchema2 }, closed9),
|
|
17154
17393
|
database_branch: _Object_({
|
|
17155
17394
|
status: phase,
|
|
17156
17395
|
branch_ref: ref5,
|
|
17157
17396
|
data_mode: Union([Literal("schema_only"), Literal("full_clone")])
|
|
17158
|
-
},
|
|
17159
|
-
queue_namespace: _Object_({ status: phase, namespace: name },
|
|
17160
|
-
storage_namespace: _Object_({ status: phase, namespace: name },
|
|
17161
|
-
test_secret: _Object_({ status: phase, name, value_issued: Literal(false) },
|
|
17162
|
-
configuration_revision: _Object_({ status: phase, configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]) },
|
|
17163
|
-
application_activation: _Object_({ status: phase, activation_id: nullableUuid },
|
|
17164
|
-
smoke_test: _Object_({ status: phase, checks, passed: checks, failed: checks },
|
|
17165
|
-
},
|
|
17397
|
+
}, closed9),
|
|
17398
|
+
queue_namespace: _Object_({ status: phase, namespace: name }, closed9),
|
|
17399
|
+
storage_namespace: _Object_({ status: phase, namespace: name }, closed9),
|
|
17400
|
+
test_secret: _Object_({ status: phase, name, value_issued: Literal(false) }, closed9),
|
|
17401
|
+
configuration_revision: _Object_({ status: phase, configuration_id: Union([ApplicationConfigurationIdSchema2, Null()]) }, closed9),
|
|
17402
|
+
application_activation: _Object_({ status: phase, activation_id: nullableUuid }, closed9),
|
|
17403
|
+
smoke_test: _Object_({ status: phase, checks, passed: checks, failed: checks }, closed9)
|
|
17404
|
+
}, closed9),
|
|
17166
17405
|
cleanup: _Object_({
|
|
17167
17406
|
required: Boolean2(),
|
|
17168
17407
|
completed: Boolean2(),
|
|
17169
17408
|
error: Union([String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }), Null()])
|
|
17170
|
-
},
|
|
17409
|
+
}, closed9),
|
|
17171
17410
|
branch_name: Optional(String2({ minLength: 1, maxLength: 80 })),
|
|
17172
17411
|
queue_name: Optional(name),
|
|
17173
17412
|
test_secret_name: Optional(name),
|
|
17174
17413
|
source_configuration_id: Optional(Union([ApplicationConfigurationIdSchema2, Null()])),
|
|
17175
|
-
created_at: Optional(
|
|
17176
|
-
updated_at: Optional(
|
|
17177
|
-
},
|
|
17414
|
+
created_at: Optional(timestamp3),
|
|
17415
|
+
updated_at: Optional(timestamp3)
|
|
17416
|
+
}, closed9);
|
|
17178
17417
|
var previewListSchema = _Object_({
|
|
17179
17418
|
...scope2,
|
|
17180
17419
|
previews: _Array_(ApplicationPreviewReceiptSchema2, { maxItems: 1000 })
|
|
17181
|
-
},
|
|
17420
|
+
}, closed9);
|
|
17182
17421
|
function assertScope(value, identity) {
|
|
17183
17422
|
if (value.project_ref !== identity.project_ref || value.application_id !== identity.application_id || value.environment_id !== identity.environment_id)
|
|
17184
17423
|
throw new Error("Application workflow scope mismatch");
|
|
@@ -17372,14 +17611,14 @@ var actionFields = {
|
|
|
17372
17611
|
reconcile_preview: ["preview_id"],
|
|
17373
17612
|
cleanup_preview: ["preview_id"]
|
|
17374
17613
|
};
|
|
17375
|
-
function
|
|
17614
|
+
function timestamp4(value) {
|
|
17376
17615
|
return Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
|
|
17377
17616
|
}
|
|
17378
17617
|
function receipt(value, identity) {
|
|
17379
17618
|
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) {
|
|
17380
17619
|
throw new Error("Invalid preview receipt");
|
|
17381
17620
|
}
|
|
17382
|
-
if (value.expires_at !== undefined && value.expires_at !== null && !
|
|
17621
|
+
if (value.expires_at !== undefined && value.expires_at !== null && !timestamp4(value.expires_at) || value.created_at !== undefined && !timestamp4(value.created_at) || value.updated_at !== undefined && !timestamp4(value.updated_at) || value.expires_at !== undefined && value.expires_at !== null && value.created_at !== undefined && !Check2(ttlSecondsSchema, (Date.parse(value.expires_at) - Date.parse(value.created_at)) / 1000)) {
|
|
17383
17622
|
throw new Error("Invalid preview expiry");
|
|
17384
17623
|
}
|
|
17385
17624
|
if (value.status === "ready") {
|
|
@@ -21106,22 +21345,22 @@ var starter_metadata_default = {
|
|
|
21106
21345
|
generatedBy: "supacloud/starter-metadata-v1",
|
|
21107
21346
|
packages: {
|
|
21108
21347
|
compiler: {
|
|
21109
|
-
version: "0.46.
|
|
21348
|
+
version: "0.46.1"
|
|
21110
21349
|
},
|
|
21111
21350
|
app: {
|
|
21112
|
-
version: "0.
|
|
21351
|
+
version: "0.27.0",
|
|
21113
21352
|
dependencies: {
|
|
21114
21353
|
rxjs: "7.8.2"
|
|
21115
21354
|
}
|
|
21116
21355
|
},
|
|
21117
21356
|
elysia: {
|
|
21118
|
-
version: "0.
|
|
21357
|
+
version: "0.30.0"
|
|
21119
21358
|
},
|
|
21120
21359
|
commands: {
|
|
21121
21360
|
version: "0.9.2"
|
|
21122
21361
|
},
|
|
21123
21362
|
contracts: {
|
|
21124
|
-
version: "0.
|
|
21363
|
+
version: "0.9.0"
|
|
21125
21364
|
},
|
|
21126
21365
|
db: {
|
|
21127
21366
|
version: "0.17.0",
|
|
@@ -26168,7 +26407,7 @@ import {
|
|
|
26168
26407
|
reverseDatabase
|
|
26169
26408
|
} from "@supacloud/db";
|
|
26170
26409
|
import { parseDatabaseSourcesConfig } from "@supacloud/db/source-contracts";
|
|
26171
|
-
var
|
|
26410
|
+
var hash4 = (content) => createHash7("sha256").update(content).digest("hex");
|
|
26172
26411
|
var result = (value, isError = false) => ({
|
|
26173
26412
|
isError,
|
|
26174
26413
|
content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
|
|
@@ -26299,7 +26538,7 @@ async function initializeCandidate(stage, majorVersion = 17) {
|
|
|
26299
26538
|
await mkdir6(join14(stage, "supabase/migrations"), { recursive: true });
|
|
26300
26539
|
await mkdir6(join14(stage, "supabase/schemas"), { recursive: true });
|
|
26301
26540
|
await writeFile5(join14(stage, "supabase/config.toml"), [
|
|
26302
|
-
`project_id = "supacloud-candidate-${
|
|
26541
|
+
`project_id = "supacloud-candidate-${hash4(stage).slice(0, 12)}"`,
|
|
26303
26542
|
"[db]",
|
|
26304
26543
|
`major_version = ${majorVersion}`,
|
|
26305
26544
|
"[db.migrations]",
|
|
@@ -26427,7 +26666,7 @@ async function migrations(root, path) {
|
|
|
26427
26666
|
const files = [];
|
|
26428
26667
|
for (const file of names) {
|
|
26429
26668
|
const text = await readFile5(await projectPath2(root, `${path}/${file}`), "utf8");
|
|
26430
|
-
files.push({ file, text, sha256:
|
|
26669
|
+
files.push({ file, text, sha256: hash4(text) });
|
|
26431
26670
|
}
|
|
26432
26671
|
return { dir, files };
|
|
26433
26672
|
}
|
|
@@ -26457,7 +26696,7 @@ async function migrationAction(args, root, options) {
|
|
|
26457
26696
|
files: input.files.map(({ file, sha256 }) => ({ file, sha256 })),
|
|
26458
26697
|
dryRun
|
|
26459
26698
|
};
|
|
26460
|
-
const digest =
|
|
26699
|
+
const digest = hash4(JSON.stringify(report));
|
|
26461
26700
|
if (dryRun.isError)
|
|
26462
26701
|
return result({ ...report, ok: false, digest, executionPerformed: false }, true);
|
|
26463
26702
|
if (args.action === "plan")
|
|
@@ -28074,7 +28313,7 @@ async function requireProjectDeploymentProtocol(http, projectRef, environmentId)
|
|
|
28074
28313
|
throw new Error("DEPLOYMENT_PROTOCOL_MISMATCH: Upgrade the SupaCloud server and CLI together (`npm install -g @supacloud/cli@latest`), then retry `supacloud deploy`. No upload or deployment was attempted; legacy endpoints will not be used.");
|
|
28075
28314
|
}
|
|
28076
28315
|
}
|
|
28077
|
-
var
|
|
28316
|
+
var operation2 = "applications.project_deploy";
|
|
28078
28317
|
var scopeSchema = _Object_({
|
|
28079
28318
|
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
28080
28319
|
application_id: ApplicationIdSchema,
|
|
@@ -28123,7 +28362,7 @@ async function runProjectDeployment(http, args) {
|
|
|
28123
28362
|
...args.web_release === undefined ? {} : { web_release: args.web_release }
|
|
28124
28363
|
};
|
|
28125
28364
|
if (!Check2(scopeSchema, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
|
|
28126
|
-
return releaseControlFailure(
|
|
28365
|
+
return releaseControlFailure(operation2, "INVALID_RESPONSE", null);
|
|
28127
28366
|
}
|
|
28128
28367
|
const expected = { ...scope, request };
|
|
28129
28368
|
const identity = {
|
|
@@ -28141,13 +28380,13 @@ async function runProjectDeployment(http, args) {
|
|
|
28141
28380
|
}, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
|
|
28142
28381
|
if (result.ok && result.status === 200) {
|
|
28143
28382
|
try {
|
|
28144
|
-
return releaseControlSuccess(
|
|
28383
|
+
return releaseControlSuccess(operation2, {
|
|
28145
28384
|
...responseReceipt(result.data, expected),
|
|
28146
28385
|
deployment_id: mutation_id
|
|
28147
28386
|
});
|
|
28148
28387
|
} catch {}
|
|
28149
28388
|
} else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
|
|
28150
|
-
return releaseControlMutationFailure(
|
|
28389
|
+
return releaseControlMutationFailure(operation2, result, identity);
|
|
28151
28390
|
}
|
|
28152
28391
|
const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
|
|
28153
28392
|
retry: false,
|
|
@@ -28161,14 +28400,14 @@ async function runProjectDeployment(http, args) {
|
|
|
28161
28400
|
if (state.deployment_id !== mutation_id || state.project_ref !== scope.project_ref || state.application_id !== scope.application_id || state.environment_id !== scope.environment_id || state.status !== "succeeded" || state.phase !== "verifying")
|
|
28162
28401
|
throw new Error;
|
|
28163
28402
|
const receipt = parseApplicationDeployResult(state.receipt, expected);
|
|
28164
|
-
return releaseControlSuccess(
|
|
28403
|
+
return releaseControlSuccess(operation2, {
|
|
28165
28404
|
...receipt,
|
|
28166
28405
|
deployment_id: mutation_id,
|
|
28167
28406
|
replayed: true,
|
|
28168
28407
|
execution_performed: false
|
|
28169
28408
|
});
|
|
28170
28409
|
} catch {
|
|
28171
|
-
return releaseControlFailure(
|
|
28410
|
+
return releaseControlFailure(operation2, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
|
|
28172
28411
|
}
|
|
28173
28412
|
}
|
|
28174
28413
|
|
|
@@ -28186,6 +28425,7 @@ var deployToolSchema = {
|
|
|
28186
28425
|
ref: optional(String2(), "Project ref (defaults to the linked project)"),
|
|
28187
28426
|
cwd: optional(String2(), "Project directory (default: current directory)"),
|
|
28188
28427
|
skip_build: optional(Boolean2(), "Use an existing output directory without building"),
|
|
28428
|
+
assets_only: optional(Boolean2(), "Publish only configured static assets; leave backend Functions, schedules and migrations unchanged"),
|
|
28189
28429
|
json: optional(Boolean2(), "Print only the final JSON result")
|
|
28190
28430
|
};
|
|
28191
28431
|
function record4(candidate) {
|
|
@@ -28280,6 +28520,7 @@ function deployTargetConfig(candidate, name) {
|
|
|
28280
28520
|
type: value.type,
|
|
28281
28521
|
root: optionalText(value.root, `targets.${name}.root`),
|
|
28282
28522
|
id: optionalText(value.id, `targets.${name}.id`),
|
|
28523
|
+
name: optionalText(value.name, `targets.${name}.name`),
|
|
28283
28524
|
slug: optionalText(value.slug, `targets.${name}.slug`),
|
|
28284
28525
|
buildCommand: optionalText(value.buildCommand, `targets.${name}.buildCommand`),
|
|
28285
28526
|
outputDirectory: optionalText(value.outputDirectory, `targets.${name}.outputDirectory`),
|
|
@@ -28330,6 +28571,7 @@ async function readDeployConfig(configRoot) {
|
|
|
28330
28571
|
targets: targetValues ? Object.fromEntries(Object.entries(targetValues).map(([name, value]) => [name, deployTargetConfig(value, name)])) : undefined,
|
|
28331
28572
|
frontend: frontend ? {
|
|
28332
28573
|
id: optionalText(frontend.id, "frontend.id"),
|
|
28574
|
+
name: optionalText(frontend.name, "frontend.name"),
|
|
28333
28575
|
root: optionalText(frontend.root, "frontend.root"),
|
|
28334
28576
|
buildCommand: optionalText(frontend.buildCommand, "frontend.buildCommand"),
|
|
28335
28577
|
outputDirectory: optionalText(frontend.outputDirectory, "frontend.outputDirectory"),
|
|
@@ -28392,13 +28634,22 @@ function deploymentList(candidate) {
|
|
|
28392
28634
|
throw new Error("Invalid frontend deployment list response");
|
|
28393
28635
|
return values.map(frontendDeployment);
|
|
28394
28636
|
}
|
|
28395
|
-
function selectDeployment(deployments, requestedId, projectName) {
|
|
28637
|
+
function selectDeployment(deployments, requestedId, projectName, requestedName) {
|
|
28396
28638
|
if (requestedId) {
|
|
28397
28639
|
const selected = deployments.find((deployment) => deployment.id === requestedId);
|
|
28398
28640
|
if (!selected)
|
|
28399
28641
|
throw new Error(`Frontend deployment '${requestedId}' was not found`);
|
|
28642
|
+
if (requestedName && selected.name !== requestedName) {
|
|
28643
|
+
throw new Error(`Frontend deployment '${requestedId}' does not match name '${requestedName}'`);
|
|
28644
|
+
}
|
|
28400
28645
|
return selected;
|
|
28401
28646
|
}
|
|
28647
|
+
if (requestedName) {
|
|
28648
|
+
const matches = deployments.filter((deployment) => deployment.name === requestedName);
|
|
28649
|
+
if (matches.length !== 1)
|
|
28650
|
+
throw new Error(`Expected exactly one frontend deployment named '${requestedName}'`);
|
|
28651
|
+
return matches[0];
|
|
28652
|
+
}
|
|
28402
28653
|
if (deployments.length === 1)
|
|
28403
28654
|
return deployments[0];
|
|
28404
28655
|
if (projectName) {
|
|
@@ -28416,6 +28667,7 @@ function selectFrontendTarget(configRoot, config) {
|
|
|
28416
28667
|
type: "frontend",
|
|
28417
28668
|
root: config.frontend?.root,
|
|
28418
28669
|
id: config.frontend?.id,
|
|
28670
|
+
name: config.frontend?.name,
|
|
28419
28671
|
buildCommand: config.frontend?.buildCommand,
|
|
28420
28672
|
outputDirectory: config.frontend?.outputDirectory,
|
|
28421
28673
|
buildEnv: config.frontend?.buildEnv
|
|
@@ -28580,7 +28832,7 @@ function payload(response) {
|
|
|
28580
28832
|
throw new Error("Deployment operation returned an invalid response");
|
|
28581
28833
|
return parsed;
|
|
28582
28834
|
}
|
|
28583
|
-
async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables) {
|
|
28835
|
+
async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables, assetsOnly = false) {
|
|
28584
28836
|
const target = selectFrontendTarget(configRoot, await readDeployConfig(configRoot));
|
|
28585
28837
|
if (!target)
|
|
28586
28838
|
return null;
|
|
@@ -28593,7 +28845,7 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
|
|
|
28593
28845
|
const listResponse = await http.get(`/v1/projects/${encodeURIComponent(projectRef)}/frontend/deployments`);
|
|
28594
28846
|
if (!listResponse.ok)
|
|
28595
28847
|
throw new Error(`Failed to list frontend deployments (HTTP ${listResponse.status})`);
|
|
28596
|
-
const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory));
|
|
28848
|
+
const selected = selectDeployment(deploymentList(listResponse.data), requestedId, await packageName(projectDirectory), target.config.name);
|
|
28597
28849
|
const configuredBuildCommand = String(target.config.buildCommand || selected.buildCommand || "").trim();
|
|
28598
28850
|
const buildCommand = configuredBuildCommand || (skipBuild ? "" : await defaultBuildCommand(projectDirectory, configRoot));
|
|
28599
28851
|
const configuredOutput = String(target.config.outputDirectory || "").trim();
|
|
@@ -28606,6 +28858,9 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
|
|
|
28606
28858
|
}
|
|
28607
28859
|
const archive = await createFrontendArchive(outputDirectory);
|
|
28608
28860
|
try {
|
|
28861
|
+
if (assetsOnly) {
|
|
28862
|
+
return { result: await publishFrontendRelease(http, projectRef, selected.id, archive.archivePath, archive.treeSha256) };
|
|
28863
|
+
}
|
|
28609
28864
|
const uploaded = payload(await uploadProjectWebRelease(http, projectRef, environmentId, selected.id, archive.archivePath));
|
|
28610
28865
|
const release = record4(uploaded.release);
|
|
28611
28866
|
const releaseId = requiredString(release?.release_id, "release.release_id");
|
|
@@ -28635,7 +28890,23 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
28635
28890
|
...config.application,
|
|
28636
28891
|
environmentId: options.environment || config.application.environmentId
|
|
28637
28892
|
} : undefined;
|
|
28638
|
-
|
|
28893
|
+
const legacyManifest = await hasProjectReleaseManifest(configRoot);
|
|
28894
|
+
const assetsOnly = args.assets_only === true || !application?.id && selectFrontendTarget(configRoot, config) !== null && !legacyManifest && !Object.values(config.targets ?? {}).some((target) => target.type === "edge_function");
|
|
28895
|
+
if (assetsOnly) {
|
|
28896
|
+
if (!selectFrontendTarget(configRoot, config)) {
|
|
28897
|
+
throw new Error("Static asset deployment requires a frontend configuration in supacloud.json");
|
|
28898
|
+
}
|
|
28899
|
+
const environmentId = options.environment?.trim() || application?.environmentId?.trim();
|
|
28900
|
+
if (!environmentId || !Check2(ApplicationIdSchema, environmentId)) {
|
|
28901
|
+
throw new Error("Static asset deployment requires SUPACLOUD_ENV");
|
|
28902
|
+
}
|
|
28903
|
+
await requireProjectDeploymentProtocol(http, projectRef, environmentId);
|
|
28904
|
+
const staged = await stageApplicationWebRelease(http, projectRef, environmentId, configRoot, args.skip_build === true, args.json === true, options.environmentVariables, true);
|
|
28905
|
+
if (!staged?.result)
|
|
28906
|
+
throw new Error("Static asset deployment did not produce a receipt");
|
|
28907
|
+
return staged.result;
|
|
28908
|
+
}
|
|
28909
|
+
if (legacyManifest) {
|
|
28639
28910
|
throw new Error(`${DEPLOYMENT_UPGRADE} Replace deploy-manifest.json with the current application delivery configuration; no remote mutation was performed.`);
|
|
28640
28911
|
}
|
|
28641
28912
|
if (application?.id) {
|
|
@@ -28963,7 +29234,7 @@ var TEST_PROFILE = [
|
|
|
28963
29234
|
"SUPACLOUD_API_URL=https://management.test.example.com",
|
|
28964
29235
|
"SUPACLOUD_API_TOKEN=<test-management-api-token>",
|
|
28965
29236
|
"SUPACLOUD_PROJECT_REF=<test-project-ref>",
|
|
28966
|
-
"SUPACLOUD_APPLICATION_ID=<application-id>",
|
|
29237
|
+
"# Optional for executable application delivery: SUPACLOUD_APPLICATION_ID=<application-id>",
|
|
28967
29238
|
""
|
|
28968
29239
|
].join(`
|
|
28969
29240
|
`);
|
|
@@ -28972,7 +29243,7 @@ var PRODUCTION_PROFILE = [
|
|
|
28972
29243
|
"SUPACLOUD_API_URL=https://management.example.com",
|
|
28973
29244
|
"SUPACLOUD_API_TOKEN=<production-management-api-token>",
|
|
28974
29245
|
"SUPACLOUD_PROJECT_REF=<production-project-ref>",
|
|
28975
|
-
"SUPACLOUD_APPLICATION_ID=<application-id>",
|
|
29246
|
+
"# Optional for executable application delivery: SUPACLOUD_APPLICATION_ID=<application-id>",
|
|
28976
29247
|
""
|
|
28977
29248
|
].join(`
|
|
28978
29249
|
`);
|
|
@@ -29096,7 +29367,7 @@ async function initializeProject(request, options) {
|
|
|
29096
29367
|
},
|
|
29097
29368
|
next: [
|
|
29098
29369
|
"cp .env.supacloud.test.example .env.supacloud.test",
|
|
29099
|
-
"
|
|
29370
|
+
"Configure frontend assets; set SUPACLOUD_APPLICATION_ID only for executable application delivery.",
|
|
29100
29371
|
"supacloud env check",
|
|
29101
29372
|
"supacloud --env test deploy"
|
|
29102
29373
|
]
|
|
@@ -29144,12 +29415,12 @@ function statusMissing(context) {
|
|
|
29144
29415
|
}
|
|
29145
29416
|
return ["SUPACLOUD_API_URL", "SUPACLOUD_API_TOKEN", "SUPACLOUD_PROJECT_REF"];
|
|
29146
29417
|
}
|
|
29147
|
-
function deployMissing(context, application) {
|
|
29418
|
+
function deployMissing(context, application, hasFrontend = false) {
|
|
29148
29419
|
const missing = statusMissing(context);
|
|
29149
29420
|
if (context.credentialScope !== "management") {
|
|
29150
29421
|
return [...missing, "Management API context"];
|
|
29151
29422
|
}
|
|
29152
|
-
if (!Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
|
|
29423
|
+
if (!(hasFrontend && !context.applicationId && !application) && !Check2(ApplicationIdSchema, context.applicationId || application?.id)) {
|
|
29153
29424
|
missing.push("valid SUPACLOUD_APPLICATION_ID or supacloud.json application.id");
|
|
29154
29425
|
}
|
|
29155
29426
|
if (!Check2(ApplicationIdSchema, context.applicationEnvironmentId || application?.environmentId)) {
|
|
@@ -29169,7 +29440,8 @@ async function inspectProfile(profile) {
|
|
|
29169
29440
|
throw error;
|
|
29170
29441
|
});
|
|
29171
29442
|
const config = record5(JSON.parse(configText));
|
|
29172
|
-
const
|
|
29443
|
+
const hasFrontend = record5(config?.frontend) !== null || Object.values(record5(config?.targets) ?? {}).some((target) => record5(target)?.type === "frontend");
|
|
29444
|
+
const deploy = deployMissing(context, record5(config?.application), hasFrontend);
|
|
29173
29445
|
return {
|
|
29174
29446
|
name: profile.name,
|
|
29175
29447
|
path: profile.path,
|
|
@@ -29265,7 +29537,7 @@ function registerDeveloperExperienceTools(server, options = {}) {
|
|
|
29265
29537
|
// package.json
|
|
29266
29538
|
var package_default = {
|
|
29267
29539
|
name: "@supacloud/cli",
|
|
29268
|
-
version: "0.96.
|
|
29540
|
+
version: "0.96.2",
|
|
29269
29541
|
description: "Project-scoped CLI for SupaCloud users",
|
|
29270
29542
|
type: "module",
|
|
29271
29543
|
main: "./dist/index.js",
|
|
@@ -29317,14 +29589,14 @@ var package_default = {
|
|
|
29317
29589
|
directory: "packages/cli"
|
|
29318
29590
|
},
|
|
29319
29591
|
dependencies: {
|
|
29320
|
-
"@supacloud/compiler": "^0.46.
|
|
29321
|
-
"@supacloud/delivery": "0.
|
|
29592
|
+
"@supacloud/compiler": "^0.46.1",
|
|
29593
|
+
"@supacloud/delivery": "0.18.0",
|
|
29322
29594
|
"@supacloud/db": "0.17.0",
|
|
29323
29595
|
typebox: "1.3.36"
|
|
29324
29596
|
},
|
|
29325
29597
|
overrides: {
|
|
29326
|
-
"@supacloud/contracts": "0.
|
|
29327
|
-
"@supacloud/delivery": "0.
|
|
29598
|
+
"@supacloud/contracts": "0.9.0",
|
|
29599
|
+
"@supacloud/delivery": "0.18.0",
|
|
29328
29600
|
"@graphql-tools/utils": "^12.0.3"
|
|
29329
29601
|
},
|
|
29330
29602
|
devDependencies: {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment
|
|
1
|
+
export declare const DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
|
|
2
2
|
export declare function assertCurrentDeploymentInput(tool: string, input: unknown): void;
|
|
@@ -26,6 +26,7 @@ export declare const deployToolSchema: {
|
|
|
26
26
|
ref: Type.TOptional<Type.TString>;
|
|
27
27
|
cwd: Type.TOptional<Type.TString>;
|
|
28
28
|
skip_build: Type.TOptional<Type.TBoolean>;
|
|
29
|
+
assets_only: Type.TOptional<Type.TBoolean>;
|
|
29
30
|
json: Type.TOptional<Type.TBoolean>;
|
|
30
31
|
};
|
|
31
32
|
export declare function findDeployConfigRoot(startDirectory: string, environmentName?: string): Promise<string>;
|
|
@@ -15,7 +15,7 @@ export declare const environmentToolSchema: ToolSchema;
|
|
|
15
15
|
declare function outputDirectoryFor(manifest: PackageManifest): string;
|
|
16
16
|
declare function profileNameFromFile(name: string): string | null;
|
|
17
17
|
declare function statusMissing(context: ResolvedContext): string[];
|
|
18
|
-
declare function deployMissing(context: ResolvedContext, application?: Record<string, unknown> | null): string[];
|
|
18
|
+
declare function deployMissing(context: ResolvedContext, application?: Record<string, unknown> | null, hasFrontend?: boolean): string[];
|
|
19
19
|
export declare function registerDeveloperExperienceTools(server: ToolServer, options?: DeveloperExperienceOptions): void;
|
|
20
20
|
export declare const __internal: {
|
|
21
21
|
outputDirectoryFor: typeof outputDirectoryFor;
|
|
@@ -46,6 +46,7 @@ export declare function uploadProjectWebRelease(http: FrontendReleaseHttp, proje
|
|
|
46
46
|
export declare function uploadFrontendSource(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, archivePath: string): Promise<ToolResponse>;
|
|
47
47
|
export declare function getActiveFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string): Promise<ToolResponse>;
|
|
48
48
|
export declare function readFrontendReleaseAuthority(http: FrontendReleaseHttp, projectRef: string, deploymentId: string): Promise<ToolResponse>;
|
|
49
|
+
export declare function publishFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, archivePath: string, expectedTreeSha256: string): Promise<ToolResponse>;
|
|
49
50
|
export declare function rollbackFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, releaseId?: string): Promise<ToolResponse>;
|
|
50
51
|
export declare function activateFrontendRelease(http: FrontendReleaseHttp, input: {
|
|
51
52
|
projectRef: string;
|
package/dist/tool-runtime.js
CHANGED
|
@@ -131,7 +131,7 @@ import { Type as Type2 } from "typebox";
|
|
|
131
131
|
import { Value as Value2 } from "typebox/value";
|
|
132
132
|
|
|
133
133
|
// src/shared/deployment-upgrade.ts
|
|
134
|
-
var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment
|
|
134
|
+
var DEPLOYMENT_UPGRADE = "DEPLOYMENT_UPGRADE_REQUIRED: Legacy deployment commands are no longer supported. Upgrade with `npm install -g @supacloud/cli@latest`, configure frontend in supacloud.json for static assets, or application.id and application.environmentId for executable application delivery, then run `supacloud deploy`. Use `supacloud deploy --assets_only` to publish only Web assets in a mixed repository. SupaCloud owns activation; do not retry with legacy commands.";
|
|
135
135
|
var removedFrontendActions = new Set([
|
|
136
136
|
"deploy_git",
|
|
137
137
|
"deploy_upload",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supacloud/cli",
|
|
3
|
-
"version": "0.96.
|
|
3
|
+
"version": "0.96.2",
|
|
4
4
|
"description": "Project-scoped CLI for SupaCloud users",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,14 +52,14 @@
|
|
|
52
52
|
"directory": "packages/cli"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@supacloud/compiler": "^0.46.
|
|
56
|
-
"@supacloud/delivery": "0.
|
|
55
|
+
"@supacloud/compiler": "^0.46.1",
|
|
56
|
+
"@supacloud/delivery": "0.18.0",
|
|
57
57
|
"@supacloud/db": "0.17.0",
|
|
58
58
|
"typebox": "1.3.36"
|
|
59
59
|
},
|
|
60
60
|
"overrides": {
|
|
61
|
-
"@supacloud/contracts": "0.
|
|
62
|
-
"@supacloud/delivery": "0.
|
|
61
|
+
"@supacloud/contracts": "0.9.0",
|
|
62
|
+
"@supacloud/delivery": "0.18.0",
|
|
63
63
|
"@graphql-tools/utils": "^12.0.3"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|