@supacloud/cli 0.98.0 → 0.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -6
- package/dist/index.js +124 -119
- package/dist/shared/deployment-upgrade.d.ts +1 -1
- package/dist/shared/tools/deploy-tools.d.ts +2 -0
- package/dist/shared/tools/frontend-release-control.d.ts +4 -1
- package/dist/shared/tools/project-deployment.d.ts +1 -0
- package/dist/tool-runtime.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -659,12 +659,19 @@ FA-owned business features are documented in
|
|
|
659
659
|
|
|
660
660
|
`deploy --target`, `--id`, `--build_command`, `--output_dir`, `--plan`, `--diff`
|
|
661
661
|
and `--dry_run` are removed. Put build settings in `supacloud.json`; use
|
|
662
|
-
`app deploy-plan` for read-only review.
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
`supacloud --env test deploy --
|
|
667
|
-
|
|
662
|
+
`app deploy-plan` for read-only review. With a frontend configured, `supacloud deploy`
|
|
663
|
+
publishes only its static assets, even in a mixed repository. `--assets_only`
|
|
664
|
+
remains an explicit alias. This preserves historical manifests, Functions,
|
|
665
|
+
Storage, schedules and migrations without invoking application compilation.
|
|
666
|
+
Use `supacloud --env test deploy --backend` to publish the configured Application
|
|
667
|
+
independently; it never builds or uploads Web. Unsupported historical backend
|
|
668
|
+
manifests and standalone Function targets still fail closed on that Application path.
|
|
669
|
+
|
|
670
|
+
Application deployments return `accepted` after durable queue insertion, not a
|
|
671
|
+
successful activation. Inspect the receipt with the read-only
|
|
672
|
+
`supacloud --env test deploy --status <deployment-id>`. Queue delivery survives
|
|
673
|
+
restart; interrupted side effects require reconciliation rather than blind retry.
|
|
674
|
+
|
|
668
675
|
Static publication reuses immutable archives, pre-upload CAS, mutation receipts
|
|
669
676
|
and exact post-activation readback. It never retries a conflicting activation.
|
|
670
677
|
|
package/dist/index.js
CHANGED
|
@@ -8786,7 +8786,7 @@ function outcomeUnknownGuidance(text) {
|
|
|
8786
8786
|
}
|
|
8787
8787
|
|
|
8788
8788
|
// src/shared/deployment-upgrade.ts
|
|
8789
|
-
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`.
|
|
8789
|
+
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`. With a frontend configured, deploy publishes only Web assets; use `supacloud deploy --backend` for the application backend. `supacloud deploy --assets_only` remains an explicit Web-only option. SupaCloud owns activation; do not retry with legacy commands.";
|
|
8790
8790
|
var removedFrontendActions = new Set([
|
|
8791
8791
|
"deploy_git",
|
|
8792
8792
|
"deploy_upload",
|
|
@@ -9339,6 +9339,8 @@ function declaredMode(moduleName, action) {
|
|
|
9339
9339
|
return;
|
|
9340
9340
|
}
|
|
9341
9341
|
function executionMode(moduleName, action, args) {
|
|
9342
|
+
if (moduleName === "deploy" && typeof args.status === "string")
|
|
9343
|
+
return "read";
|
|
9342
9344
|
if (moduleName === "deploy" && (args.dry_run === true || args.plan === true || args.diff === true))
|
|
9343
9345
|
return "read";
|
|
9344
9346
|
if (moduleName === "database" && ["push_migrations", "baseline_migrations"].includes(action) && args.dry_run === true)
|
|
@@ -16763,7 +16765,7 @@ async function getFrontendRelease(http, projectRef, deploymentId, releaseId) {
|
|
|
16763
16765
|
}
|
|
16764
16766
|
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
|
|
16765
16767
|
}
|
|
16766
|
-
async function
|
|
16768
|
+
async function uploadFrontendReleaseWithReadback(http, projectRef, deploymentId, archivePath, verifyReadback) {
|
|
16767
16769
|
const endpoint = releaseEndpoint(projectRef, deploymentId);
|
|
16768
16770
|
const archive = await verifiedArchive(archivePath);
|
|
16769
16771
|
let response;
|
|
@@ -16782,13 +16784,15 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
|
|
|
16782
16784
|
} finally {
|
|
16783
16785
|
await archive.handle.close();
|
|
16784
16786
|
}
|
|
16785
|
-
const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
|
|
16787
|
+
const release = response.ok && (response.status === 200 || response.status === 201) ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId: archive.sha256 }) : null;
|
|
16786
16788
|
if (!release) {
|
|
16787
16789
|
if (response.status >= 400 && response.status < 500 && response.status !== 408 && !response.transportError) {
|
|
16788
16790
|
return releaseFailure("frontend.upload_release", "HTTP_ERROR", response.status);
|
|
16789
16791
|
}
|
|
16790
16792
|
return uploadReadback(http, projectRef, deploymentId, archive.sha256, response.status);
|
|
16791
16793
|
}
|
|
16794
|
+
if (!verifyReadback)
|
|
16795
|
+
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release });
|
|
16792
16796
|
const readback = await http.get(`${endpoint}/${release.release_id}`, { maxJsonBytes: RESPONSE_MAX_BYTES });
|
|
16793
16797
|
const verified = readback.ok ? releaseEnvelope(readback.data, { projectRef, deploymentId, releaseId: release.release_id }) : null;
|
|
16794
16798
|
if (!verified || verified.tree_sha256 !== release.tree_sha256) {
|
|
@@ -16796,65 +16800,11 @@ async function uploadFrontendRelease(http, projectRef, deploymentId, archivePath
|
|
|
16796
16800
|
}
|
|
16797
16801
|
return toolResponse({ project_ref: projectRef, deployment_id: deploymentId, release: verified });
|
|
16798
16802
|
}
|
|
16799
|
-
async function uploadProjectWebRelease(http, projectRef, environmentId, deploymentId, archivePath) {
|
|
16800
|
-
const endpoint = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/web-release?deployment_id=${encodeURIComponent(deploymentId)}`;
|
|
16801
|
-
const archive = await verifiedArchive(archivePath);
|
|
16802
|
-
const successPayload = (value) => {
|
|
16803
|
-
const release = value ? releaseRecord(value.release) : null;
|
|
16804
|
-
if (!value || value.ok !== true || value.project_ref !== projectRef || value.environment_id !== environmentId || value.deployment_id !== deploymentId || value.release_id !== archive.sha256 || release?.release_id !== archive.sha256 || release.tree_sha256.length !== 64)
|
|
16805
|
-
return null;
|
|
16806
|
-
return toolResponse({
|
|
16807
|
-
project_ref: projectRef,
|
|
16808
|
-
environment_id: environmentId,
|
|
16809
|
-
deployment_id: deploymentId,
|
|
16810
|
-
release_id: archive.sha256,
|
|
16811
|
-
release
|
|
16812
|
-
});
|
|
16813
|
-
};
|
|
16814
|
-
try {
|
|
16815
|
-
const response = await http.postBinary(endpoint, {
|
|
16816
|
-
stream: archiveStream(archive),
|
|
16817
|
-
byteLength: archive.sizeBytes
|
|
16818
|
-
}, {
|
|
16819
|
-
contentType: FRONTEND_ARCHIVE_CONTENT_TYPE,
|
|
16820
|
-
contentLength: archive.sizeBytes,
|
|
16821
|
-
contentSha256: archive.sha256,
|
|
16822
|
-
maxJsonBytes: RESPONSE_MAX_BYTES,
|
|
16823
|
-
timeoutMs: UPLOAD_REQUEST_TIMEOUT_MS,
|
|
16824
|
-
responseTimeoutMs: MUTATION_RESPONSE_TIMEOUT_MS
|
|
16825
|
-
});
|
|
16826
|
-
const value = response.data && typeof response.data === "object" && !Array.isArray(response.data) ? response.data : null;
|
|
16827
|
-
if (response.ok && response.status === 201) {
|
|
16828
|
-
const success = successPayload(value);
|
|
16829
|
-
if (success)
|
|
16830
|
-
return success;
|
|
16831
|
-
}
|
|
16832
|
-
if (response.transportError || response.responseReadError || response.status >= 500 || response.status === 202) {
|
|
16833
|
-
const readback = await getFrontendRelease(http, projectRef, deploymentId, archive.sha256);
|
|
16834
|
-
if (!readback.isError) {
|
|
16835
|
-
const readbackValue = JSON.parse(readback.content[0]?.text ?? "{}");
|
|
16836
|
-
const release = readbackValue.release;
|
|
16837
|
-
if (release && typeof release === "object" && !Array.isArray(release) && release.release_id === archive.sha256) {
|
|
16838
|
-
return toolResponse({
|
|
16839
|
-
project_ref: projectRef,
|
|
16840
|
-
environment_id: environmentId,
|
|
16841
|
-
deployment_id: deploymentId,
|
|
16842
|
-
release_id: archive.sha256,
|
|
16843
|
-
release
|
|
16844
|
-
});
|
|
16845
|
-
}
|
|
16846
|
-
}
|
|
16847
|
-
}
|
|
16848
|
-
return releaseFailure("frontend.upload_project_web_release", response.status >= 400 && response.status < 500 && !response.transportError ? "HTTP_ERROR" : "OUTCOME_UNKNOWN", response.status);
|
|
16849
|
-
} finally {
|
|
16850
|
-
await archive.handle.close();
|
|
16851
|
-
}
|
|
16852
|
-
}
|
|
16853
16803
|
async function uploadReadback(http, projectRef, deploymentId, releaseId, uploadStatus) {
|
|
16854
16804
|
const response = await http.get(releasePath(projectRef, deploymentId, releaseId), {
|
|
16855
16805
|
maxJsonBytes: RESPONSE_MAX_BYTES
|
|
16856
16806
|
});
|
|
16857
|
-
const release = response.ok ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
|
|
16807
|
+
const release = response.ok && response.status === 200 ? releaseEnvelope(response.data, { projectRef, deploymentId, releaseId }) : null;
|
|
16858
16808
|
if (!release) {
|
|
16859
16809
|
return releaseFailure("frontend.upload_release", "OUTCOME_UNKNOWN", uploadStatus);
|
|
16860
16810
|
}
|
|
@@ -16913,13 +16863,9 @@ function activationReceipt(candidate, input) {
|
|
|
16913
16863
|
return release;
|
|
16914
16864
|
}
|
|
16915
16865
|
async function activeReleaseReadback(http, identity) {
|
|
16916
|
-
const snapshot = await
|
|
16917
|
-
if (
|
|
16918
|
-
return
|
|
16919
|
-
const inventory = snapshot.inventory;
|
|
16920
|
-
if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
|
|
16921
|
-
return { release: null, status: 200 };
|
|
16922
|
-
}
|
|
16866
|
+
const snapshot = await activeReleaseSnapshotReadback(http, identity);
|
|
16867
|
+
if (!snapshot.release)
|
|
16868
|
+
return snapshot;
|
|
16923
16869
|
const releaseRead = await http.get(releasePath(identity.projectRef, identity.deploymentId, identity.releaseId), { maxJsonBytes: RESPONSE_MAX_BYTES });
|
|
16924
16870
|
const release = releaseRead.ok && releaseRead.status === 200 ? releaseEnvelope(releaseRead.data, {
|
|
16925
16871
|
projectRef: identity.projectRef,
|
|
@@ -16928,6 +16874,16 @@ async function activeReleaseReadback(http, identity) {
|
|
|
16928
16874
|
}) : null;
|
|
16929
16875
|
return { release, status: releaseRead.status };
|
|
16930
16876
|
}
|
|
16877
|
+
async function activeReleaseSnapshotReadback(http, identity) {
|
|
16878
|
+
const snapshot = await readActiveFrontendRelease(http, identity.projectRef, identity.deploymentId);
|
|
16879
|
+
if ("failure" in snapshot)
|
|
16880
|
+
return { release: null, status: snapshot.status };
|
|
16881
|
+
const inventory = snapshot.inventory;
|
|
16882
|
+
if (inventory.active_release_id !== identity.releaseId || inventory.active_activation_id !== identity.mutationId) {
|
|
16883
|
+
return { release: null, status: 200 };
|
|
16884
|
+
}
|
|
16885
|
+
return { release: inventory.releases[0] ?? null, status: 200 };
|
|
16886
|
+
}
|
|
16931
16887
|
async function readActiveFrontendRelease(http, projectRef, deploymentId) {
|
|
16932
16888
|
const response = await http.get(`${deploymentEndpoint(projectRef, deploymentId)}/active-release`, {
|
|
16933
16889
|
maxJsonBytes: RESPONSE_MAX_BYTES
|
|
@@ -16962,7 +16918,7 @@ async function getActiveFrontendRelease(http, projectRef, deploymentId) {
|
|
|
16962
16918
|
const snapshot = await readActiveFrontendRelease(http, projectRef, deploymentId);
|
|
16963
16919
|
return "failure" in snapshot ? snapshot.failure : toolResponse(snapshot.inventory);
|
|
16964
16920
|
}
|
|
16965
|
-
async function publishFrontendRelease(http, projectRef, deploymentId,
|
|
16921
|
+
async function publishFrontendRelease(http, projectRef, deploymentId, archiveSource, expectedTreeSha256) {
|
|
16966
16922
|
const authority = await readActiveFrontendRelease(http, projectRef, deploymentId);
|
|
16967
16923
|
if ("failure" in authority)
|
|
16968
16924
|
return authority.failure;
|
|
@@ -16979,7 +16935,14 @@ async function publishFrontendRelease(http, projectRef, deploymentId, archivePat
|
|
|
16979
16935
|
unchanged: true
|
|
16980
16936
|
});
|
|
16981
16937
|
}
|
|
16982
|
-
const
|
|
16938
|
+
const archive = typeof archiveSource === "string" ? { archivePath: archiveSource } : await archiveSource();
|
|
16939
|
+
let uploaded;
|
|
16940
|
+
try {
|
|
16941
|
+
uploaded = await uploadFrontendReleaseWithReadback(http, projectRef, deploymentId, archive.archivePath, false);
|
|
16942
|
+
} finally {
|
|
16943
|
+
if ("cleanup" in archive)
|
|
16944
|
+
await archive.cleanup();
|
|
16945
|
+
}
|
|
16983
16946
|
if (uploaded.isError)
|
|
16984
16947
|
return uploaded;
|
|
16985
16948
|
const value = JSON.parse(uploaded.content[0].text);
|
|
@@ -16990,14 +16953,14 @@ async function publishFrontendRelease(http, projectRef, deploymentId, archivePat
|
|
|
16990
16953
|
return releaseFailure("frontend.deploy", "INVALID_RESPONSE", 200);
|
|
16991
16954
|
}
|
|
16992
16955
|
const mutationId = crypto.randomUUID();
|
|
16993
|
-
const activated = await
|
|
16956
|
+
const activated = await activateFrontendReleaseWithReadback(http, {
|
|
16994
16957
|
projectRef,
|
|
16995
16958
|
deploymentId,
|
|
16996
16959
|
releaseId: release.release_id,
|
|
16997
16960
|
mutationId,
|
|
16998
16961
|
expectedActiveReleaseId: inventory.active_release_id ?? "absent",
|
|
16999
16962
|
expectedActivationId: inventory.active_activation_id ?? "absent"
|
|
17000
|
-
});
|
|
16963
|
+
}, activeReleaseSnapshotReadback);
|
|
17001
16964
|
const activatedPayload = JSON.parse(activated.content[0].text);
|
|
17002
16965
|
const active = activatedPayload.release;
|
|
17003
16966
|
const treeMismatch = !activated.isError && (!active || typeof active !== "object" || !("tree_sha256" in active) || active.tree_sha256 !== expectedTreeSha256);
|
|
@@ -17176,6 +17139,9 @@ async function readPreviousFrontendRelease(http, projectRef, deploymentId) {
|
|
|
17176
17139
|
};
|
|
17177
17140
|
}
|
|
17178
17141
|
async function activateFrontendRelease(http, input) {
|
|
17142
|
+
return activateFrontendReleaseWithReadback(http, input, activeReleaseReadback);
|
|
17143
|
+
}
|
|
17144
|
+
async function activateFrontendReleaseWithReadback(http, input, readActive) {
|
|
17179
17145
|
const mutationId = input.mutationId;
|
|
17180
17146
|
if (!MUTATION_ID_PATTERN2.test(mutationId))
|
|
17181
17147
|
throw new Error("'mutation_id' must be a UUIDv4");
|
|
@@ -17201,7 +17167,7 @@ async function activateFrontendRelease(http, input) {
|
|
|
17201
17167
|
}
|
|
17202
17168
|
return activationReadback(http, input, mutationId, response.status);
|
|
17203
17169
|
}
|
|
17204
|
-
const readback = await
|
|
17170
|
+
const readback = await readActive(http, { ...input, mutationId });
|
|
17205
17171
|
if (!readback.release || readback.release.tree_sha256 !== release.tree_sha256) {
|
|
17206
17172
|
return releaseFailure("frontend.activate_release", "OUTCOME_UNKNOWN", readback.status);
|
|
17207
17173
|
}
|
|
@@ -26359,6 +26325,7 @@ async function runAppRelease(request, options, delegate) {
|
|
|
26359
26325
|
schema: RELEASE_CONTROL_RESPONSE_SCHEMA,
|
|
26360
26326
|
ok: true,
|
|
26361
26327
|
operation: "applications.release",
|
|
26328
|
+
...deployReceipt.status === "accepted" ? { status: "accepted" } : {},
|
|
26362
26329
|
project_ref: ref,
|
|
26363
26330
|
application_id: id,
|
|
26364
26331
|
environment_id: environmentId,
|
|
@@ -26369,16 +26336,17 @@ async function runAppRelease(request, options, delegate) {
|
|
|
26369
26336
|
build: buildReceipt ? completed.build : { skipped: true, manifest_path: manifestPath },
|
|
26370
26337
|
phases: completed,
|
|
26371
26338
|
no_op: deployReceipt.action === "no-op" || deployReceipt.no_op === true,
|
|
26372
|
-
execution_performed: deployReceipt.execution_performed === true,
|
|
26339
|
+
...deployReceipt.status === "accepted" ? {} : { execution_performed: deployReceipt.execution_performed === true },
|
|
26373
26340
|
...typeof deployReceipt.activation_id === "string" ? { activation_id: deployReceipt.activation_id } : {},
|
|
26374
26341
|
...deployReceipt.web === undefined ? {} : { web: deployReceipt.web }
|
|
26375
26342
|
};
|
|
26376
26343
|
return request.format === "json" || request.json === true ? textResult(JSON.stringify(result, null, 2)) : textResult([
|
|
26377
|
-
`${ref}/${id}/${environmentId}: ${result.no_op ? "no-op" : "released"}`,
|
|
26344
|
+
`${ref}/${id}/${environmentId}: ${deployReceipt.status === "accepted" ? "accepted" : result.no_op ? "no-op" : "released"}`,
|
|
26378
26345
|
`Release: ${releaseId}`,
|
|
26379
26346
|
`Configuration: ${configurationId}`,
|
|
26380
26347
|
`Activation: ${result.activation_id ?? "not performed"}`,
|
|
26381
26348
|
...result.deployment_id === undefined ? [] : [`Deployment: ${result.deployment_id}`],
|
|
26349
|
+
...deployReceipt.status === "accepted" && result.deployment_id !== undefined ? [`Status: supacloud deploy --status ${result.deployment_id}`] : [],
|
|
26382
26350
|
`Build: ${request.skip_build ? "skipped" : "completed"}`
|
|
26383
26351
|
].join(`
|
|
26384
26352
|
`));
|
|
@@ -29057,11 +29025,22 @@ async function requireProjectDeploymentProtocol(http, projectRef, environmentId)
|
|
|
29057
29025
|
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.");
|
|
29058
29026
|
}
|
|
29059
29027
|
}
|
|
29028
|
+
var operation2 = "applications.project_deploy";
|
|
29060
29029
|
var scopeSchema = _Object_({
|
|
29061
29030
|
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
29062
29031
|
application_id: ApplicationIdSchema,
|
|
29063
29032
|
environment_id: ApplicationIdSchema
|
|
29064
29033
|
});
|
|
29034
|
+
var acceptedSchema = _Object_({
|
|
29035
|
+
schema: Literal("supacloud.project-deployment-accepted.v1"),
|
|
29036
|
+
ok: Literal(true),
|
|
29037
|
+
status: Literal("accepted"),
|
|
29038
|
+
deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
|
|
29039
|
+
...scopeSchema.properties,
|
|
29040
|
+
release_id: ApplicationDeployRequestSchema.properties.release_id,
|
|
29041
|
+
request_sha256: String2({ pattern: "^[a-f0-9]{64}$" }),
|
|
29042
|
+
replayed: Boolean2()
|
|
29043
|
+
}, { additionalProperties: false });
|
|
29065
29044
|
var statusSchema = _Object_({
|
|
29066
29045
|
schema: Literal("supacloud.project-deployment-status.v1"),
|
|
29067
29046
|
deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
|
|
@@ -29086,6 +29065,27 @@ var statusSchema = _Object_({
|
|
|
29086
29065
|
receipt: Optional(Unknown()),
|
|
29087
29066
|
failure_code: Optional(String2({ pattern: "^[A-Z][A-Z0-9_]{0,63}$" }))
|
|
29088
29067
|
}, { additionalProperties: false });
|
|
29068
|
+
async function readProjectDeploymentStatus(http, projectRef, environmentId, deploymentId) {
|
|
29069
|
+
if (!/^[a-z0-9-]{1,20}$/.test(projectRef) || !Check2(ApplicationIdSchema, environmentId) || !Check2(ApplicationDeployRequestSchema.properties.mutation_id, deploymentId)) {
|
|
29070
|
+
return releaseControlFailure(operation2, "INVALID_RESPONSE", null);
|
|
29071
|
+
}
|
|
29072
|
+
const path = `/v1/projects/${encodeURIComponent(projectRef)}/environments/${encodeURIComponent(environmentId)}/deployments/${deploymentId}`;
|
|
29073
|
+
const response = await http.get(path, { retry: false, totalTimeoutMs: 1e4, maxJsonBytes: 131072 });
|
|
29074
|
+
try {
|
|
29075
|
+
const state = response.data;
|
|
29076
|
+
if (!response.ok || response.status !== 200 || !Check2(statusSchema, state) || state.project_ref !== projectRef || state.environment_id !== environmentId || state.deployment_id !== deploymentId)
|
|
29077
|
+
throw new Error;
|
|
29078
|
+
if (state.status === "succeeded") {
|
|
29079
|
+
const receipt = parseApplicationDeployResult(state.receipt);
|
|
29080
|
+
if (state.phase !== "verifying" || receipt.project_ref !== projectRef || receipt.environment_id !== environmentId || receipt.application_id !== state.application_id || receipt.mutation_id !== deploymentId)
|
|
29081
|
+
throw new Error;
|
|
29082
|
+
} else if (state.receipt !== undefined)
|
|
29083
|
+
throw new Error;
|
|
29084
|
+
return state.status === "outcome_unknown" || state.status === "failed_terminal" ? releaseControlFailure(operation2, state.status === "outcome_unknown" ? "OUTCOME_UNKNOWN" : "MUTATION_NOT_SUCCEEDED", response.status, { ...state }) : releaseControlSuccess(operation2, { ...state });
|
|
29085
|
+
} catch {
|
|
29086
|
+
return releaseControlFailure(operation2, "INVALID_RESPONSE", response.status);
|
|
29087
|
+
}
|
|
29088
|
+
}
|
|
29089
29089
|
|
|
29090
29090
|
// src/shared/tools/deploy-tools.ts
|
|
29091
29091
|
var MAX_SOURCE_BYTES = 256 * 1024 * 1024;
|
|
@@ -29102,6 +29102,8 @@ var deployToolSchema = {
|
|
|
29102
29102
|
cwd: optional(String2(), "Project directory (default: current directory)"),
|
|
29103
29103
|
skip_build: optional(Boolean2(), "Use an existing output directory without building"),
|
|
29104
29104
|
assets_only: optional(Boolean2(), "Publish only configured static assets; leave backend Functions, schedules and migrations unchanged"),
|
|
29105
|
+
backend: optional(Boolean2(), "Publish the application backend independently; do not build or activate frontend assets"),
|
|
29106
|
+
status: optional(String2({ format: "uuid" }), "Read a backend deployment status without publishing"),
|
|
29105
29107
|
json: optional(Boolean2(), "Print only the final JSON result")
|
|
29106
29108
|
};
|
|
29107
29109
|
function record4(candidate) {
|
|
@@ -29477,8 +29479,7 @@ async function collectArchiveFiles(root) {
|
|
|
29477
29479
|
}
|
|
29478
29480
|
return { files, bytes, count: paths.length, treeSha256: tree.digest("hex") };
|
|
29479
29481
|
}
|
|
29480
|
-
async function
|
|
29481
|
-
const collected = await collectArchiveFiles(outputDirectory);
|
|
29482
|
+
async function createCollectedFrontendArchive(outputDirectory, collected) {
|
|
29482
29483
|
const temporaryDirectory = await mkdtemp2(join18(tmpdir3(), "supacloud-deploy-"));
|
|
29483
29484
|
const archivePath = join18(temporaryDirectory, `${basename8(outputDirectory)}.tar.zst`);
|
|
29484
29485
|
try {
|
|
@@ -29499,16 +29500,7 @@ async function createFrontendArchive(outputDirectory) {
|
|
|
29499
29500
|
throw error;
|
|
29500
29501
|
}
|
|
29501
29502
|
}
|
|
29502
|
-
function
|
|
29503
|
-
if (response.isError)
|
|
29504
|
-
throw new Error(response.content[0]?.text || "Deployment operation failed");
|
|
29505
|
-
const text = response.content.find((chunk) => chunk.type === "text")?.text;
|
|
29506
|
-
const parsed = text ? record4(JSON.parse(text)) : null;
|
|
29507
|
-
if (!parsed)
|
|
29508
|
-
throw new Error("Deployment operation returned an invalid response");
|
|
29509
|
-
return parsed;
|
|
29510
|
-
}
|
|
29511
|
-
async function stageApplicationWebRelease(http, projectRef, environmentId, configRoot, skipBuild, json, environmentVariables, assetsOnly = false) {
|
|
29503
|
+
async function publishConfiguredFrontend(http, projectRef, configRoot, skipBuild, json, environmentVariables) {
|
|
29512
29504
|
const target = selectFrontendTarget(configRoot, await readDeployConfig(configRoot));
|
|
29513
29505
|
if (!target)
|
|
29514
29506
|
return null;
|
|
@@ -29532,27 +29524,8 @@ async function stageApplicationWebRelease(http, projectRef, environmentId, confi
|
|
|
29532
29524
|
if (!skipBuild) {
|
|
29533
29525
|
await runBuild(buildCommand, projectDirectory, build.env, json);
|
|
29534
29526
|
}
|
|
29535
|
-
const
|
|
29536
|
-
|
|
29537
|
-
if (assetsOnly) {
|
|
29538
|
-
return { result: await publishFrontendRelease(http, projectRef, selected.id, archive.archivePath, archive.treeSha256) };
|
|
29539
|
-
}
|
|
29540
|
-
const uploaded = payload(await uploadProjectWebRelease(http, projectRef, environmentId, selected.id, archive.archivePath));
|
|
29541
|
-
const release = record4(uploaded.release);
|
|
29542
|
-
const releaseId = requiredString(release?.release_id, "release.release_id");
|
|
29543
|
-
if (releaseId !== archive.sha256)
|
|
29544
|
-
throw new Error("Uploaded Web release identity does not match the local archive");
|
|
29545
|
-
if (release?.tree_sha256 !== archive.treeSha256)
|
|
29546
|
-
throw new Error("Uploaded Web release tree does not match the local build");
|
|
29547
|
-
return {
|
|
29548
|
-
request: {
|
|
29549
|
-
deployment_id: selected.id,
|
|
29550
|
-
release_id: releaseId
|
|
29551
|
-
}
|
|
29552
|
-
};
|
|
29553
|
-
} finally {
|
|
29554
|
-
await archive.cleanup();
|
|
29555
|
-
}
|
|
29527
|
+
const collected = await collectArchiveFiles(outputDirectory);
|
|
29528
|
+
return publishFrontendRelease(http, projectRef, selected.id, () => createCollectedFrontendArchive(outputDirectory, collected), collected.treeSha256);
|
|
29556
29529
|
}
|
|
29557
29530
|
function registerDeployTools(server, http, options = {}) {
|
|
29558
29531
|
registerTool(server, "deploy", "Build and publish the linked project with one command", deployToolSchema, async (args) => {
|
|
@@ -29560,6 +29533,16 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
29560
29533
|
const projectRef = String(args.ref || options.projectRef || "").trim();
|
|
29561
29534
|
if (!projectRef)
|
|
29562
29535
|
throw new Error("A linked project ref is required. Set SUPACLOUD_PROJECT_REF or pass --ref");
|
|
29536
|
+
if (args.assets_only === true && args.backend === true)
|
|
29537
|
+
throw new Error("Choose either frontend assets or backend deployment");
|
|
29538
|
+
if (typeof args.status === "string") {
|
|
29539
|
+
if (args.assets_only === true || args.backend === true)
|
|
29540
|
+
throw new Error("Status cannot be combined with publishing options");
|
|
29541
|
+
const environmentId = options.environment?.trim() || options.application?.environmentId?.trim();
|
|
29542
|
+
if (!environmentId)
|
|
29543
|
+
throw new Error("Deployment status requires SUPACLOUD_ENV");
|
|
29544
|
+
return readProjectDeploymentStatus(http, projectRef, environmentId, args.status);
|
|
29545
|
+
}
|
|
29563
29546
|
const configRoot = await findDeployConfigRoot(invocationDirectory, options.environment ?? undefined);
|
|
29564
29547
|
const config = await readDeployConfig(configRoot);
|
|
29565
29548
|
const application = options.application?.id ? options.application : config.application ? {
|
|
@@ -29567,7 +29550,7 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
29567
29550
|
environmentId: options.environment || config.application.environmentId
|
|
29568
29551
|
} : undefined;
|
|
29569
29552
|
const legacyManifest = await hasProjectReleaseManifest(configRoot);
|
|
29570
|
-
const assetsOnly = args.assets_only === true ||
|
|
29553
|
+
const assetsOnly = args.assets_only === true || args.backend !== true && selectFrontendTarget(configRoot, config) !== null;
|
|
29571
29554
|
if (assetsOnly) {
|
|
29572
29555
|
if (!selectFrontendTarget(configRoot, config)) {
|
|
29573
29556
|
throw new Error("Static asset deployment requires a frontend configuration in supacloud.json");
|
|
@@ -29577,10 +29560,10 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
29577
29560
|
throw new Error("Static asset deployment requires SUPACLOUD_ENV");
|
|
29578
29561
|
}
|
|
29579
29562
|
await requireProjectDeploymentProtocol(http, projectRef, environmentId);
|
|
29580
|
-
const
|
|
29581
|
-
if (!
|
|
29563
|
+
const result = await publishConfiguredFrontend(http, projectRef, configRoot, args.skip_build === true, args.json === true, options.environmentVariables);
|
|
29564
|
+
if (!result)
|
|
29582
29565
|
throw new Error("Static asset deployment did not produce a receipt");
|
|
29583
|
-
return
|
|
29566
|
+
return result;
|
|
29584
29567
|
}
|
|
29585
29568
|
if (legacyManifest) {
|
|
29586
29569
|
throw new Error(`${DEPLOYMENT_UPGRADE} Replace deploy-manifest.json with the current application delivery configuration; no remote mutation was performed.`);
|
|
@@ -29602,7 +29585,6 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
29602
29585
|
throw new Error("Application profile must set only one of SUPACLOUD_APPLICATION_CONFIGURATION_PATH or SUPACLOUD_APPLICATION_CONFIGURATION_ID");
|
|
29603
29586
|
}
|
|
29604
29587
|
await requireProjectDeploymentProtocol(http, projectRef, environmentId);
|
|
29605
|
-
const stagedWeb = await stageApplicationWebRelease(http, projectRef, environmentId, configRoot, args.skip_build === true, args.json === true, options.environmentVariables);
|
|
29606
29588
|
const result = await options.applicationRelease({
|
|
29607
29589
|
action: "release",
|
|
29608
29590
|
ref: projectRef,
|
|
@@ -29613,7 +29595,6 @@ function registerDeployTools(server, http, options = {}) {
|
|
|
29613
29595
|
...configurationId ? { configuration_id: configurationId } : {},
|
|
29614
29596
|
...application.manifestPath ? { manifest_path: application.manifestPath } : {},
|
|
29615
29597
|
...args.skip_build === true ? { skip_build: true } : {},
|
|
29616
|
-
...stagedWeb?.request === undefined ? {} : { web_release: stagedWeb.request },
|
|
29617
29598
|
...args.json === true ? { format: "json", json: true } : {}
|
|
29618
29599
|
});
|
|
29619
29600
|
return result;
|
|
@@ -30408,12 +30389,22 @@ function registerDeveloperExperienceTools(server, options = {}) {
|
|
|
30408
30389
|
}
|
|
30409
30390
|
|
|
30410
30391
|
// src/shared/tools/project-deployment.ts
|
|
30411
|
-
var
|
|
30392
|
+
var operation3 = "applications.project_deploy";
|
|
30412
30393
|
var scopeSchema2 = _Object_({
|
|
30413
30394
|
project_ref: String2({ pattern: "^[a-z0-9-]{1,20}$" }),
|
|
30414
30395
|
application_id: ApplicationIdSchema,
|
|
30415
30396
|
environment_id: ApplicationIdSchema
|
|
30416
30397
|
});
|
|
30398
|
+
var acceptedSchema2 = _Object_({
|
|
30399
|
+
schema: Literal("supacloud.project-deployment-accepted.v1"),
|
|
30400
|
+
ok: Literal(true),
|
|
30401
|
+
status: Literal("accepted"),
|
|
30402
|
+
deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
|
|
30403
|
+
...scopeSchema2.properties,
|
|
30404
|
+
release_id: ApplicationDeployRequestSchema.properties.release_id,
|
|
30405
|
+
request_sha256: String2({ pattern: "^[a-f0-9]{64}$" }),
|
|
30406
|
+
replayed: Boolean2()
|
|
30407
|
+
}, { additionalProperties: false });
|
|
30417
30408
|
var statusSchema2 = _Object_({
|
|
30418
30409
|
schema: Literal("supacloud.project-deployment-status.v1"),
|
|
30419
30410
|
deployment_id: ApplicationDeployRequestSchema.properties.mutation_id,
|
|
@@ -30457,7 +30448,7 @@ async function runProjectDeployment(http, args) {
|
|
|
30457
30448
|
...args.web_release === undefined ? {} : { web_release: args.web_release }
|
|
30458
30449
|
};
|
|
30459
30450
|
if (!Check2(scopeSchema2, scope) || !Check2(ApplicationDeployRequestSchema, request) || request.configuration_id !== undefined && request.configuration_write !== undefined && request.configuration_id !== request.configuration_write.configuration_id) {
|
|
30460
|
-
return releaseControlFailure(
|
|
30451
|
+
return releaseControlFailure(operation3, "INVALID_RESPONSE", null);
|
|
30461
30452
|
}
|
|
30462
30453
|
const expected = { ...scope, request };
|
|
30463
30454
|
const identity = {
|
|
@@ -30473,15 +30464,29 @@ async function runProjectDeployment(http, args) {
|
|
|
30473
30464
|
deployment_id: mutation_id,
|
|
30474
30465
|
application_id: scope.application_id
|
|
30475
30466
|
}, { timeoutMs: 120000, maxJsonBytes: 131072, responseTimeoutMs: 30000 });
|
|
30476
|
-
if (result.ok && result.status ===
|
|
30467
|
+
if (result.ok && result.status === 202) {
|
|
30468
|
+
const accepted = result.data;
|
|
30469
|
+
if (Check2(acceptedSchema2, accepted) && accepted.deployment_id === mutation_id && accepted.project_ref === scope.project_ref && accepted.application_id === scope.application_id && accepted.environment_id === scope.environment_id && accepted.release_id === request.release_id && accepted.request_sha256 === mutationRequestFingerprint(request)) {
|
|
30470
|
+
return releaseControlSuccess(operation3, {
|
|
30471
|
+
status: "accepted",
|
|
30472
|
+
deployment_id: mutation_id,
|
|
30473
|
+
project_ref: scope.project_ref,
|
|
30474
|
+
application_id: scope.application_id,
|
|
30475
|
+
environment_id: scope.environment_id,
|
|
30476
|
+
release_id: request.release_id,
|
|
30477
|
+
replayed: accepted.replayed,
|
|
30478
|
+
status_path: `${endpoint}/${mutation_id}`
|
|
30479
|
+
});
|
|
30480
|
+
}
|
|
30481
|
+
} else if (result.ok && result.status === 200) {
|
|
30477
30482
|
try {
|
|
30478
|
-
return releaseControlSuccess(
|
|
30483
|
+
return releaseControlSuccess(operation3, {
|
|
30479
30484
|
...responseReceipt(result.data, expected),
|
|
30480
30485
|
deployment_id: mutation_id
|
|
30481
30486
|
});
|
|
30482
30487
|
} catch {}
|
|
30483
30488
|
} else if (!result.ok && !result.transportError && !result.responseReadError && result.status < 500 && result.status !== 408) {
|
|
30484
|
-
return releaseControlMutationFailure(
|
|
30489
|
+
return releaseControlMutationFailure(operation3, result, identity);
|
|
30485
30490
|
}
|
|
30486
30491
|
const observed = await http.get(`${endpoint}/${encodeURIComponent(mutation_id)}`, {
|
|
30487
30492
|
retry: false,
|
|
@@ -30495,20 +30500,20 @@ async function runProjectDeployment(http, args) {
|
|
|
30495
30500
|
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")
|
|
30496
30501
|
throw new Error;
|
|
30497
30502
|
const receipt = parseApplicationDeployResult(state.receipt, expected);
|
|
30498
|
-
return releaseControlSuccess(
|
|
30503
|
+
return releaseControlSuccess(operation3, {
|
|
30499
30504
|
...receipt,
|
|
30500
30505
|
deployment_id: mutation_id,
|
|
30501
30506
|
replayed: true,
|
|
30502
30507
|
execution_performed: false
|
|
30503
30508
|
});
|
|
30504
30509
|
} catch {
|
|
30505
|
-
return releaseControlFailure(
|
|
30510
|
+
return releaseControlFailure(operation3, "OUTCOME_UNKNOWN", result.transportError ? null : result.status, identity);
|
|
30506
30511
|
}
|
|
30507
30512
|
}
|
|
30508
30513
|
// package.json
|
|
30509
30514
|
var package_default = {
|
|
30510
30515
|
name: "@supacloud/cli",
|
|
30511
|
-
version: "0.
|
|
30516
|
+
version: "0.99.0",
|
|
30512
30517
|
description: "Project-scoped CLI for SupaCloud users",
|
|
30513
30518
|
type: "module",
|
|
30514
30519
|
main: "./dist/index.js",
|
|
@@ -1,2 +1,2 @@
|
|
|
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`.
|
|
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`. With a frontend configured, deploy publishes only Web assets; use `supacloud deploy --backend` for the application backend. `supacloud deploy --assets_only` remains an explicit Web-only option. SupaCloud owns activation; do not retry with legacy commands.";
|
|
2
2
|
export declare function assertCurrentDeploymentInput(tool: string, input: unknown): void;
|
|
@@ -27,6 +27,8 @@ export declare const deployToolSchema: {
|
|
|
27
27
|
cwd: Type.TOptional<Type.TString>;
|
|
28
28
|
skip_build: Type.TOptional<Type.TBoolean>;
|
|
29
29
|
assets_only: Type.TOptional<Type.TBoolean>;
|
|
30
|
+
backend: Type.TOptional<Type.TBoolean>;
|
|
31
|
+
status: Type.TOptional<Type.TString>;
|
|
30
32
|
json: Type.TOptional<Type.TBoolean>;
|
|
31
33
|
};
|
|
32
34
|
export declare function findDeployConfigRoot(startDirectory: string, environmentName?: string): Promise<string>;
|
|
@@ -46,7 +46,10 @@ 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,
|
|
49
|
+
export declare function publishFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, archiveSource: string | (() => Promise<{
|
|
50
|
+
archivePath: string;
|
|
51
|
+
cleanup(): Promise<void>;
|
|
52
|
+
}>), expectedTreeSha256: string): Promise<ToolResponse>;
|
|
50
53
|
export declare function rollbackFrontendRelease(http: FrontendReleaseHttp, projectRef: string, deploymentId: string, releaseId?: string, options?: {
|
|
51
54
|
expectedActiveReleaseId?: string;
|
|
52
55
|
expectedActivationId?: string;
|
|
@@ -2,3 +2,4 @@ import type { ToolResult } from "../tool-server";
|
|
|
2
2
|
import type { HttpTransport } from "../transports/http";
|
|
3
3
|
export declare function requireProjectDeploymentProtocol(http: Pick<HttpTransport, "get">, projectRef: string, environmentId: string): Promise<void>;
|
|
4
4
|
export declare function runProjectDeployment(http: Pick<HttpTransport, "post" | "get">, args: Record<string, unknown>): Promise<ToolResult>;
|
|
5
|
+
export declare function readProjectDeploymentStatus(http: Pick<HttpTransport, "get">, projectRef: string, environmentId: string, deploymentId: string): Promise<ToolResult>;
|
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 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`.
|
|
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`. With a frontend configured, deploy publishes only Web assets; use `supacloud deploy --backend` for the application backend. `supacloud deploy --assets_only` remains an explicit Web-only option. SupaCloud owns activation; do not retry with legacy commands.";
|
|
135
135
|
var removedFrontendActions = new Set([
|
|
136
136
|
"deploy_git",
|
|
137
137
|
"deploy_upload",
|