deepspace 0.29.1 → 0.30.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/CHANGELOG.md +42 -0
- package/dist/{chunk-DWSZYN73.js → chunk-DIG45T65.js} +2 -2
- package/dist/{chunk-DWSZYN73.js.map → chunk-DIG45T65.js.map} +1 -1
- package/dist/cli.js +282 -166
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +12 -1
- package/dist/server.js +10 -0
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +12 -1
- package/dist/worker.js +10 -0
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
renderUsage
|
|
9
9
|
} from "citty";
|
|
10
10
|
import { sync as spawnSync9 } from "cross-spawn";
|
|
11
|
-
import { readFileSync as
|
|
11
|
+
import { readFileSync as readFileSync28, existsSync as existsSync31 } from "fs";
|
|
12
12
|
import { dirname as dirname13, join as join29 } from "path";
|
|
13
13
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14
14
|
|
|
@@ -854,6 +854,10 @@ async function ensureToken(options = {}) {
|
|
|
854
854
|
throw notAuthenticated("The stored session is no longer valid (expired or unreadable)");
|
|
855
855
|
return token;
|
|
856
856
|
}
|
|
857
|
+
function loginAction() {
|
|
858
|
+
const canRunBare = Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY) || Boolean(process.env.DEEPSPACE_EMAIL) && Boolean(process.env.DEEPSPACE_PASSWORD);
|
|
859
|
+
return canRunBare ? cliAction("deepspace", "auth", "login") : void 0;
|
|
860
|
+
}
|
|
857
861
|
function notAuthenticated(state) {
|
|
858
862
|
const selected = process.env.DEEPSPACE_AUTH_URL !== void 0 ? `the auth service at ${AUTH_URL} (selected by DEEPSPACE_AUTH_URL)` : DEEPSPACE_ENV === "production" && process.env.DEEPSPACE_ENV === void 0 ? "production" : `${DEEPSPACE_ENV} (selected by DEEPSPACE_ENV=${process.env.DEEPSPACE_ENV})`;
|
|
859
863
|
const elsewhere = Object.entries(PLANE_AUTH_URLS).filter(([, url]) => url !== AUTH_URL && existsSync(credentialPaths(url).sessionPath)).map(([plane]) => plane);
|
|
@@ -865,7 +869,7 @@ function notAuthenticated(state) {
|
|
|
865
869
|
return new Refusal(
|
|
866
870
|
`${state} on ${selected}.${other} Run \`deepspace auth login\` (headless: \`deepspace auth login --email you@example.com --password-stdin\`, or set DEEPSPACE_EMAIL and DEEPSPACE_PASSWORD).`,
|
|
867
871
|
"not_authenticated",
|
|
868
|
-
{ action:
|
|
872
|
+
{ action: loginAction() }
|
|
869
873
|
);
|
|
870
874
|
}
|
|
871
875
|
function isTokenValid(jwt, minimumValidityMs) {
|
|
@@ -1006,7 +1010,7 @@ var login_default = defineDeepspaceCommand({
|
|
|
1006
1010
|
"Login timed out. Run `deepspace auth login` to try again.",
|
|
1007
1011
|
"login_timeout",
|
|
1008
1012
|
{
|
|
1009
|
-
action:
|
|
1013
|
+
action: loginAction()
|
|
1010
1014
|
}
|
|
1011
1015
|
);
|
|
1012
1016
|
}
|
|
@@ -1078,14 +1082,14 @@ async function createCliLoginSession(codeChallenge) {
|
|
|
1078
1082
|
throw new Refusal(
|
|
1079
1083
|
`Could not reach the auth service to create a login session: ${error instanceof Error ? error.message : String(error)}`,
|
|
1080
1084
|
"login_session_unreachable",
|
|
1081
|
-
{ action:
|
|
1085
|
+
{ action: loginAction() }
|
|
1082
1086
|
);
|
|
1083
1087
|
}
|
|
1084
1088
|
if (!sessionRes.ok) {
|
|
1085
1089
|
throw new Refusal(
|
|
1086
1090
|
`Could not create login session (${sessionRes.status})`,
|
|
1087
1091
|
"login_session_failed",
|
|
1088
|
-
{ action:
|
|
1092
|
+
{ action: loginAction() }
|
|
1089
1093
|
);
|
|
1090
1094
|
}
|
|
1091
1095
|
const sessionData = await sessionRes.json().catch(() => ({}));
|
|
@@ -1093,7 +1097,7 @@ async function createCliLoginSession(codeChallenge) {
|
|
|
1093
1097
|
throw new Refusal(
|
|
1094
1098
|
"Could not create login session \u2014 the auth server returned no session id or login url.",
|
|
1095
1099
|
"login_session_failed",
|
|
1096
|
-
{ action:
|
|
1100
|
+
{ action: loginAction() }
|
|
1097
1101
|
);
|
|
1098
1102
|
}
|
|
1099
1103
|
return { sessionId: sessionData.sessionId, loginUrl: sessionData.loginUrl };
|
|
@@ -2771,7 +2775,7 @@ async function fetchAppIdentityToken(deployUrl, callerJwt, appId) {
|
|
|
2771
2775
|
// wrangler env, and a bare `app init` under --env would target the
|
|
2772
2776
|
// TOP-LEVEL [vars] slot. dev/test/deploy attach the env-aware
|
|
2773
2777
|
// remedy as a structured action; surfaces without an action channel
|
|
2774
|
-
//
|
|
2778
|
+
// fall back to the
|
|
2775
2779
|
// app_not_found hint (check the id / `deepspace app list`).
|
|
2776
2780
|
`App ${appId} is not registered on this platform \u2014 DEEPSPACE_APP_ID may belong to a different environment (a staging id does not exist on prod, and vice versa), or the app was never initialized here.`,
|
|
2777
2781
|
404,
|
|
@@ -2805,7 +2809,7 @@ async function fetchAppIdentityToken(deployUrl, callerJwt, appId) {
|
|
|
2805
2809
|
// src/cli/lib/dev-vars.ts
|
|
2806
2810
|
var HEADER = [
|
|
2807
2811
|
"# Generated by deepspace \u2014 do not edit; this file is rewritten on every",
|
|
2808
|
-
"# dev, test,
|
|
2812
|
+
"# dev, test, and deploy run. App values live in the secret store:",
|
|
2809
2813
|
"# npx deepspace secrets set KEY=value"
|
|
2810
2814
|
].join("\n");
|
|
2811
2815
|
function requireAppIdFor(appDir, wranglerEnv) {
|
|
@@ -3053,6 +3057,15 @@ function canonicalPath2(path) {
|
|
|
3053
3057
|
return resolve7(path);
|
|
3054
3058
|
}
|
|
3055
3059
|
}
|
|
3060
|
+
function processAlive(pid) {
|
|
3061
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
3062
|
+
try {
|
|
3063
|
+
process.kill(pid, 0);
|
|
3064
|
+
return true;
|
|
3065
|
+
} catch (err) {
|
|
3066
|
+
return err.code === "EPERM";
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3056
3069
|
|
|
3057
3070
|
// src/cli/lib/preflight.ts
|
|
3058
3071
|
import { execFileSync } from "child_process";
|
|
@@ -3124,6 +3137,8 @@ function removeMacosJunk(dir) {
|
|
|
3124
3137
|
|
|
3125
3138
|
// src/server/rooms/binding-manifest.ts
|
|
3126
3139
|
var MAX_ENV_VAR_BYTES = 5 * 1024;
|
|
3140
|
+
var MAX_BINDING_NAME_LENGTH = 256;
|
|
3141
|
+
var SECRET_NAME_RE = new RegExp(`^[A-Za-z_][A-Za-z0-9_]{0,${MAX_BINDING_NAME_LENGTH - 1}}$`);
|
|
3127
3142
|
var AUTO_PROVISION_SENTINEL = "auto";
|
|
3128
3143
|
var VECTORIZE_METRICS = /* @__PURE__ */ new Set(["cosine", "euclidean", "dot-product"]);
|
|
3129
3144
|
var ALLOWED_BINDING_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -3184,6 +3199,12 @@ function validateBindingManifest(manifest) {
|
|
|
3184
3199
|
errors.push({ reason: `Binding of type "${type}" missing 'name' (string)` });
|
|
3185
3200
|
continue;
|
|
3186
3201
|
}
|
|
3202
|
+
if (name.length > MAX_BINDING_NAME_LENGTH) {
|
|
3203
|
+
errors.push({
|
|
3204
|
+
reason: `Binding name "${name.slice(0, 64)}\u2026" is ${name.length} characters; the limit is ${MAX_BINDING_NAME_LENGTH}`
|
|
3205
|
+
});
|
|
3206
|
+
continue;
|
|
3207
|
+
}
|
|
3187
3208
|
if (RESERVED_BINDING_NAMES.has(name)) {
|
|
3188
3209
|
errors.push({ reason: `Binding name "${name}" is reserved by the SDK` });
|
|
3189
3210
|
continue;
|
|
@@ -3425,7 +3446,6 @@ var RESERVED_SECRET_NAMES = /* @__PURE__ */ new Set([
|
|
|
3425
3446
|
"API_WORKER_URL",
|
|
3426
3447
|
"PLATFORM_WORKER_URL"
|
|
3427
3448
|
]);
|
|
3428
|
-
var SECRET_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3429
3449
|
var CONFIG_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
3430
3450
|
var MAX_SECRET_VALUE_BYTES = 32 * 1024;
|
|
3431
3451
|
function validateConfigName(configName) {
|
|
@@ -3438,6 +3458,12 @@ function validateConfigName(configName) {
|
|
|
3438
3458
|
return configName;
|
|
3439
3459
|
}
|
|
3440
3460
|
function validateSecretName(name) {
|
|
3461
|
+
if (name.length > MAX_BINDING_NAME_LENGTH) {
|
|
3462
|
+
throw new InputError(
|
|
3463
|
+
`Secret name "${name.slice(0, 64)}\u2026" is ${name.length} characters; the limit is ${MAX_BINDING_NAME_LENGTH}.`,
|
|
3464
|
+
"invalid_secret_name"
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3441
3467
|
if (!SECRET_NAME_RE.test(name)) {
|
|
3442
3468
|
throw new InputError(
|
|
3443
3469
|
`Invalid secret name "${name}". Use letters, numbers, and underscores; start with a letter or underscore.`,
|
|
@@ -3993,7 +4019,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
3993
4019
|
token = await ensureToken();
|
|
3994
4020
|
} catch (err) {
|
|
3995
4021
|
throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
|
|
3996
|
-
action:
|
|
4022
|
+
action: loginAction()
|
|
3997
4023
|
});
|
|
3998
4024
|
}
|
|
3999
4025
|
let payload;
|
|
@@ -4003,7 +4029,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
4003
4029
|
throw new Refusal(
|
|
4004
4030
|
"Malformed session token. Run `npx deepspace auth login`.",
|
|
4005
4031
|
"not_authenticated",
|
|
4006
|
-
{ action:
|
|
4032
|
+
{ action: loginAction() }
|
|
4007
4033
|
);
|
|
4008
4034
|
}
|
|
4009
4035
|
say(`Logged in as ${payload.name ?? payload.email}`);
|
|
@@ -4380,7 +4406,7 @@ function isAlive(pid) {
|
|
|
4380
4406
|
}
|
|
4381
4407
|
|
|
4382
4408
|
// src/cli/commands/test.ts
|
|
4383
|
-
import { existsSync as existsSync16, readdirSync as readdirSync5 } from "fs";
|
|
4409
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync as readdirSync5, rmSync as rmSync6 } from "fs";
|
|
4384
4410
|
import { join as join14, relative as relative2, resolve as resolve10, sep as sep2 } from "path";
|
|
4385
4411
|
import { sync as spawnSync5 } from "cross-spawn";
|
|
4386
4412
|
|
|
@@ -4638,12 +4664,39 @@ function playwrightTestArgs(testFiles, flags = {}) {
|
|
|
4638
4664
|
"tests/playwright.config.ts",
|
|
4639
4665
|
"--output",
|
|
4640
4666
|
PLAYWRIGHT_OUTPUT_DIR,
|
|
4667
|
+
// The default list reporter stays for the live stream; the json reporter
|
|
4668
|
+
// is what lets the CLI surface runtime skips and their authored reasons,
|
|
4669
|
+
// which the list reporter swallows (AX C3, docs/audits/2026-09-01).
|
|
4670
|
+
"--reporter=list,json",
|
|
4641
4671
|
...flags.grep ? ["--grep", flags.grep] : [],
|
|
4642
4672
|
...flags.project ? ["--project", flags.project] : [],
|
|
4643
4673
|
...flags.headed ? ["--headed"] : [],
|
|
4644
4674
|
...testFiles
|
|
4645
4675
|
];
|
|
4646
4676
|
}
|
|
4677
|
+
function skippedTestsFromPlaywrightJson(raw) {
|
|
4678
|
+
const skipped = [];
|
|
4679
|
+
const walk = (suite) => {
|
|
4680
|
+
for (const spec of suite.specs ?? []) {
|
|
4681
|
+
for (const test of spec.tests ?? []) {
|
|
4682
|
+
if (test.status !== "skipped") continue;
|
|
4683
|
+
const note3 = test.annotations?.find((entry) => entry.type === "skip")?.description;
|
|
4684
|
+
skipped.push({
|
|
4685
|
+
spec: typeof spec.file === "string" ? spec.file : "",
|
|
4686
|
+
title: typeof spec.title === "string" ? spec.title : "",
|
|
4687
|
+
reason: typeof note3 === "string" && note3 ? note3 : null
|
|
4688
|
+
});
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
for (const child of suite.suites ?? []) walk(child);
|
|
4692
|
+
};
|
|
4693
|
+
try {
|
|
4694
|
+
walk(JSON.parse(raw));
|
|
4695
|
+
} catch {
|
|
4696
|
+
return [];
|
|
4697
|
+
}
|
|
4698
|
+
return skipped;
|
|
4699
|
+
}
|
|
4647
4700
|
var test_default = defineDeepspaceCommand({
|
|
4648
4701
|
meta: {
|
|
4649
4702
|
name: "test",
|
|
@@ -4717,7 +4770,7 @@ var test_default = defineDeepspaceCommand({
|
|
|
4717
4770
|
throw new Refusal(
|
|
4718
4771
|
err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.",
|
|
4719
4772
|
"not_authenticated",
|
|
4720
|
-
{ action:
|
|
4773
|
+
{ action: loginAction() }
|
|
4721
4774
|
);
|
|
4722
4775
|
}
|
|
4723
4776
|
let generatedSecretsCache;
|
|
@@ -4753,15 +4806,21 @@ var test_default = defineDeepspaceCommand({
|
|
|
4753
4806
|
}
|
|
4754
4807
|
let exitCode = 0;
|
|
4755
4808
|
let skippedSpecs = [];
|
|
4809
|
+
let skippedTests = [];
|
|
4810
|
+
const playwright = (testFiles) => {
|
|
4811
|
+
const result = runPlaywright(appDir, testFiles, port, wranglerEnv, forwarded);
|
|
4812
|
+
skippedTests = result.skippedTests;
|
|
4813
|
+
return result.exitCode;
|
|
4814
|
+
};
|
|
4756
4815
|
switch (suite) {
|
|
4757
4816
|
case "smoke":
|
|
4758
|
-
exitCode =
|
|
4817
|
+
exitCode = playwright(["tests/smoke.spec.ts"]);
|
|
4759
4818
|
break;
|
|
4760
4819
|
case "api":
|
|
4761
|
-
exitCode =
|
|
4820
|
+
exitCode = playwright(["tests/api.spec.ts"]);
|
|
4762
4821
|
break;
|
|
4763
4822
|
case "e2e":
|
|
4764
|
-
exitCode =
|
|
4823
|
+
exitCode = playwright([]);
|
|
4765
4824
|
break;
|
|
4766
4825
|
case "unit":
|
|
4767
4826
|
if (forwarded.grep || forwarded.project || forwarded.headed) {
|
|
@@ -4775,12 +4834,12 @@ var test_default = defineDeepspaceCommand({
|
|
|
4775
4834
|
exitCode = runVitest(appDir, wranglerEnv);
|
|
4776
4835
|
if (exitCode === 0) {
|
|
4777
4836
|
await ensurePortFree(port, "0.0.0.0");
|
|
4778
|
-
exitCode =
|
|
4837
|
+
exitCode = playwright([]);
|
|
4779
4838
|
}
|
|
4780
4839
|
break;
|
|
4781
4840
|
case "default":
|
|
4782
4841
|
skippedSpecs = specsSkippedByDefaultSuite(appDir);
|
|
4783
|
-
exitCode =
|
|
4842
|
+
exitCode = playwright([...DEFAULT_SUITE_SPECS]);
|
|
4784
4843
|
if (skippedSpecs.length > 0) {
|
|
4785
4844
|
say(
|
|
4786
4845
|
`skipped ${skippedSpecs.length} spec file(s) not in smoke+api (${skippedSpecs.join(", ")}) \u2014 run 'deepspace test run all'`
|
|
@@ -4796,7 +4855,7 @@ var test_default = defineDeepspaceCommand({
|
|
|
4796
4855
|
"spec_not_found"
|
|
4797
4856
|
);
|
|
4798
4857
|
}
|
|
4799
|
-
exitCode =
|
|
4858
|
+
exitCode = playwright([suite]);
|
|
4800
4859
|
} else {
|
|
4801
4860
|
throw new Refusal(
|
|
4802
4861
|
`Unknown test suite: ${suite}
|
|
@@ -4805,12 +4864,20 @@ Available: smoke, api, e2e, unit, all \u2014 or a path to one spec file (tests/<
|
|
|
4805
4864
|
);
|
|
4806
4865
|
}
|
|
4807
4866
|
}
|
|
4867
|
+
if (skippedTests.length > 0) {
|
|
4868
|
+
const reasons = [...new Set(skippedTests.map((test) => test.reason).filter(Boolean))];
|
|
4869
|
+
say(
|
|
4870
|
+
`${skippedTests.length} test(s) were skipped at runtime` + (reasons.length > 0 ? ` \u2014 ${reasons.join(" | ")}` : "")
|
|
4871
|
+
);
|
|
4872
|
+
}
|
|
4808
4873
|
if (exitCode !== 0) {
|
|
4809
4874
|
throw new Refusal(`Test suite '${suite}' failed (exit ${exitCode}).`, "tests_failed", {
|
|
4810
|
-
extra: { suite, port, exitCode, skippedSpecs }
|
|
4875
|
+
extra: { suite, port, exitCode, skippedSpecs, skippedTests }
|
|
4811
4876
|
});
|
|
4812
4877
|
}
|
|
4813
|
-
return {
|
|
4878
|
+
return {
|
|
4879
|
+
data: { suite, port, appDir, wranglerEnv: wranglerEnv ?? null, skippedSpecs, skippedTests }
|
|
4880
|
+
};
|
|
4814
4881
|
}
|
|
4815
4882
|
});
|
|
4816
4883
|
function runSuite(appDir, argv, wranglerEnv, extraEnv = {}) {
|
|
@@ -4835,10 +4902,19 @@ function runSuite(appDir, argv, wranglerEnv, extraEnv = {}) {
|
|
|
4835
4902
|
}
|
|
4836
4903
|
}
|
|
4837
4904
|
function runPlaywright(appDir, testFiles, port, wranglerEnv, flags = {}) {
|
|
4838
|
-
|
|
4905
|
+
const resultsPath = join14(appDir, ".deepspace", "playwright-results.json");
|
|
4906
|
+
rmSync6(resultsPath, { force: true });
|
|
4907
|
+
const exitCode = runSuite(appDir, playwrightTestArgs(testFiles, flags), wranglerEnv, {
|
|
4839
4908
|
DEEPSPACE_PORT: String(port),
|
|
4840
|
-
PLAYWRIGHT_HTML_OUTPUT_DIR: ".deepspace/playwright-report"
|
|
4909
|
+
PLAYWRIGHT_HTML_OUTPUT_DIR: ".deepspace/playwright-report",
|
|
4910
|
+
PLAYWRIGHT_JSON_OUTPUT_FILE: resultsPath
|
|
4841
4911
|
});
|
|
4912
|
+
let raw = "";
|
|
4913
|
+
try {
|
|
4914
|
+
raw = readFileSync13(resultsPath, "utf-8");
|
|
4915
|
+
} catch {
|
|
4916
|
+
}
|
|
4917
|
+
return { exitCode, skippedTests: skippedTestsFromPlaywrightJson(raw) };
|
|
4842
4918
|
}
|
|
4843
4919
|
function runVitest(appDir, wranglerEnv) {
|
|
4844
4920
|
return runSuite(appDir, ["vitest", "run", "--passWithNoTests"], wranglerEnv);
|
|
@@ -5452,14 +5528,30 @@ var CONSECUTIVE_MATCHES = 10;
|
|
|
5452
5528
|
var MATCH_INTERVAL_MS = 250;
|
|
5453
5529
|
async function waitForLiveRelease(url, releaseStamp, timeoutMs) {
|
|
5454
5530
|
if (!releaseStamp) return "unverifiable";
|
|
5531
|
+
return agreeingProbes(
|
|
5532
|
+
timeoutMs,
|
|
5533
|
+
async (attempt) => servesRelease(bustedUrl(RELEASE_STAMP_PATH, url, attempt), releaseStamp)
|
|
5534
|
+
);
|
|
5535
|
+
}
|
|
5536
|
+
async function waitForHostReleased(url, timeoutMs) {
|
|
5537
|
+
return agreeingProbes(timeoutMs, async (attempt) => {
|
|
5538
|
+
const result = await getOnFreshConnection(bustedUrl("/", url, attempt));
|
|
5539
|
+
return result !== null && result.statusCode === 404;
|
|
5540
|
+
});
|
|
5541
|
+
}
|
|
5542
|
+
async function waitForDataPlane(url, appId, timeoutMs) {
|
|
5543
|
+
return agreeingProbes(timeoutMs, async (attempt) => {
|
|
5544
|
+
const result = await getOnFreshConnection(bustedUrl(`/ws/app:${appId}`, url, attempt));
|
|
5545
|
+
return result !== null && result.statusCode < 500;
|
|
5546
|
+
});
|
|
5547
|
+
}
|
|
5548
|
+
async function agreeingProbes(timeoutMs, probe) {
|
|
5455
5549
|
const deadline = Date.now() + timeoutMs;
|
|
5456
5550
|
let attempt = 0;
|
|
5457
5551
|
let streak = 0;
|
|
5458
5552
|
while (Date.now() < deadline) {
|
|
5459
5553
|
attempt++;
|
|
5460
|
-
|
|
5461
|
-
probe.searchParams.set("probe", `${Date.now()}-${attempt}`);
|
|
5462
|
-
if (await servesRelease(probe, releaseStamp)) {
|
|
5554
|
+
if (await probe(attempt)) {
|
|
5463
5555
|
streak++;
|
|
5464
5556
|
if (streak >= CONSECUTIVE_MATCHES) return "confirmed";
|
|
5465
5557
|
await sleep2(MATCH_INTERVAL_MS);
|
|
@@ -5470,11 +5562,16 @@ async function waitForLiveRelease(url, releaseStamp, timeoutMs) {
|
|
|
5470
5562
|
}
|
|
5471
5563
|
return "unconfirmed";
|
|
5472
5564
|
}
|
|
5565
|
+
function bustedUrl(path, base, attempt) {
|
|
5566
|
+
const probe = new URL(path, base);
|
|
5567
|
+
probe.searchParams.set("probe", `${Date.now()}-${attempt}`);
|
|
5568
|
+
return probe;
|
|
5569
|
+
}
|
|
5473
5570
|
async function servesRelease(probe, releaseStamp) {
|
|
5474
|
-
const
|
|
5475
|
-
if (
|
|
5571
|
+
const result = await getOnFreshConnection(probe);
|
|
5572
|
+
if (result === null || result.statusCode !== 200) return false;
|
|
5476
5573
|
try {
|
|
5477
|
-
return JSON.parse(body).release === releaseStamp;
|
|
5574
|
+
return JSON.parse(result.body).release === releaseStamp;
|
|
5478
5575
|
} catch {
|
|
5479
5576
|
return false;
|
|
5480
5577
|
}
|
|
@@ -5486,17 +5583,13 @@ function getOnFreshConnection(url, timeoutMs = 5e3) {
|
|
|
5486
5583
|
url,
|
|
5487
5584
|
{ method: "GET", agent: false, timeout: timeoutMs, headers: { "cache-control": "no-cache" } },
|
|
5488
5585
|
(response) => {
|
|
5489
|
-
|
|
5490
|
-
response.resume();
|
|
5491
|
-
resolve23(null);
|
|
5492
|
-
return;
|
|
5493
|
-
}
|
|
5586
|
+
const statusCode = response.statusCode ?? 0;
|
|
5494
5587
|
let body = "";
|
|
5495
5588
|
response.setEncoding("utf8");
|
|
5496
5589
|
response.on("data", (chunk) => {
|
|
5497
5590
|
if (body.length < 4096) body += chunk;
|
|
5498
5591
|
});
|
|
5499
|
-
response.on("end", () => resolve23(body));
|
|
5592
|
+
response.on("end", () => resolve23({ statusCode, body }));
|
|
5500
5593
|
response.on("error", () => resolve23(null));
|
|
5501
5594
|
}
|
|
5502
5595
|
);
|
|
@@ -5580,7 +5673,7 @@ function describeFilesFailure(status3, body) {
|
|
|
5580
5673
|
import * as p6 from "@clack/prompts";
|
|
5581
5674
|
import { execSync as execSync2 } from "child_process";
|
|
5582
5675
|
import { createHash as createHash2 } from "crypto";
|
|
5583
|
-
import { existsSync as existsSync20, readFileSync as
|
|
5676
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16, readdirSync as readdirSync7 } from "fs";
|
|
5584
5677
|
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join18, relative as relative3, resolve as resolve14, sep as sep3 } from "path";
|
|
5585
5678
|
|
|
5586
5679
|
// src/build/app-id.ts
|
|
@@ -5611,7 +5704,7 @@ function removeBuildDevVars(workerDir) {
|
|
|
5611
5704
|
}
|
|
5612
5705
|
|
|
5613
5706
|
// src/documentation/deploy.ts
|
|
5614
|
-
import { existsSync as existsSync18, readFileSync as
|
|
5707
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
5615
5708
|
import { join as join16 } from "path";
|
|
5616
5709
|
function readDocumentationDeployManifest(appDir, clientDir) {
|
|
5617
5710
|
if (!existsSync18(join16(appDir, "documentation.json"))) return void 0;
|
|
@@ -5621,11 +5714,11 @@ function readDocumentationDeployManifest(appDir, clientDir) {
|
|
|
5621
5714
|
"documentation.json exists but the build produced no documentation manifest. Ensure vite.config.ts includes deepSpaceDocumentation() from deepspace/documentation."
|
|
5622
5715
|
);
|
|
5623
5716
|
}
|
|
5624
|
-
return JSON.parse(
|
|
5717
|
+
return JSON.parse(readFileSync14(manifestPath, "utf8"));
|
|
5625
5718
|
}
|
|
5626
5719
|
|
|
5627
5720
|
// src/cli/commands/update/app-migrations.ts
|
|
5628
|
-
import { existsSync as existsSync19, readFileSync as
|
|
5721
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
|
|
5629
5722
|
import { join as join17 } from "path";
|
|
5630
5723
|
|
|
5631
5724
|
// src/shared/protocol/app-migrations.ts
|
|
@@ -5704,7 +5797,7 @@ function readAppliedAppMigrations(appDir) {
|
|
|
5704
5797
|
if (!existsSync19(path)) return [];
|
|
5705
5798
|
let parsed;
|
|
5706
5799
|
try {
|
|
5707
|
-
parsed = JSON.parse(
|
|
5800
|
+
parsed = JSON.parse(readFileSync15(path, "utf8"));
|
|
5708
5801
|
} catch {
|
|
5709
5802
|
throw new Refusal(
|
|
5710
5803
|
`${APP_MIGRATIONS_MANIFEST} must contain valid JSON`,
|
|
@@ -5770,12 +5863,12 @@ async function buildDeployBundle(options) {
|
|
|
5770
5863
|
"build_output_missing"
|
|
5771
5864
|
);
|
|
5772
5865
|
}
|
|
5773
|
-
const deployConfig = JSON.parse(
|
|
5866
|
+
const deployConfig = JSON.parse(readFileSync16(deployConfigPath, "utf-8"));
|
|
5774
5867
|
const outputWranglerPath = resolve14(dirname7(deployConfigPath), deployConfig.configPath);
|
|
5775
5868
|
if (!existsSync20(outputWranglerPath)) {
|
|
5776
5869
|
output.die(`Output wrangler.json not found at ${outputWranglerPath}`, "build_output_missing");
|
|
5777
5870
|
}
|
|
5778
|
-
const outputConfig = JSON.parse(
|
|
5871
|
+
const outputConfig = JSON.parse(readFileSync16(outputWranglerPath, "utf-8"));
|
|
5779
5872
|
if (outputConfig.name && outputConfig.name !== appName) {
|
|
5780
5873
|
const envHint = envName ? ` (--env ${envName})` : "";
|
|
5781
5874
|
output.die(
|
|
@@ -5876,7 +5969,7 @@ function collectWorkerBundle(workerDir, mainPath, clientDir) {
|
|
|
5876
5969
|
if (entry.isDirectory()) {
|
|
5877
5970
|
walk(fullPath);
|
|
5878
5971
|
} else if (entry.isFile() && WORKER_ES_MODULE.test(entry.name)) {
|
|
5879
|
-
modules.push({ name: moduleName(root, fullPath), content:
|
|
5972
|
+
modules.push({ name: moduleName(root, fullPath), content: readFileSync16(fullPath, "utf-8") });
|
|
5880
5973
|
}
|
|
5881
5974
|
}
|
|
5882
5975
|
};
|
|
@@ -5930,7 +6023,7 @@ function clientAppIdRefusal(assets, appId, envName) {
|
|
|
5930
6023
|
for (const asset of assets) {
|
|
5931
6024
|
if (!CLIENT_CODE_ASSET.test(asset.path)) continue;
|
|
5932
6025
|
if (DOCUMENTATION_OUTPUT.test(asset.path)) continue;
|
|
5933
|
-
const source =
|
|
6026
|
+
const source = readFileSync16(asset.sourcePath, "utf-8");
|
|
5934
6027
|
if (unsubstituted === void 0 && source.includes(APP_ID_DEFINE)) unsubstituted = asset.path;
|
|
5935
6028
|
for (const found of source.matchAll(APP_ID_LITERAL)) {
|
|
5936
6029
|
if (found[0] !== appId && !foreign.has(found[0])) foreign.set(found[0], asset.path);
|
|
@@ -5964,7 +6057,7 @@ function collectAssets(dir) {
|
|
|
5964
6057
|
if (entry.isDirectory()) {
|
|
5965
6058
|
walk(fullPath, relativePath);
|
|
5966
6059
|
} else {
|
|
5967
|
-
const bytes =
|
|
6060
|
+
const bytes = readFileSync16(fullPath);
|
|
5968
6061
|
assets.push({
|
|
5969
6062
|
path: `/${relativePath}`,
|
|
5970
6063
|
hash: createHash2("sha256").update(bytes).digest("hex"),
|
|
@@ -5985,7 +6078,7 @@ function readDeployAssetConfig(clientDir) {
|
|
|
5985
6078
|
]) {
|
|
5986
6079
|
const filePath = join18(clientDir, file);
|
|
5987
6080
|
if (!existsSync20(filePath)) continue;
|
|
5988
|
-
const content =
|
|
6081
|
+
const content = readFileSync16(filePath, "utf8");
|
|
5989
6082
|
if (content.trim()) config[key] = content;
|
|
5990
6083
|
}
|
|
5991
6084
|
return config;
|
|
@@ -6310,7 +6403,7 @@ function createDeployOutput(json) {
|
|
|
6310
6403
|
|
|
6311
6404
|
// src/cli/commands/deploy/request.ts
|
|
6312
6405
|
import * as p11 from "@clack/prompts";
|
|
6313
|
-
import { readFileSync as
|
|
6406
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
6314
6407
|
|
|
6315
6408
|
// src/cli/commands/deploy/repository.ts
|
|
6316
6409
|
import * as p9 from "@clack/prompts";
|
|
@@ -7481,7 +7574,7 @@ async function uploadDeployAssetsWithAuth(options, auth2) {
|
|
|
7481
7574
|
// against the plan before it touches storage, and a stream body
|
|
7482
7575
|
// would be sent chunked with no length at all; a retry also needs a
|
|
7483
7576
|
// body it can send again.
|
|
7484
|
-
body:
|
|
7577
|
+
body: readFileSync17(asset.sourcePath)
|
|
7485
7578
|
}),
|
|
7486
7579
|
{ attempts: ASSET_UPLOAD_ATTEMPTS, timeoutMs: ASSET_UPLOAD_ATTEMPT_TIMEOUT_MS }
|
|
7487
7580
|
)
|
|
@@ -7526,7 +7619,10 @@ function isDeployServiceResourceLimit(status3, error) {
|
|
|
7526
7619
|
}
|
|
7527
7620
|
function formatDeployWorkerError(status3, error, code) {
|
|
7528
7621
|
const detail = error ?? `Deployment error (${status3})`;
|
|
7529
|
-
if (code === "cli_outdated" || code === "secrets_read_failed" || code === "release_reconciliation_pending"
|
|
7622
|
+
if (code === "cli_outdated" || code === "secrets_read_failed" || code === "release_reconciliation_pending" || // Cloudflare deterministically rejected this upload; the sentence already
|
|
7623
|
+
// names the input to fix, and incident boilerplate would prescribe an
|
|
7624
|
+
// infinite wait-and-retry loop (AX S1, docs/audits/2026-09-01).
|
|
7625
|
+
code === "worker_upload_rejected") {
|
|
7530
7626
|
return detail;
|
|
7531
7627
|
}
|
|
7532
7628
|
if (isDeployServiceResourceLimit(status3, error)) {
|
|
@@ -7553,8 +7649,9 @@ function errorMessage5(error) {
|
|
|
7553
7649
|
|
|
7554
7650
|
// src/cli/commands/deploy/lock.ts
|
|
7555
7651
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7556
|
-
import { mkdirSync as mkdirSync8, readFileSync as
|
|
7652
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync18, rmSync as rmSync7, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
7557
7653
|
import { dirname as dirname8, join as join20 } from "path";
|
|
7654
|
+
var DEPLOY_LOCK_MAX_AGE_MS = 10 * 6e4;
|
|
7558
7655
|
function deployLockPath(appDir) {
|
|
7559
7656
|
return join20(appDir, ".deepspace", "deploy.lock");
|
|
7560
7657
|
}
|
|
@@ -7566,29 +7663,58 @@ function acquireDeployLock(appDir) {
|
|
|
7566
7663
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7567
7664
|
token: randomUUID2()
|
|
7568
7665
|
};
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7666
|
+
const take = () => {
|
|
7667
|
+
try {
|
|
7668
|
+
writeFileSync6(path, JSON.stringify(record), { flag: "wx" });
|
|
7669
|
+
return true;
|
|
7670
|
+
} catch (err) {
|
|
7671
|
+
if (err.code !== "EEXIST") throw err;
|
|
7672
|
+
return false;
|
|
7673
|
+
}
|
|
7674
|
+
};
|
|
7675
|
+
if (!take()) {
|
|
7676
|
+
if (lockIsStale(path)) rmSync7(path, { force: true });
|
|
7677
|
+
if (!take()) {
|
|
7678
|
+
const holder = readLock(path);
|
|
7679
|
+
throw new Refusal(
|
|
7680
|
+
(holder ? `Another deploy of this directory holds the deploy lock (pid ${holder.pid}, started ${holder.startedAt})` : `A fresh deploy lock is present at ${path} but unreadable, so this run cannot tell whether a deploy is live`) + ` \u2014 two deploys of one checkout race on its build output. Dead and stale locks are reclaimed automatically, so this holder still looks live; wait for it to finish, or remove ${path} and retry only if you are certain no deploy is running.`,
|
|
7681
|
+
"deploy_in_progress",
|
|
7682
|
+
{
|
|
7683
|
+
extra: {
|
|
7684
|
+
lockPath: path,
|
|
7685
|
+
...holder ? { holder: { pid: holder.pid, startedAt: holder.startedAt } } : {}
|
|
7686
|
+
}
|
|
7581
7687
|
}
|
|
7582
|
-
|
|
7583
|
-
|
|
7688
|
+
);
|
|
7689
|
+
}
|
|
7584
7690
|
}
|
|
7585
|
-
|
|
7586
|
-
|
|
7691
|
+
const onSignal = (signal) => {
|
|
7692
|
+
release2();
|
|
7693
|
+
process.stderr.write(`Deploy interrupted by ${signal}; released the deploy lock.
|
|
7694
|
+
`);
|
|
7695
|
+
process.exit(signal === "SIGTERM" ? 143 : 130);
|
|
7587
7696
|
};
|
|
7697
|
+
process.once("SIGINT", onSignal);
|
|
7698
|
+
process.once("SIGTERM", onSignal);
|
|
7699
|
+
function release2() {
|
|
7700
|
+
process.removeListener("SIGINT", onSignal);
|
|
7701
|
+
process.removeListener("SIGTERM", onSignal);
|
|
7702
|
+
if (readLock(path)?.token === record.token) rmSync7(path, { force: true });
|
|
7703
|
+
}
|
|
7704
|
+
return release2;
|
|
7705
|
+
}
|
|
7706
|
+
function lockIsStale(path) {
|
|
7707
|
+
try {
|
|
7708
|
+
if (Date.now() - statSync3(path).mtimeMs > DEPLOY_LOCK_MAX_AGE_MS) return true;
|
|
7709
|
+
} catch {
|
|
7710
|
+
return false;
|
|
7711
|
+
}
|
|
7712
|
+
const holder = readLock(path);
|
|
7713
|
+
return holder !== null && !processAlive(holder.pid);
|
|
7588
7714
|
}
|
|
7589
7715
|
function readLock(path) {
|
|
7590
7716
|
try {
|
|
7591
|
-
const parsed = JSON.parse(
|
|
7717
|
+
const parsed = JSON.parse(readFileSync18(path, "utf-8"));
|
|
7592
7718
|
return typeof parsed.pid === "number" && typeof parsed.startedAt === "string" && typeof parsed.token === "string" ? { pid: parsed.pid, startedAt: parsed.startedAt, token: parsed.token } : null;
|
|
7593
7719
|
} catch {
|
|
7594
7720
|
return null;
|
|
@@ -7823,11 +7949,20 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7823
7949
|
);
|
|
7824
7950
|
}
|
|
7825
7951
|
let serving = "unverifiable";
|
|
7952
|
+
let dataPlane = "unconfirmed";
|
|
7826
7953
|
const edgeWaitStarted = Date.now();
|
|
7827
7954
|
if (body.url) {
|
|
7828
7955
|
spinner2.message("Waiting for the edge to serve this release...");
|
|
7829
7956
|
serving = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
7830
|
-
if (serving === "confirmed")
|
|
7957
|
+
if (serving === "confirmed") {
|
|
7958
|
+
dataPlane = await waitForDataPlane(body.url, appId, 3e4);
|
|
7959
|
+
await wakeWorker(body.url);
|
|
7960
|
+
if (dataPlane === "unconfirmed") {
|
|
7961
|
+
p12.log.warn(
|
|
7962
|
+
"The edge serves the new release, but its worker still answered 5xx on the data plane \u2014 Durable Object bindings can lag a redeploy briefly. First requests may fail; retry before asserting against the app."
|
|
7963
|
+
);
|
|
7964
|
+
}
|
|
7965
|
+
}
|
|
7831
7966
|
if (serving !== "confirmed") {
|
|
7832
7967
|
spinner2.stop(
|
|
7833
7968
|
serving === "unconfirmed" ? "Deployed \u2014 the edge is still rolling this release out" : "Deployed \u2014 serving could not be verified from here"
|
|
@@ -7846,6 +7981,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7846
7981
|
releaseId: body.releaseId ?? null,
|
|
7847
7982
|
bundleRetained: body.bundleRetained ?? null,
|
|
7848
7983
|
serving,
|
|
7984
|
+
dataPlane,
|
|
7849
7985
|
recoverable: repository.recoverable,
|
|
7850
7986
|
...worktree,
|
|
7851
7987
|
...renameFields,
|
|
@@ -7857,7 +7993,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7857
7993
|
}
|
|
7858
7994
|
}
|
|
7859
7995
|
spinner2.stop(
|
|
7860
|
-
`Deployed! (edge confirmed in ${Math.round((Date.now() - edgeWaitStarted) / 1e3)}s)`
|
|
7996
|
+
`Deployed! (edge${dataPlane === "confirmed" ? " + data plane" : ""} confirmed in ${Math.round((Date.now() - edgeWaitStarted) / 1e3)}s)`
|
|
7861
7997
|
);
|
|
7862
7998
|
p12.log.success(`Live at: ${body.url}`);
|
|
7863
7999
|
await syncPostDeployCommerce(appDir, appId, output.nonInteractive);
|
|
@@ -7870,6 +8006,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7870
8006
|
// Always present, so a caller branches on one field instead of
|
|
7871
8007
|
// inferring success from an absent one.
|
|
7872
8008
|
serving,
|
|
8009
|
+
dataPlane,
|
|
7873
8010
|
releaseId: body.releaseId ?? null,
|
|
7874
8011
|
bundleRetained: body.bundleRetained ?? null,
|
|
7875
8012
|
recoverable: repository.recoverable,
|
|
@@ -7999,7 +8136,7 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
7999
8136
|
token = await ensureToken();
|
|
8000
8137
|
} catch (err) {
|
|
8001
8138
|
throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
|
|
8002
|
-
action:
|
|
8139
|
+
action: loginAction()
|
|
8003
8140
|
});
|
|
8004
8141
|
}
|
|
8005
8142
|
let appId;
|
|
@@ -8070,13 +8207,20 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
8070
8207
|
}
|
|
8071
8208
|
const hosts = body.releasedHosts ?? [];
|
|
8072
8209
|
const alreadyUndeployed = hosts.length === 0;
|
|
8073
|
-
|
|
8210
|
+
let released = null;
|
|
8211
|
+
if (!alreadyUndeployed) {
|
|
8212
|
+
s?.message("Waiting for the edge to release the host...");
|
|
8213
|
+
released = await waitForHostReleased(`https://${hosts[0]}`, 9e4);
|
|
8214
|
+
}
|
|
8215
|
+
s?.stop(
|
|
8216
|
+
alreadyUndeployed ? "Nothing to remove" : released === "confirmed" ? "Removed (edge confirmed the takedown)" : "Removed \u2014 the edge is still releasing the host"
|
|
8217
|
+
);
|
|
8074
8218
|
if (!args.json) {
|
|
8075
8219
|
p13.outro(
|
|
8076
|
-
alreadyUndeployed ? `${target2} was already offline \u2014 no URL was serving, so nothing changed. The app keeps its id; redeploy to bring it back.` : `${hosts.join(", ")} taken down. The app keeps its id \u2014 redeploy to bring it back.`
|
|
8220
|
+
alreadyUndeployed ? `${target2} was already offline \u2014 no URL was serving, so nothing changed. The app keeps its id; redeploy to bring it back.` : `${hosts.join(", ")} taken down${released === "confirmed" ? "" : " (cached edges may answer 200 for a short while yet)"}. The app keeps its id \u2014 redeploy to bring it back.`
|
|
8077
8221
|
);
|
|
8078
8222
|
}
|
|
8079
|
-
return { data: { appId, releasedHosts: hosts, alreadyUndeployed } };
|
|
8223
|
+
return { data: { appId, releasedHosts: hosts, alreadyUndeployed, released } };
|
|
8080
8224
|
}
|
|
8081
8225
|
});
|
|
8082
8226
|
|
|
@@ -8091,7 +8235,7 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
8091
8235
|
} catch (err) {
|
|
8092
8236
|
const msg = err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.";
|
|
8093
8237
|
throw isNetworkError(err) ? new Refusal(msg, "network_error") : new Refusal(msg, "not_authenticated", {
|
|
8094
|
-
action:
|
|
8238
|
+
action: loginAction()
|
|
8095
8239
|
});
|
|
8096
8240
|
}
|
|
8097
8241
|
let payload;
|
|
@@ -8099,7 +8243,7 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
8099
8243
|
payload = decodeJwtPayload(jwt);
|
|
8100
8244
|
} catch {
|
|
8101
8245
|
throw new Refusal("Malformed session token. Run `deepspace auth login` again.", "not_authenticated", {
|
|
8102
|
-
action:
|
|
8246
|
+
action: loginAction()
|
|
8103
8247
|
});
|
|
8104
8248
|
}
|
|
8105
8249
|
const isTestAccount = !!payload.email?.endsWith("@deepspace.test");
|
|
@@ -8610,7 +8754,7 @@ var usage_default = defineDeepspaceCommand({
|
|
|
8610
8754
|
});
|
|
8611
8755
|
|
|
8612
8756
|
// src/cli/commands/add.ts
|
|
8613
|
-
import { existsSync as existsSync23, readFileSync as
|
|
8757
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, realpathSync as realpathSync4 } from "fs";
|
|
8614
8758
|
import { dirname as dirname10, join as join23, resolve as resolve17 } from "path";
|
|
8615
8759
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
8616
8760
|
|
|
@@ -8623,10 +8767,10 @@ import {
|
|
|
8623
8767
|
mkdirSync as mkdirSync9,
|
|
8624
8768
|
mkdtempSync,
|
|
8625
8769
|
openSync as openSync2,
|
|
8626
|
-
readFileSync as
|
|
8770
|
+
readFileSync as readFileSync19,
|
|
8627
8771
|
readSync,
|
|
8628
8772
|
readdirSync as readdirSync8,
|
|
8629
|
-
rmSync as
|
|
8773
|
+
rmSync as rmSync8,
|
|
8630
8774
|
writeFileSync as writeFileSync7
|
|
8631
8775
|
} from "fs";
|
|
8632
8776
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
@@ -8640,7 +8784,7 @@ function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
|
8640
8784
|
const packagePath = join22(dir, "package.json");
|
|
8641
8785
|
if (existsSync22(packagePath)) {
|
|
8642
8786
|
try {
|
|
8643
|
-
const pkg2 = JSON.parse(
|
|
8787
|
+
const pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
8644
8788
|
if (pkg2.name === "deepspace") return dir;
|
|
8645
8789
|
} catch {
|
|
8646
8790
|
}
|
|
@@ -8657,7 +8801,7 @@ function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
|
8657
8801
|
const configPath = join22(packageRoot, "features", id, "feature.json");
|
|
8658
8802
|
if (!existsSync22(configPath)) return null;
|
|
8659
8803
|
try {
|
|
8660
|
-
const config = JSON.parse(
|
|
8804
|
+
const config = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
8661
8805
|
if (typeof config.id !== "string" || typeof config.name !== "string" || !Array.isArray(config.files)) {
|
|
8662
8806
|
return null;
|
|
8663
8807
|
}
|
|
@@ -8709,7 +8853,7 @@ function copyFile(src, dest) {
|
|
|
8709
8853
|
function copyFileWithImportShift(src, dest, levels) {
|
|
8710
8854
|
mkdirSync9(dirname9(dest), { recursive: true });
|
|
8711
8855
|
const prefix = "../".repeat(levels);
|
|
8712
|
-
const shifted =
|
|
8856
|
+
const shifted = readFileSync19(src, "utf-8").replace(
|
|
8713
8857
|
/(from\s+|import\s+|import\()(['"])(\.\.\/)/g,
|
|
8714
8858
|
`$1$2${prefix}$3`
|
|
8715
8859
|
);
|
|
@@ -8768,7 +8912,7 @@ function integrateSchema(config, targetDir, emit) {
|
|
|
8768
8912
|
if (!existsSync22(schemasPath)) {
|
|
8769
8913
|
return [unresolvedSchema(config.schema, "src/schemas.ts was not found.", emit)];
|
|
8770
8914
|
}
|
|
8771
|
-
let content =
|
|
8915
|
+
let content = readFileSync19(schemasPath, "utf-8");
|
|
8772
8916
|
const { exportName, importPath, spreadOperator } = config.schema;
|
|
8773
8917
|
const importPattern = new RegExp(`^import\\s+\\{[^}]*\\b${exportName}\\b`, "m");
|
|
8774
8918
|
if (importPattern.test(content)) {
|
|
@@ -8825,7 +8969,7 @@ function integrateActions(config, targetDir, emit) {
|
|
|
8825
8969
|
if (!existsSync22(actionsPath)) {
|
|
8826
8970
|
return [unresolvedActions(config.actions, "src/actions/index.ts was not found.", emit)];
|
|
8827
8971
|
}
|
|
8828
|
-
let content =
|
|
8972
|
+
let content = readFileSync19(actionsPath, "utf-8");
|
|
8829
8973
|
const registryPattern = /export const actions:\s*Record<string,\s*ActionHandler(?:<[^>]*>)?>\s*=\s*\{/;
|
|
8830
8974
|
if (!registryPattern.test(content)) {
|
|
8831
8975
|
const reason = "src/actions/index.ts has an unexpected structure.";
|
|
@@ -8880,7 +9024,7 @@ function integrateCode(config, targetDir, emit) {
|
|
|
8880
9024
|
});
|
|
8881
9025
|
continue;
|
|
8882
9026
|
}
|
|
8883
|
-
const original =
|
|
9027
|
+
const original = readFileSync19(targetPath, "utf-8");
|
|
8884
9028
|
if (original.includes(insertion.insert.trim())) {
|
|
8885
9029
|
emit(` Integration already present: ${insertion.file}`);
|
|
8886
9030
|
continue;
|
|
@@ -8918,7 +9062,7 @@ ${content.slice(
|
|
|
8918
9062
|
function integrateIgnore(config, targetDir) {
|
|
8919
9063
|
if (!config.ignore?.length) return;
|
|
8920
9064
|
const targetPath = join22(targetDir, ".gitignore");
|
|
8921
|
-
const current = existsSync22(targetPath) ?
|
|
9065
|
+
const current = existsSync22(targetPath) ? readFileSync19(targetPath, "utf-8") : "";
|
|
8922
9066
|
const present = new Set(current.split(/\r?\n/).map((line) => line.trim()));
|
|
8923
9067
|
const missing = config.ignore.filter((pattern) => !present.has(pattern));
|
|
8924
9068
|
if (missing.length === 0) return;
|
|
@@ -8938,7 +9082,7 @@ function integrateWrangler(config, targetDir, emit) {
|
|
|
8938
9082
|
if (!existsSync22(targetPath)) {
|
|
8939
9083
|
return [{ area: "wrangler", reason: "wrangler.toml was not found.", steps }];
|
|
8940
9084
|
}
|
|
8941
|
-
let source =
|
|
9085
|
+
let source = readFileSync19(targetPath, "utf-8");
|
|
8942
9086
|
if (runWorkerFirst && !/^\[assets\]\s*$/m.test(source)) {
|
|
8943
9087
|
return [{ area: "wrangler", reason: "wrangler.toml has no [assets] section.", steps }];
|
|
8944
9088
|
}
|
|
@@ -9035,7 +9179,7 @@ function integrateRoute(config, targetDir, emit) {
|
|
|
9035
9179
|
if (!existsSync22(navPath)) {
|
|
9036
9180
|
return [unresolvedRoute(config.route, config, "src/nav.ts was not found.", emit)];
|
|
9037
9181
|
}
|
|
9038
|
-
let content =
|
|
9182
|
+
let content = readFileSync19(navPath, "utf-8");
|
|
9039
9183
|
const routePath = config.route.path;
|
|
9040
9184
|
if (content.includes(`'${routePath}'`)) {
|
|
9041
9185
|
emit(` Nav already present: ${routePath}`);
|
|
@@ -9097,7 +9241,7 @@ function runPackageInstall(packageManager, targetDir, outputVisible) {
|
|
|
9097
9241
|
};
|
|
9098
9242
|
} finally {
|
|
9099
9243
|
if (outputFd !== void 0) closeSync2(outputFd);
|
|
9100
|
-
|
|
9244
|
+
rmSync8(captureDir, { recursive: true, force: true });
|
|
9101
9245
|
}
|
|
9102
9246
|
}
|
|
9103
9247
|
function integrateDependencies(config, targetDir, runInstall, outputVisible, emit) {
|
|
@@ -9116,7 +9260,7 @@ function integrateDependencies(config, targetDir, runInstall, outputVisible, emi
|
|
|
9116
9260
|
}
|
|
9117
9261
|
let pkg2;
|
|
9118
9262
|
try {
|
|
9119
|
-
pkg2 = JSON.parse(
|
|
9263
|
+
pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
9120
9264
|
} catch (error) {
|
|
9121
9265
|
emit(
|
|
9122
9266
|
` Could not patch package.json (parse error: ${error instanceof Error ? error.message : String(error)})`
|
|
@@ -9176,7 +9320,7 @@ ${child.diagnosticTail}` : "";
|
|
|
9176
9320
|
}
|
|
9177
9321
|
function dependencySnapshot(targetDir) {
|
|
9178
9322
|
try {
|
|
9179
|
-
const pkg2 = JSON.parse(
|
|
9323
|
+
const pkg2 = JSON.parse(readFileSync19(join22(targetDir, "package.json"), "utf-8"));
|
|
9180
9324
|
return {
|
|
9181
9325
|
dependencies: pkg2.dependencies ?? {},
|
|
9182
9326
|
devDependencies: pkg2.devDependencies ?? {}
|
|
@@ -9424,7 +9568,7 @@ function isDeepSpaceApp(dir) {
|
|
|
9424
9568
|
const packagePath = join23(dir, "package.json");
|
|
9425
9569
|
if (!existsSync23(packagePath)) return false;
|
|
9426
9570
|
try {
|
|
9427
|
-
const pkg2 = JSON.parse(
|
|
9571
|
+
const pkg2 = JSON.parse(readFileSync20(packagePath, "utf-8"));
|
|
9428
9572
|
return Boolean(pkg2.dependencies?.deepspace || pkg2.devDependencies?.deepspace);
|
|
9429
9573
|
} catch {
|
|
9430
9574
|
return false;
|
|
@@ -9896,10 +10040,10 @@ var domain_default = defineCommand5({
|
|
|
9896
10040
|
// src/cli/commands/app-files.ts
|
|
9897
10041
|
import { defineCommand as defineCommand6 } from "citty";
|
|
9898
10042
|
import { basename as basename4, resolve as resolve18 } from "path";
|
|
9899
|
-
import { existsSync as existsSync24, statSync as
|
|
10043
|
+
import { existsSync as existsSync24, statSync as statSync5 } from "fs";
|
|
9900
10044
|
|
|
9901
10045
|
// src/cli/lib/app-files-api.ts
|
|
9902
|
-
import { createWriteStream, openAsBlob, statSync as
|
|
10046
|
+
import { createWriteStream, openAsBlob, statSync as statSync4 } from "fs";
|
|
9903
10047
|
import { basename as basename3, extname } from "path";
|
|
9904
10048
|
import { Readable } from "stream";
|
|
9905
10049
|
import { pipeline } from "stream/promises";
|
|
@@ -10009,7 +10153,7 @@ Content-Type: ${contentType}\r
|
|
|
10009
10153
|
}
|
|
10010
10154
|
async function uploadAppFile(baseUrl, token, appId, localPath, key, onProgress) {
|
|
10011
10155
|
const path = filesPath(appId, `/upload?key=${encodeKeyPath(key)}`);
|
|
10012
|
-
const size =
|
|
10156
|
+
const size = statSync4(localPath).size;
|
|
10013
10157
|
if (size > MAX_APP_FILE_BYTES) {
|
|
10014
10158
|
throw new ApiError(oversizeMessage(size), 0, "too_large", path);
|
|
10015
10159
|
}
|
|
@@ -10175,7 +10319,7 @@ var put = defineDeepspaceCommand({
|
|
|
10175
10319
|
},
|
|
10176
10320
|
async run({ args }) {
|
|
10177
10321
|
const localPath = resolve18(String(args.file));
|
|
10178
|
-
if (!existsSync24(localPath) || !
|
|
10322
|
+
if (!existsSync24(localPath) || !statSync5(localPath).isFile()) {
|
|
10179
10323
|
throw new Refusal(`No such file: ${args.file}`, "file_not_found");
|
|
10180
10324
|
}
|
|
10181
10325
|
const key = requireKey(args.key ?? basename4(localPath));
|
|
@@ -10685,7 +10829,7 @@ var transfer_default = defineCommand8({
|
|
|
10685
10829
|
import { defineCommand as defineCommand9 } from "citty";
|
|
10686
10830
|
|
|
10687
10831
|
// src/cli/commands/_invoke-impl.ts
|
|
10688
|
-
import { readFileSync as
|
|
10832
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
10689
10833
|
import * as p15 from "@clack/prompts";
|
|
10690
10834
|
var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
10691
10835
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -10732,7 +10876,7 @@ async function resolveBody(opts) {
|
|
|
10732
10876
|
"no_stdin"
|
|
10733
10877
|
);
|
|
10734
10878
|
}
|
|
10735
|
-
raw = opts.bodyFile === "-" ? await readStreamText(process.stdin) :
|
|
10879
|
+
raw = opts.bodyFile === "-" ? await readStreamText(process.stdin) : readFileSync21(opts.bodyFile, "utf-8");
|
|
10736
10880
|
if (opts.bodyFile === "-" && raw.trim() === "") {
|
|
10737
10881
|
throw new Refusal(
|
|
10738
10882
|
"Nothing arrived on stdin \u2014 check the command feeding this one, or pass --body / a file path.",
|
|
@@ -10919,7 +11063,7 @@ async function runInvoke(args) {
|
|
|
10919
11063
|
} catch (err) {
|
|
10920
11064
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10921
11065
|
throw new Refusal(msg, "not_authenticated", {
|
|
10922
|
-
action:
|
|
11066
|
+
action: loginAction()
|
|
10923
11067
|
});
|
|
10924
11068
|
}
|
|
10925
11069
|
const controller = new AbortController();
|
|
@@ -10975,7 +11119,7 @@ async function runInvoke(args) {
|
|
|
10975
11119
|
delete rest.message;
|
|
10976
11120
|
delete rest.code;
|
|
10977
11121
|
throw new Refusal(lines.join("\n"), code, {
|
|
10978
|
-
...res.status === 401 ? { action:
|
|
11122
|
+
...res.status === 401 ? { action: loginAction() } : {},
|
|
10979
11123
|
extra: rest
|
|
10980
11124
|
});
|
|
10981
11125
|
}
|
|
@@ -11381,7 +11525,7 @@ async function callAgent(target2, path, init, timeout) {
|
|
|
11381
11525
|
throw new Refusal(
|
|
11382
11526
|
"Authentication was rejected. Run `deepspace auth login` and try again.",
|
|
11383
11527
|
"not_authenticated",
|
|
11384
|
-
{ action:
|
|
11528
|
+
{ action: loginAction() }
|
|
11385
11529
|
);
|
|
11386
11530
|
}
|
|
11387
11531
|
}
|
|
@@ -11472,7 +11616,7 @@ var agent_default = defineCommand10({
|
|
|
11472
11616
|
|
|
11473
11617
|
// src/cli/commands/feedback.ts
|
|
11474
11618
|
import * as p16 from "@clack/prompts";
|
|
11475
|
-
import { existsSync as existsSync25, readFileSync as
|
|
11619
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
|
|
11476
11620
|
import { dirname as dirname11, join as join24 } from "path";
|
|
11477
11621
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11478
11622
|
import { release } from "os";
|
|
@@ -11501,7 +11645,7 @@ function readCliVersion() {
|
|
|
11501
11645
|
];
|
|
11502
11646
|
for (const path of candidates) {
|
|
11503
11647
|
if (!existsSync25(path)) continue;
|
|
11504
|
-
const pkg2 = JSON.parse(
|
|
11648
|
+
const pkg2 = JSON.parse(readFileSync22(path, "utf-8"));
|
|
11505
11649
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
11506
11650
|
}
|
|
11507
11651
|
} catch {
|
|
@@ -11676,7 +11820,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
11676
11820
|
throw new Refusal(
|
|
11677
11821
|
err.message ?? "Not signed in. Run `deepspace auth login`.",
|
|
11678
11822
|
"not_authenticated",
|
|
11679
|
-
{ action:
|
|
11823
|
+
{ action: loginAction() }
|
|
11680
11824
|
);
|
|
11681
11825
|
}
|
|
11682
11826
|
const result = await api3(token, "/api/feedback", {
|
|
@@ -11697,7 +11841,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
11697
11841
|
|
|
11698
11842
|
// src/cli/commands/secrets.ts
|
|
11699
11843
|
import { defineCommand as defineCommand11 } from "citty";
|
|
11700
|
-
import { readFileSync as
|
|
11844
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
11701
11845
|
|
|
11702
11846
|
// src/cli/lib/citty-args.ts
|
|
11703
11847
|
function dedupePositionals(bound, rest) {
|
|
@@ -12012,7 +12156,7 @@ async function readUploadSource(file) {
|
|
|
12012
12156
|
return readStreamText(process.stdin, MAX_STDIN_BYTES);
|
|
12013
12157
|
}
|
|
12014
12158
|
try {
|
|
12015
|
-
return
|
|
12159
|
+
return readFileSync23(file, "utf-8");
|
|
12016
12160
|
} catch (err) {
|
|
12017
12161
|
const errno = err.code;
|
|
12018
12162
|
if (typeof errno !== "string" || errno.length === 0) throw err;
|
|
@@ -12062,47 +12206,6 @@ var download = defineCommand11({
|
|
|
12062
12206
|
process.stdout.write(formatSecretsDownload(secrets, format));
|
|
12063
12207
|
}
|
|
12064
12208
|
});
|
|
12065
|
-
var pull = defineCommand11({
|
|
12066
|
-
meta: { name: "pull", description: "Refresh the .dev.vars cache from the app store" },
|
|
12067
|
-
args: { ...COMMON_ARGS },
|
|
12068
|
-
async run({ args }) {
|
|
12069
|
-
const wranglerEnv = args.env?.trim() || void 0;
|
|
12070
|
-
const appDir = findAppDir();
|
|
12071
|
-
if (!appDir)
|
|
12072
|
-
throw new InputError(
|
|
12073
|
-
"Run from a DeepSpace app directory (one containing wrangler.toml).",
|
|
12074
|
-
"not_in_app_repo"
|
|
12075
|
-
);
|
|
12076
|
-
const t = await resolveTarget(args, { register: true });
|
|
12077
|
-
const ownerId = decodeJwtPayload(t.token).sub;
|
|
12078
|
-
const refreshed = await refreshSecretsCache(
|
|
12079
|
-
DEPLOY_URL12,
|
|
12080
|
-
t.token,
|
|
12081
|
-
t.appId,
|
|
12082
|
-
wranglerEnv,
|
|
12083
|
-
t.configName
|
|
12084
|
-
);
|
|
12085
|
-
try {
|
|
12086
|
-
await writeDevVars(appDir, ownerId, t.token, wranglerEnv, {
|
|
12087
|
-
appId: t.appId,
|
|
12088
|
-
generatedSecretsCache: refreshed.rendered
|
|
12089
|
-
});
|
|
12090
|
-
} catch (err) {
|
|
12091
|
-
if (args.app && err instanceof Refusal && err.code === "app_not_found") {
|
|
12092
|
-
throw new Refusal(err.message, err.code);
|
|
12093
|
-
}
|
|
12094
|
-
throw err;
|
|
12095
|
-
}
|
|
12096
|
-
const count = Object.keys(refreshed.pulled?.values ?? {}).length;
|
|
12097
|
-
ok(
|
|
12098
|
-
args.json === true,
|
|
12099
|
-
{ appId: t.appId, config: t.configName, pulled: count },
|
|
12100
|
-
() => console.log(
|
|
12101
|
-
refreshed.pulled ? `Pulled ${count} secrets (${t.configName}) into .dev.vars.` : `Config ${t.configName} does not exist yet; regenerated .dev.vars without app secrets.`
|
|
12102
|
-
)
|
|
12103
|
-
);
|
|
12104
|
-
}
|
|
12105
|
-
});
|
|
12106
12209
|
var configsList = defineCommand11({
|
|
12107
12210
|
meta: { name: "list", description: "List the app\u2019s configs" },
|
|
12108
12211
|
args: { ...COMMON_ARGS },
|
|
@@ -12212,7 +12315,6 @@ var secrets_default = defineCommand11({
|
|
|
12212
12315
|
delete: del2,
|
|
12213
12316
|
upload,
|
|
12214
12317
|
download,
|
|
12215
|
-
pull,
|
|
12216
12318
|
configs
|
|
12217
12319
|
}
|
|
12218
12320
|
});
|
|
@@ -12369,7 +12471,7 @@ var init_default = defineDeepspaceCommand({
|
|
|
12369
12471
|
// src/cli/commands/status.ts
|
|
12370
12472
|
import { defineCommand as defineCommand12 } from "citty";
|
|
12371
12473
|
import * as p17 from "@clack/prompts";
|
|
12372
|
-
import { existsSync as existsSync26, readFileSync as
|
|
12474
|
+
import { existsSync as existsSync26, readFileSync as readFileSync24 } from "fs";
|
|
12373
12475
|
function timeAgo(iso) {
|
|
12374
12476
|
const ms = Date.now() - Date.parse(iso);
|
|
12375
12477
|
if (!Number.isFinite(ms) || ms < 0) return iso;
|
|
@@ -12473,7 +12575,7 @@ var status_default = defineCommand12({
|
|
|
12473
12575
|
let undecodableToken = false;
|
|
12474
12576
|
try {
|
|
12475
12577
|
const payload = decodeJwtPayload(
|
|
12476
|
-
|
|
12578
|
+
readFileSync24(TOKEN_PATH, "utf-8").trim()
|
|
12477
12579
|
);
|
|
12478
12580
|
if (payload.email) who = payload.email;
|
|
12479
12581
|
userId = payload.sub ?? null;
|
|
@@ -13321,7 +13423,7 @@ var pull_default = defineDeepspaceCommand({
|
|
|
13321
13423
|
|
|
13322
13424
|
// src/cli/commands/clone.ts
|
|
13323
13425
|
import * as p20 from "@clack/prompts";
|
|
13324
|
-
import { existsSync as existsSync27, readdirSync as readdirSync9, rmSync as
|
|
13426
|
+
import { existsSync as existsSync27, readdirSync as readdirSync9, rmSync as rmSync9 } from "fs";
|
|
13325
13427
|
import { resolve as resolve19, basename as basename5, join as join25 } from "path";
|
|
13326
13428
|
function cleanFailedCloneDir(dir) {
|
|
13327
13429
|
let entries;
|
|
@@ -13332,7 +13434,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
13332
13434
|
}
|
|
13333
13435
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
13334
13436
|
try {
|
|
13335
|
-
|
|
13437
|
+
rmSync9(join25(dir, ".git"), { recursive: true, force: true });
|
|
13336
13438
|
return [];
|
|
13337
13439
|
} catch {
|
|
13338
13440
|
return entries;
|
|
@@ -13434,7 +13536,7 @@ var clone_default = defineDeepspaceCommand({
|
|
|
13434
13536
|
},
|
|
13435
13537
|
// One runnable follow-up instead of the old five-line "Next steps" block:
|
|
13436
13538
|
// nothing else in the clone works until the deps are installed. Secrets
|
|
13437
|
-
//
|
|
13539
|
+
// and `dev` (which refreshes `.dev.vars` itself) follow from there.
|
|
13438
13540
|
action: { cwd: dir, argv: [detectPackageManager(dir), "install"] }
|
|
13439
13541
|
};
|
|
13440
13542
|
}
|
|
@@ -13574,6 +13676,12 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
13574
13676
|
type: "boolean",
|
|
13575
13677
|
description: "Proceed even though the target release declares fewer Durable Object classes than the current one \u2014 THEIR STORED DATA IS DELETED.",
|
|
13576
13678
|
default: false
|
|
13679
|
+
},
|
|
13680
|
+
yes: {
|
|
13681
|
+
type: "boolean",
|
|
13682
|
+
alias: "y",
|
|
13683
|
+
description: "Skip the confirmation (required for --json / non-interactive)",
|
|
13684
|
+
default: false
|
|
13577
13685
|
}
|
|
13578
13686
|
},
|
|
13579
13687
|
async run({ args }) {
|
|
@@ -13605,7 +13713,15 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
13605
13713
|
if ("error" in picked) throw new Refusal(picked.error, picked.code);
|
|
13606
13714
|
releaseId = picked.releaseId;
|
|
13607
13715
|
}
|
|
13608
|
-
spinner2?.
|
|
13716
|
+
spinner2?.stop(`Rollback target: ${releaseId}`);
|
|
13717
|
+
await requireConsent({
|
|
13718
|
+
yes: Boolean(args.yes),
|
|
13719
|
+
json: Boolean(args.json),
|
|
13720
|
+
message: `This re-deploys release ${releaseId} as the live release of ${appId} (live secrets are kept, not the release's).`,
|
|
13721
|
+
prompt: `Roll ${appId} back to ${releaseId}?`,
|
|
13722
|
+
extra: { appId, releaseId }
|
|
13723
|
+
});
|
|
13724
|
+
spinner2?.start(`Rolling back to ${releaseId}\u2026`);
|
|
13609
13725
|
let result;
|
|
13610
13726
|
try {
|
|
13611
13727
|
result = await apiFetch(DEPLOY_URL15, token, `/api/deploy/${appId}/rollback`, {
|
|
@@ -13822,10 +13938,10 @@ import * as p24 from "@clack/prompts";
|
|
|
13822
13938
|
import {
|
|
13823
13939
|
existsSync as existsSync28,
|
|
13824
13940
|
mkdirSync as mkdirSync10,
|
|
13825
|
-
readFileSync as
|
|
13941
|
+
readFileSync as readFileSync25,
|
|
13826
13942
|
realpathSync as realpathSync6,
|
|
13827
13943
|
renameSync as renameSync2,
|
|
13828
|
-
statSync as
|
|
13944
|
+
statSync as statSync6,
|
|
13829
13945
|
writeFileSync as writeFileSync8
|
|
13830
13946
|
} from "fs";
|
|
13831
13947
|
import { dirname as dirname12, isAbsolute as isAbsolute6, join as join26, relative as relative4, sep as sep4 } from "path";
|
|
@@ -13885,7 +14001,7 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
13885
14001
|
const markerPath = worktreeMarkerPath(worktreeRoot);
|
|
13886
14002
|
if (!markerPath) return false;
|
|
13887
14003
|
try {
|
|
13888
|
-
const marker = JSON.parse(
|
|
14004
|
+
const marker = JSON.parse(readFileSync25(markerPath, "utf-8"));
|
|
13889
14005
|
return marker.version === 1 && marker.workspaceId === workspaceId && marker.mode === "managed-linked";
|
|
13890
14006
|
} catch {
|
|
13891
14007
|
return false;
|
|
@@ -13928,7 +14044,7 @@ function rematerializeWorkspaceWorktree(appDir, worktreeRoot, branch, workspaceI
|
|
|
13928
14044
|
function inOwnLinkedWorktree(appDir, id) {
|
|
13929
14045
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
13930
14046
|
try {
|
|
13931
|
-
return
|
|
14047
|
+
return statSync6(join26(repoToplevel(appDir), ".git")).isFile();
|
|
13932
14048
|
} catch {
|
|
13933
14049
|
return false;
|
|
13934
14050
|
}
|
|
@@ -14374,7 +14490,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
14374
14490
|
|
|
14375
14491
|
// src/cli/commands/workspace/attach.ts
|
|
14376
14492
|
import * as p26 from "@clack/prompts";
|
|
14377
|
-
import { existsSync as existsSync29, readdirSync as readdirSync10, realpathSync as realpathSync7, rmSync as
|
|
14493
|
+
import { existsSync as existsSync29, readdirSync as readdirSync10, realpathSync as realpathSync7, rmSync as rmSync10 } from "fs";
|
|
14378
14494
|
import { isAbsolute as isAbsolute8, resolve as resolve21 } from "path";
|
|
14379
14495
|
function samePath(a, b) {
|
|
14380
14496
|
const real = (p34) => {
|
|
@@ -14405,7 +14521,7 @@ function cleanFailedFreshAttachDir(dir) {
|
|
|
14405
14521
|
return entries;
|
|
14406
14522
|
}
|
|
14407
14523
|
try {
|
|
14408
|
-
|
|
14524
|
+
rmSync10(dir, { recursive: true, force: true });
|
|
14409
14525
|
return [];
|
|
14410
14526
|
} catch {
|
|
14411
14527
|
return entries.length > 0 ? entries : ["<cleanup-failed>"];
|
|
@@ -14941,13 +15057,13 @@ import * as p30 from "@clack/prompts";
|
|
|
14941
15057
|
|
|
14942
15058
|
// src/cli/lib/validation.ts
|
|
14943
15059
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
14944
|
-
import { readFileSync as
|
|
15060
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
14945
15061
|
import { join as join27 } from "path";
|
|
14946
15062
|
var MAX_SUMMARY_CHARS = 4e3;
|
|
14947
15063
|
var MAX_OUTPUT_BUFFER = 64 * 1024 * 1024;
|
|
14948
15064
|
function configuredCommand(appDir) {
|
|
14949
15065
|
try {
|
|
14950
|
-
const pkg2 = JSON.parse(
|
|
15066
|
+
const pkg2 = JSON.parse(readFileSync26(join27(appDir, "package.json"), "utf-8"));
|
|
14951
15067
|
if (pkg2.scripts?.validate) return `${detectPackageManager(appDir)} run --silent validate`;
|
|
14952
15068
|
} catch {
|
|
14953
15069
|
}
|
|
@@ -15899,13 +16015,13 @@ function reportSource(appId, state, json) {
|
|
|
15899
16015
|
|
|
15900
16016
|
// src/cli/commands/update.ts
|
|
15901
16017
|
import * as p33 from "@clack/prompts";
|
|
15902
|
-
import { existsSync as existsSync30, readFileSync as
|
|
16018
|
+
import { existsSync as existsSync30, readFileSync as readFileSync27 } from "fs";
|
|
15903
16019
|
import { join as join28, resolve as resolve22 } from "path";
|
|
15904
16020
|
|
|
15905
16021
|
// package.json
|
|
15906
16022
|
var package_default = {
|
|
15907
16023
|
name: "deepspace",
|
|
15908
|
-
version: "0.
|
|
16024
|
+
version: "0.30.0",
|
|
15909
16025
|
engines: {
|
|
15910
16026
|
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
15911
16027
|
},
|
|
@@ -16087,7 +16203,7 @@ function readManifest(appDir) {
|
|
|
16087
16203
|
throw new Refusal("This app has no package.json \u2014 nothing to update.", "not_in_app_repo");
|
|
16088
16204
|
}
|
|
16089
16205
|
try {
|
|
16090
|
-
return JSON.parse(
|
|
16206
|
+
return JSON.parse(readFileSync27(path, "utf8"));
|
|
16091
16207
|
} catch {
|
|
16092
16208
|
throw new Refusal("package.json must contain valid JSON.", "invalid_package_manifest");
|
|
16093
16209
|
}
|
|
@@ -16123,7 +16239,7 @@ function usersSchemaVisibilityUpgradeInstruction(appDir) {
|
|
|
16123
16239
|
const schemaName = "src/schemas/users-schema.ts";
|
|
16124
16240
|
const path = join28(appDir, schemaName);
|
|
16125
16241
|
if (!existsSync30(path)) return null;
|
|
16126
|
-
const source =
|
|
16242
|
+
const source = readFileSync27(path, "utf8");
|
|
16127
16243
|
if (!/\bmember\s*:\s*\{[^}]*\bread\s*:\s*true\b/s.test(source)) return null;
|
|
16128
16244
|
return `${schemaName}: review member user-row visibility at ${USERS_SCHEMA_VISIBILITY_GUIDE}; leave the app-owned schema unchanged until you choose its policy.`;
|
|
16129
16245
|
}
|
|
@@ -16223,7 +16339,7 @@ process.stdout.on("error", (error) => {
|
|
|
16223
16339
|
throw error;
|
|
16224
16340
|
});
|
|
16225
16341
|
var __dirname = dirname13(fileURLToPath3(import.meta.url));
|
|
16226
|
-
var pkg = JSON.parse(
|
|
16342
|
+
var pkg = JSON.parse(readFileSync28(join29(__dirname, "..", "package.json"), "utf-8"));
|
|
16227
16343
|
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync31("/etc/ssl/certs/ca-certificates.crt")) {
|
|
16228
16344
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
16229
16345
|
}
|