deepspace 0.29.0 → 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 +53 -0
- package/dist/{chunk-ZWFH5HON.js → chunk-DIG45T65.js} +2 -2
- package/dist/{chunk-ZWFH5HON.js.map → chunk-DIG45T65.js.map} +1 -1
- package/dist/cli.js +344 -179
- 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
|
|
|
@@ -301,6 +301,49 @@ function apiFetchReadWithRetry(baseUrl, token, path) {
|
|
|
301
301
|
function isTransientFailure(error) {
|
|
302
302
|
return error instanceof ApiError && (error.status === 0 || error.status === 408 || error.status === 429 || error.status >= 500);
|
|
303
303
|
}
|
|
304
|
+
async function fetchIntegrationCatalog(baseUrl, opts = {}) {
|
|
305
|
+
const path = opts.summary ? "/api/integrations?summary=1" : "/api/integrations";
|
|
306
|
+
let res;
|
|
307
|
+
try {
|
|
308
|
+
res = await fetch(`${baseUrl}${path}`, { signal: AbortSignal.timeout(15e3) });
|
|
309
|
+
} catch (err) {
|
|
310
|
+
throw new ApiError(
|
|
311
|
+
`Could not fetch the integration catalog: ${err instanceof Error ? err.message : String(err)}`,
|
|
312
|
+
0,
|
|
313
|
+
"catalog_unavailable",
|
|
314
|
+
path
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
if (!res.ok) {
|
|
318
|
+
throw new ApiError(
|
|
319
|
+
`Failed to fetch integration catalog (${res.status})`,
|
|
320
|
+
res.status,
|
|
321
|
+
"catalog_unavailable",
|
|
322
|
+
path
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
let value;
|
|
326
|
+
try {
|
|
327
|
+
value = await res.json();
|
|
328
|
+
} catch {
|
|
329
|
+
throw new ApiError(
|
|
330
|
+
"The integration catalog returned invalid JSON.",
|
|
331
|
+
res.status,
|
|
332
|
+
"invalid_catalog",
|
|
333
|
+
path
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
const integrations = value?.integrations;
|
|
337
|
+
if (!integrations || typeof integrations !== "object" || Array.isArray(integrations)) {
|
|
338
|
+
throw new ApiError(
|
|
339
|
+
"The integration catalog returned an invalid shape.",
|
|
340
|
+
res.status,
|
|
341
|
+
"invalid_catalog",
|
|
342
|
+
path
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return value;
|
|
346
|
+
}
|
|
304
347
|
|
|
305
348
|
// src/cli/lib/cli-errors.ts
|
|
306
349
|
var InputError = class extends Error {
|
|
@@ -664,9 +707,13 @@ function appDomainForEnv(env) {
|
|
|
664
707
|
return env === "production" ? "app.space" : env === "staging" ? "spacestest.com" : null;
|
|
665
708
|
}
|
|
666
709
|
var PLATFORM_URLS = DEEPSPACE_ENV === "production" ? PROD_URLS : DEEPSPACE_ENV === "staging" ? STAGING_URLS : INVALID_URLS;
|
|
710
|
+
var PLANE_URLS = {
|
|
711
|
+
production: PROD_URLS,
|
|
712
|
+
staging: STAGING_URLS
|
|
713
|
+
};
|
|
667
714
|
var PLANE_AUTH_URLS = {
|
|
668
|
-
production:
|
|
669
|
-
staging:
|
|
715
|
+
production: PLANE_URLS.production.auth,
|
|
716
|
+
staging: PLANE_URLS.staging.auth
|
|
670
717
|
};
|
|
671
718
|
function effectivePlatformUrls(env = process.env) {
|
|
672
719
|
return {
|
|
@@ -807,6 +854,10 @@ async function ensureToken(options = {}) {
|
|
|
807
854
|
throw notAuthenticated("The stored session is no longer valid (expired or unreadable)");
|
|
808
855
|
return token;
|
|
809
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
|
+
}
|
|
810
861
|
function notAuthenticated(state) {
|
|
811
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})`;
|
|
812
863
|
const elsewhere = Object.entries(PLANE_AUTH_URLS).filter(([, url]) => url !== AUTH_URL && existsSync(credentialPaths(url).sessionPath)).map(([plane]) => plane);
|
|
@@ -818,7 +869,7 @@ function notAuthenticated(state) {
|
|
|
818
869
|
return new Refusal(
|
|
819
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).`,
|
|
820
871
|
"not_authenticated",
|
|
821
|
-
{ action:
|
|
872
|
+
{ action: loginAction() }
|
|
822
873
|
);
|
|
823
874
|
}
|
|
824
875
|
function isTokenValid(jwt, minimumValidityMs) {
|
|
@@ -959,7 +1010,7 @@ var login_default = defineDeepspaceCommand({
|
|
|
959
1010
|
"Login timed out. Run `deepspace auth login` to try again.",
|
|
960
1011
|
"login_timeout",
|
|
961
1012
|
{
|
|
962
|
-
action:
|
|
1013
|
+
action: loginAction()
|
|
963
1014
|
}
|
|
964
1015
|
);
|
|
965
1016
|
}
|
|
@@ -1031,14 +1082,14 @@ async function createCliLoginSession(codeChallenge) {
|
|
|
1031
1082
|
throw new Refusal(
|
|
1032
1083
|
`Could not reach the auth service to create a login session: ${error instanceof Error ? error.message : String(error)}`,
|
|
1033
1084
|
"login_session_unreachable",
|
|
1034
|
-
{ action:
|
|
1085
|
+
{ action: loginAction() }
|
|
1035
1086
|
);
|
|
1036
1087
|
}
|
|
1037
1088
|
if (!sessionRes.ok) {
|
|
1038
1089
|
throw new Refusal(
|
|
1039
1090
|
`Could not create login session (${sessionRes.status})`,
|
|
1040
1091
|
"login_session_failed",
|
|
1041
|
-
{ action:
|
|
1092
|
+
{ action: loginAction() }
|
|
1042
1093
|
);
|
|
1043
1094
|
}
|
|
1044
1095
|
const sessionData = await sessionRes.json().catch(() => ({}));
|
|
@@ -1046,7 +1097,7 @@ async function createCliLoginSession(codeChallenge) {
|
|
|
1046
1097
|
throw new Refusal(
|
|
1047
1098
|
"Could not create login session \u2014 the auth server returned no session id or login url.",
|
|
1048
1099
|
"login_session_failed",
|
|
1049
|
-
{ action:
|
|
1100
|
+
{ action: loginAction() }
|
|
1050
1101
|
);
|
|
1051
1102
|
}
|
|
1052
1103
|
return { sessionId: sessionData.sessionId, loginUrl: sessionData.loginUrl };
|
|
@@ -2724,7 +2775,7 @@ async function fetchAppIdentityToken(deployUrl, callerJwt, appId) {
|
|
|
2724
2775
|
// wrangler env, and a bare `app init` under --env would target the
|
|
2725
2776
|
// TOP-LEVEL [vars] slot. dev/test/deploy attach the env-aware
|
|
2726
2777
|
// remedy as a structured action; surfaces without an action channel
|
|
2727
|
-
//
|
|
2778
|
+
// fall back to the
|
|
2728
2779
|
// app_not_found hint (check the id / `deepspace app list`).
|
|
2729
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.`,
|
|
2730
2781
|
404,
|
|
@@ -2758,7 +2809,7 @@ async function fetchAppIdentityToken(deployUrl, callerJwt, appId) {
|
|
|
2758
2809
|
// src/cli/lib/dev-vars.ts
|
|
2759
2810
|
var HEADER = [
|
|
2760
2811
|
"# Generated by deepspace \u2014 do not edit; this file is rewritten on every",
|
|
2761
|
-
"# dev, test,
|
|
2812
|
+
"# dev, test, and deploy run. App values live in the secret store:",
|
|
2762
2813
|
"# npx deepspace secrets set KEY=value"
|
|
2763
2814
|
].join("\n");
|
|
2764
2815
|
function requireAppIdFor(appDir, wranglerEnv) {
|
|
@@ -3006,6 +3057,15 @@ function canonicalPath2(path) {
|
|
|
3006
3057
|
return resolve7(path);
|
|
3007
3058
|
}
|
|
3008
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
|
+
}
|
|
3009
3069
|
|
|
3010
3070
|
// src/cli/lib/preflight.ts
|
|
3011
3071
|
import { execFileSync } from "child_process";
|
|
@@ -3077,6 +3137,8 @@ function removeMacosJunk(dir) {
|
|
|
3077
3137
|
|
|
3078
3138
|
// src/server/rooms/binding-manifest.ts
|
|
3079
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}}$`);
|
|
3080
3142
|
var AUTO_PROVISION_SENTINEL = "auto";
|
|
3081
3143
|
var VECTORIZE_METRICS = /* @__PURE__ */ new Set(["cosine", "euclidean", "dot-product"]);
|
|
3082
3144
|
var ALLOWED_BINDING_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -3137,6 +3199,12 @@ function validateBindingManifest(manifest) {
|
|
|
3137
3199
|
errors.push({ reason: `Binding of type "${type}" missing 'name' (string)` });
|
|
3138
3200
|
continue;
|
|
3139
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
|
+
}
|
|
3140
3208
|
if (RESERVED_BINDING_NAMES.has(name)) {
|
|
3141
3209
|
errors.push({ reason: `Binding name "${name}" is reserved by the SDK` });
|
|
3142
3210
|
continue;
|
|
@@ -3378,7 +3446,6 @@ var RESERVED_SECRET_NAMES = /* @__PURE__ */ new Set([
|
|
|
3378
3446
|
"API_WORKER_URL",
|
|
3379
3447
|
"PLATFORM_WORKER_URL"
|
|
3380
3448
|
]);
|
|
3381
|
-
var SECRET_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3382
3449
|
var CONFIG_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
3383
3450
|
var MAX_SECRET_VALUE_BYTES = 32 * 1024;
|
|
3384
3451
|
function validateConfigName(configName) {
|
|
@@ -3391,6 +3458,12 @@ function validateConfigName(configName) {
|
|
|
3391
3458
|
return configName;
|
|
3392
3459
|
}
|
|
3393
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
|
+
}
|
|
3394
3467
|
if (!SECRET_NAME_RE.test(name)) {
|
|
3395
3468
|
throw new InputError(
|
|
3396
3469
|
`Invalid secret name "${name}". Use letters, numbers, and underscores; start with a letter or underscore.`,
|
|
@@ -3946,7 +4019,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
3946
4019
|
token = await ensureToken();
|
|
3947
4020
|
} catch (err) {
|
|
3948
4021
|
throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
|
|
3949
|
-
action:
|
|
4022
|
+
action: loginAction()
|
|
3950
4023
|
});
|
|
3951
4024
|
}
|
|
3952
4025
|
let payload;
|
|
@@ -3956,7 +4029,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
3956
4029
|
throw new Refusal(
|
|
3957
4030
|
"Malformed session token. Run `npx deepspace auth login`.",
|
|
3958
4031
|
"not_authenticated",
|
|
3959
|
-
{ action:
|
|
4032
|
+
{ action: loginAction() }
|
|
3960
4033
|
);
|
|
3961
4034
|
}
|
|
3962
4035
|
say(`Logged in as ${payload.name ?? payload.email}`);
|
|
@@ -4333,7 +4406,7 @@ function isAlive(pid) {
|
|
|
4333
4406
|
}
|
|
4334
4407
|
|
|
4335
4408
|
// src/cli/commands/test.ts
|
|
4336
|
-
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";
|
|
4337
4410
|
import { join as join14, relative as relative2, resolve as resolve10, sep as sep2 } from "path";
|
|
4338
4411
|
import { sync as spawnSync5 } from "cross-spawn";
|
|
4339
4412
|
|
|
@@ -4591,12 +4664,39 @@ function playwrightTestArgs(testFiles, flags = {}) {
|
|
|
4591
4664
|
"tests/playwright.config.ts",
|
|
4592
4665
|
"--output",
|
|
4593
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",
|
|
4594
4671
|
...flags.grep ? ["--grep", flags.grep] : [],
|
|
4595
4672
|
...flags.project ? ["--project", flags.project] : [],
|
|
4596
4673
|
...flags.headed ? ["--headed"] : [],
|
|
4597
4674
|
...testFiles
|
|
4598
4675
|
];
|
|
4599
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
|
+
}
|
|
4600
4700
|
var test_default = defineDeepspaceCommand({
|
|
4601
4701
|
meta: {
|
|
4602
4702
|
name: "test",
|
|
@@ -4670,7 +4770,7 @@ var test_default = defineDeepspaceCommand({
|
|
|
4670
4770
|
throw new Refusal(
|
|
4671
4771
|
err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.",
|
|
4672
4772
|
"not_authenticated",
|
|
4673
|
-
{ action:
|
|
4773
|
+
{ action: loginAction() }
|
|
4674
4774
|
);
|
|
4675
4775
|
}
|
|
4676
4776
|
let generatedSecretsCache;
|
|
@@ -4706,15 +4806,21 @@ var test_default = defineDeepspaceCommand({
|
|
|
4706
4806
|
}
|
|
4707
4807
|
let exitCode = 0;
|
|
4708
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
|
+
};
|
|
4709
4815
|
switch (suite) {
|
|
4710
4816
|
case "smoke":
|
|
4711
|
-
exitCode =
|
|
4817
|
+
exitCode = playwright(["tests/smoke.spec.ts"]);
|
|
4712
4818
|
break;
|
|
4713
4819
|
case "api":
|
|
4714
|
-
exitCode =
|
|
4820
|
+
exitCode = playwright(["tests/api.spec.ts"]);
|
|
4715
4821
|
break;
|
|
4716
4822
|
case "e2e":
|
|
4717
|
-
exitCode =
|
|
4823
|
+
exitCode = playwright([]);
|
|
4718
4824
|
break;
|
|
4719
4825
|
case "unit":
|
|
4720
4826
|
if (forwarded.grep || forwarded.project || forwarded.headed) {
|
|
@@ -4728,12 +4834,12 @@ var test_default = defineDeepspaceCommand({
|
|
|
4728
4834
|
exitCode = runVitest(appDir, wranglerEnv);
|
|
4729
4835
|
if (exitCode === 0) {
|
|
4730
4836
|
await ensurePortFree(port, "0.0.0.0");
|
|
4731
|
-
exitCode =
|
|
4837
|
+
exitCode = playwright([]);
|
|
4732
4838
|
}
|
|
4733
4839
|
break;
|
|
4734
4840
|
case "default":
|
|
4735
4841
|
skippedSpecs = specsSkippedByDefaultSuite(appDir);
|
|
4736
|
-
exitCode =
|
|
4842
|
+
exitCode = playwright([...DEFAULT_SUITE_SPECS]);
|
|
4737
4843
|
if (skippedSpecs.length > 0) {
|
|
4738
4844
|
say(
|
|
4739
4845
|
`skipped ${skippedSpecs.length} spec file(s) not in smoke+api (${skippedSpecs.join(", ")}) \u2014 run 'deepspace test run all'`
|
|
@@ -4749,7 +4855,7 @@ var test_default = defineDeepspaceCommand({
|
|
|
4749
4855
|
"spec_not_found"
|
|
4750
4856
|
);
|
|
4751
4857
|
}
|
|
4752
|
-
exitCode =
|
|
4858
|
+
exitCode = playwright([suite]);
|
|
4753
4859
|
} else {
|
|
4754
4860
|
throw new Refusal(
|
|
4755
4861
|
`Unknown test suite: ${suite}
|
|
@@ -4758,12 +4864,20 @@ Available: smoke, api, e2e, unit, all \u2014 or a path to one spec file (tests/<
|
|
|
4758
4864
|
);
|
|
4759
4865
|
}
|
|
4760
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
|
+
}
|
|
4761
4873
|
if (exitCode !== 0) {
|
|
4762
4874
|
throw new Refusal(`Test suite '${suite}' failed (exit ${exitCode}).`, "tests_failed", {
|
|
4763
|
-
extra: { suite, port, exitCode, skippedSpecs }
|
|
4875
|
+
extra: { suite, port, exitCode, skippedSpecs, skippedTests }
|
|
4764
4876
|
});
|
|
4765
4877
|
}
|
|
4766
|
-
return {
|
|
4878
|
+
return {
|
|
4879
|
+
data: { suite, port, appDir, wranglerEnv: wranglerEnv ?? null, skippedSpecs, skippedTests }
|
|
4880
|
+
};
|
|
4767
4881
|
}
|
|
4768
4882
|
});
|
|
4769
4883
|
function runSuite(appDir, argv, wranglerEnv, extraEnv = {}) {
|
|
@@ -4788,10 +4902,19 @@ function runSuite(appDir, argv, wranglerEnv, extraEnv = {}) {
|
|
|
4788
4902
|
}
|
|
4789
4903
|
}
|
|
4790
4904
|
function runPlaywright(appDir, testFiles, port, wranglerEnv, flags = {}) {
|
|
4791
|
-
|
|
4905
|
+
const resultsPath = join14(appDir, ".deepspace", "playwright-results.json");
|
|
4906
|
+
rmSync6(resultsPath, { force: true });
|
|
4907
|
+
const exitCode = runSuite(appDir, playwrightTestArgs(testFiles, flags), wranglerEnv, {
|
|
4792
4908
|
DEEPSPACE_PORT: String(port),
|
|
4793
|
-
PLAYWRIGHT_HTML_OUTPUT_DIR: ".deepspace/playwright-report"
|
|
4909
|
+
PLAYWRIGHT_HTML_OUTPUT_DIR: ".deepspace/playwright-report",
|
|
4910
|
+
PLAYWRIGHT_JSON_OUTPUT_FILE: resultsPath
|
|
4794
4911
|
});
|
|
4912
|
+
let raw = "";
|
|
4913
|
+
try {
|
|
4914
|
+
raw = readFileSync13(resultsPath, "utf-8");
|
|
4915
|
+
} catch {
|
|
4916
|
+
}
|
|
4917
|
+
return { exitCode, skippedTests: skippedTestsFromPlaywrightJson(raw) };
|
|
4795
4918
|
}
|
|
4796
4919
|
function runVitest(appDir, wranglerEnv) {
|
|
4797
4920
|
return runSuite(appDir, ["vitest", "run", "--passWithNoTests"], wranglerEnv);
|
|
@@ -5405,14 +5528,30 @@ var CONSECUTIVE_MATCHES = 10;
|
|
|
5405
5528
|
var MATCH_INTERVAL_MS = 250;
|
|
5406
5529
|
async function waitForLiveRelease(url, releaseStamp, timeoutMs) {
|
|
5407
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) {
|
|
5408
5549
|
const deadline = Date.now() + timeoutMs;
|
|
5409
5550
|
let attempt = 0;
|
|
5410
5551
|
let streak = 0;
|
|
5411
5552
|
while (Date.now() < deadline) {
|
|
5412
5553
|
attempt++;
|
|
5413
|
-
|
|
5414
|
-
probe.searchParams.set("probe", `${Date.now()}-${attempt}`);
|
|
5415
|
-
if (await servesRelease(probe, releaseStamp)) {
|
|
5554
|
+
if (await probe(attempt)) {
|
|
5416
5555
|
streak++;
|
|
5417
5556
|
if (streak >= CONSECUTIVE_MATCHES) return "confirmed";
|
|
5418
5557
|
await sleep2(MATCH_INTERVAL_MS);
|
|
@@ -5423,11 +5562,16 @@ async function waitForLiveRelease(url, releaseStamp, timeoutMs) {
|
|
|
5423
5562
|
}
|
|
5424
5563
|
return "unconfirmed";
|
|
5425
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
|
+
}
|
|
5426
5570
|
async function servesRelease(probe, releaseStamp) {
|
|
5427
|
-
const
|
|
5428
|
-
if (
|
|
5571
|
+
const result = await getOnFreshConnection(probe);
|
|
5572
|
+
if (result === null || result.statusCode !== 200) return false;
|
|
5429
5573
|
try {
|
|
5430
|
-
return JSON.parse(body).release === releaseStamp;
|
|
5574
|
+
return JSON.parse(result.body).release === releaseStamp;
|
|
5431
5575
|
} catch {
|
|
5432
5576
|
return false;
|
|
5433
5577
|
}
|
|
@@ -5439,17 +5583,13 @@ function getOnFreshConnection(url, timeoutMs = 5e3) {
|
|
|
5439
5583
|
url,
|
|
5440
5584
|
{ method: "GET", agent: false, timeout: timeoutMs, headers: { "cache-control": "no-cache" } },
|
|
5441
5585
|
(response) => {
|
|
5442
|
-
|
|
5443
|
-
response.resume();
|
|
5444
|
-
resolve23(null);
|
|
5445
|
-
return;
|
|
5446
|
-
}
|
|
5586
|
+
const statusCode = response.statusCode ?? 0;
|
|
5447
5587
|
let body = "";
|
|
5448
5588
|
response.setEncoding("utf8");
|
|
5449
5589
|
response.on("data", (chunk) => {
|
|
5450
5590
|
if (body.length < 4096) body += chunk;
|
|
5451
5591
|
});
|
|
5452
|
-
response.on("end", () => resolve23(body));
|
|
5592
|
+
response.on("end", () => resolve23({ statusCode, body }));
|
|
5453
5593
|
response.on("error", () => resolve23(null));
|
|
5454
5594
|
}
|
|
5455
5595
|
);
|
|
@@ -5533,7 +5673,7 @@ function describeFilesFailure(status3, body) {
|
|
|
5533
5673
|
import * as p6 from "@clack/prompts";
|
|
5534
5674
|
import { execSync as execSync2 } from "child_process";
|
|
5535
5675
|
import { createHash as createHash2 } from "crypto";
|
|
5536
|
-
import { existsSync as existsSync20, readFileSync as
|
|
5676
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16, readdirSync as readdirSync7 } from "fs";
|
|
5537
5677
|
import { dirname as dirname7, isAbsolute as isAbsolute4, join as join18, relative as relative3, resolve as resolve14, sep as sep3 } from "path";
|
|
5538
5678
|
|
|
5539
5679
|
// src/build/app-id.ts
|
|
@@ -5564,7 +5704,7 @@ function removeBuildDevVars(workerDir) {
|
|
|
5564
5704
|
}
|
|
5565
5705
|
|
|
5566
5706
|
// src/documentation/deploy.ts
|
|
5567
|
-
import { existsSync as existsSync18, readFileSync as
|
|
5707
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
5568
5708
|
import { join as join16 } from "path";
|
|
5569
5709
|
function readDocumentationDeployManifest(appDir, clientDir) {
|
|
5570
5710
|
if (!existsSync18(join16(appDir, "documentation.json"))) return void 0;
|
|
@@ -5574,11 +5714,11 @@ function readDocumentationDeployManifest(appDir, clientDir) {
|
|
|
5574
5714
|
"documentation.json exists but the build produced no documentation manifest. Ensure vite.config.ts includes deepSpaceDocumentation() from deepspace/documentation."
|
|
5575
5715
|
);
|
|
5576
5716
|
}
|
|
5577
|
-
return JSON.parse(
|
|
5717
|
+
return JSON.parse(readFileSync14(manifestPath, "utf8"));
|
|
5578
5718
|
}
|
|
5579
5719
|
|
|
5580
5720
|
// src/cli/commands/update/app-migrations.ts
|
|
5581
|
-
import { existsSync as existsSync19, readFileSync as
|
|
5721
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "fs";
|
|
5582
5722
|
import { join as join17 } from "path";
|
|
5583
5723
|
|
|
5584
5724
|
// src/shared/protocol/app-migrations.ts
|
|
@@ -5657,7 +5797,7 @@ function readAppliedAppMigrations(appDir) {
|
|
|
5657
5797
|
if (!existsSync19(path)) return [];
|
|
5658
5798
|
let parsed;
|
|
5659
5799
|
try {
|
|
5660
|
-
parsed = JSON.parse(
|
|
5800
|
+
parsed = JSON.parse(readFileSync15(path, "utf8"));
|
|
5661
5801
|
} catch {
|
|
5662
5802
|
throw new Refusal(
|
|
5663
5803
|
`${APP_MIGRATIONS_MANIFEST} must contain valid JSON`,
|
|
@@ -5723,12 +5863,12 @@ async function buildDeployBundle(options) {
|
|
|
5723
5863
|
"build_output_missing"
|
|
5724
5864
|
);
|
|
5725
5865
|
}
|
|
5726
|
-
const deployConfig = JSON.parse(
|
|
5866
|
+
const deployConfig = JSON.parse(readFileSync16(deployConfigPath, "utf-8"));
|
|
5727
5867
|
const outputWranglerPath = resolve14(dirname7(deployConfigPath), deployConfig.configPath);
|
|
5728
5868
|
if (!existsSync20(outputWranglerPath)) {
|
|
5729
5869
|
output.die(`Output wrangler.json not found at ${outputWranglerPath}`, "build_output_missing");
|
|
5730
5870
|
}
|
|
5731
|
-
const outputConfig = JSON.parse(
|
|
5871
|
+
const outputConfig = JSON.parse(readFileSync16(outputWranglerPath, "utf-8"));
|
|
5732
5872
|
if (outputConfig.name && outputConfig.name !== appName) {
|
|
5733
5873
|
const envHint = envName ? ` (--env ${envName})` : "";
|
|
5734
5874
|
output.die(
|
|
@@ -5829,7 +5969,7 @@ function collectWorkerBundle(workerDir, mainPath, clientDir) {
|
|
|
5829
5969
|
if (entry.isDirectory()) {
|
|
5830
5970
|
walk(fullPath);
|
|
5831
5971
|
} else if (entry.isFile() && WORKER_ES_MODULE.test(entry.name)) {
|
|
5832
|
-
modules.push({ name: moduleName(root, fullPath), content:
|
|
5972
|
+
modules.push({ name: moduleName(root, fullPath), content: readFileSync16(fullPath, "utf-8") });
|
|
5833
5973
|
}
|
|
5834
5974
|
}
|
|
5835
5975
|
};
|
|
@@ -5883,7 +6023,7 @@ function clientAppIdRefusal(assets, appId, envName) {
|
|
|
5883
6023
|
for (const asset of assets) {
|
|
5884
6024
|
if (!CLIENT_CODE_ASSET.test(asset.path)) continue;
|
|
5885
6025
|
if (DOCUMENTATION_OUTPUT.test(asset.path)) continue;
|
|
5886
|
-
const source =
|
|
6026
|
+
const source = readFileSync16(asset.sourcePath, "utf-8");
|
|
5887
6027
|
if (unsubstituted === void 0 && source.includes(APP_ID_DEFINE)) unsubstituted = asset.path;
|
|
5888
6028
|
for (const found of source.matchAll(APP_ID_LITERAL)) {
|
|
5889
6029
|
if (found[0] !== appId && !foreign.has(found[0])) foreign.set(found[0], asset.path);
|
|
@@ -5917,7 +6057,7 @@ function collectAssets(dir) {
|
|
|
5917
6057
|
if (entry.isDirectory()) {
|
|
5918
6058
|
walk(fullPath, relativePath);
|
|
5919
6059
|
} else {
|
|
5920
|
-
const bytes =
|
|
6060
|
+
const bytes = readFileSync16(fullPath);
|
|
5921
6061
|
assets.push({
|
|
5922
6062
|
path: `/${relativePath}`,
|
|
5923
6063
|
hash: createHash2("sha256").update(bytes).digest("hex"),
|
|
@@ -5938,7 +6078,7 @@ function readDeployAssetConfig(clientDir) {
|
|
|
5938
6078
|
]) {
|
|
5939
6079
|
const filePath = join18(clientDir, file);
|
|
5940
6080
|
if (!existsSync20(filePath)) continue;
|
|
5941
|
-
const content =
|
|
6081
|
+
const content = readFileSync16(filePath, "utf8");
|
|
5942
6082
|
if (content.trim()) config[key] = content;
|
|
5943
6083
|
}
|
|
5944
6084
|
return config;
|
|
@@ -6263,7 +6403,7 @@ function createDeployOutput(json) {
|
|
|
6263
6403
|
|
|
6264
6404
|
// src/cli/commands/deploy/request.ts
|
|
6265
6405
|
import * as p11 from "@clack/prompts";
|
|
6266
|
-
import { readFileSync as
|
|
6406
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
6267
6407
|
|
|
6268
6408
|
// src/cli/commands/deploy/repository.ts
|
|
6269
6409
|
import * as p9 from "@clack/prompts";
|
|
@@ -7434,7 +7574,7 @@ async function uploadDeployAssetsWithAuth(options, auth2) {
|
|
|
7434
7574
|
// against the plan before it touches storage, and a stream body
|
|
7435
7575
|
// would be sent chunked with no length at all; a retry also needs a
|
|
7436
7576
|
// body it can send again.
|
|
7437
|
-
body:
|
|
7577
|
+
body: readFileSync17(asset.sourcePath)
|
|
7438
7578
|
}),
|
|
7439
7579
|
{ attempts: ASSET_UPLOAD_ATTEMPTS, timeoutMs: ASSET_UPLOAD_ATTEMPT_TIMEOUT_MS }
|
|
7440
7580
|
)
|
|
@@ -7479,7 +7619,10 @@ function isDeployServiceResourceLimit(status3, error) {
|
|
|
7479
7619
|
}
|
|
7480
7620
|
function formatDeployWorkerError(status3, error, code) {
|
|
7481
7621
|
const detail = error ?? `Deployment error (${status3})`;
|
|
7482
|
-
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") {
|
|
7483
7626
|
return detail;
|
|
7484
7627
|
}
|
|
7485
7628
|
if (isDeployServiceResourceLimit(status3, error)) {
|
|
@@ -7506,8 +7649,9 @@ function errorMessage5(error) {
|
|
|
7506
7649
|
|
|
7507
7650
|
// src/cli/commands/deploy/lock.ts
|
|
7508
7651
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
7509
|
-
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";
|
|
7510
7653
|
import { dirname as dirname8, join as join20 } from "path";
|
|
7654
|
+
var DEPLOY_LOCK_MAX_AGE_MS = 10 * 6e4;
|
|
7511
7655
|
function deployLockPath(appDir) {
|
|
7512
7656
|
return join20(appDir, ".deepspace", "deploy.lock");
|
|
7513
7657
|
}
|
|
@@ -7519,29 +7663,58 @@ function acquireDeployLock(appDir) {
|
|
|
7519
7663
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7520
7664
|
token: randomUUID2()
|
|
7521
7665
|
};
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
|
|
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
|
+
}
|
|
7534
7687
|
}
|
|
7535
|
-
|
|
7536
|
-
|
|
7688
|
+
);
|
|
7689
|
+
}
|
|
7537
7690
|
}
|
|
7538
|
-
|
|
7539
|
-
|
|
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);
|
|
7540
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);
|
|
7541
7714
|
}
|
|
7542
7715
|
function readLock(path) {
|
|
7543
7716
|
try {
|
|
7544
|
-
const parsed = JSON.parse(
|
|
7717
|
+
const parsed = JSON.parse(readFileSync18(path, "utf-8"));
|
|
7545
7718
|
return typeof parsed.pid === "number" && typeof parsed.startedAt === "string" && typeof parsed.token === "string" ? { pid: parsed.pid, startedAt: parsed.startedAt, token: parsed.token } : null;
|
|
7546
7719
|
} catch {
|
|
7547
7720
|
return null;
|
|
@@ -7776,11 +7949,20 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7776
7949
|
);
|
|
7777
7950
|
}
|
|
7778
7951
|
let serving = "unverifiable";
|
|
7952
|
+
let dataPlane = "unconfirmed";
|
|
7779
7953
|
const edgeWaitStarted = Date.now();
|
|
7780
7954
|
if (body.url) {
|
|
7781
7955
|
spinner2.message("Waiting for the edge to serve this release...");
|
|
7782
7956
|
serving = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
7783
|
-
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
|
+
}
|
|
7784
7966
|
if (serving !== "confirmed") {
|
|
7785
7967
|
spinner2.stop(
|
|
7786
7968
|
serving === "unconfirmed" ? "Deployed \u2014 the edge is still rolling this release out" : "Deployed \u2014 serving could not be verified from here"
|
|
@@ -7799,6 +7981,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7799
7981
|
releaseId: body.releaseId ?? null,
|
|
7800
7982
|
bundleRetained: body.bundleRetained ?? null,
|
|
7801
7983
|
serving,
|
|
7984
|
+
dataPlane,
|
|
7802
7985
|
recoverable: repository.recoverable,
|
|
7803
7986
|
...worktree,
|
|
7804
7987
|
...renameFields,
|
|
@@ -7810,7 +7993,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7810
7993
|
}
|
|
7811
7994
|
}
|
|
7812
7995
|
spinner2.stop(
|
|
7813
|
-
`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)`
|
|
7814
7997
|
);
|
|
7815
7998
|
p12.log.success(`Live at: ${body.url}`);
|
|
7816
7999
|
await syncPostDeployCommerce(appDir, appId, output.nonInteractive);
|
|
@@ -7823,6 +8006,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
|
|
|
7823
8006
|
// Always present, so a caller branches on one field instead of
|
|
7824
8007
|
// inferring success from an absent one.
|
|
7825
8008
|
serving,
|
|
8009
|
+
dataPlane,
|
|
7826
8010
|
releaseId: body.releaseId ?? null,
|
|
7827
8011
|
bundleRetained: body.bundleRetained ?? null,
|
|
7828
8012
|
recoverable: repository.recoverable,
|
|
@@ -7952,7 +8136,7 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
7952
8136
|
token = await ensureToken();
|
|
7953
8137
|
} catch (err) {
|
|
7954
8138
|
throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
|
|
7955
|
-
action:
|
|
8139
|
+
action: loginAction()
|
|
7956
8140
|
});
|
|
7957
8141
|
}
|
|
7958
8142
|
let appId;
|
|
@@ -8023,13 +8207,20 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
8023
8207
|
}
|
|
8024
8208
|
const hosts = body.releasedHosts ?? [];
|
|
8025
8209
|
const alreadyUndeployed = hosts.length === 0;
|
|
8026
|
-
|
|
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
|
+
);
|
|
8027
8218
|
if (!args.json) {
|
|
8028
8219
|
p13.outro(
|
|
8029
|
-
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.`
|
|
8030
8221
|
);
|
|
8031
8222
|
}
|
|
8032
|
-
return { data: { appId, releasedHosts: hosts, alreadyUndeployed } };
|
|
8223
|
+
return { data: { appId, releasedHosts: hosts, alreadyUndeployed, released } };
|
|
8033
8224
|
}
|
|
8034
8225
|
});
|
|
8035
8226
|
|
|
@@ -8044,7 +8235,7 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
8044
8235
|
} catch (err) {
|
|
8045
8236
|
const msg = err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.";
|
|
8046
8237
|
throw isNetworkError(err) ? new Refusal(msg, "network_error") : new Refusal(msg, "not_authenticated", {
|
|
8047
|
-
action:
|
|
8238
|
+
action: loginAction()
|
|
8048
8239
|
});
|
|
8049
8240
|
}
|
|
8050
8241
|
let payload;
|
|
@@ -8052,7 +8243,7 @@ var whoami_default = defineDeepspaceCommand({
|
|
|
8052
8243
|
payload = decodeJwtPayload(jwt);
|
|
8053
8244
|
} catch {
|
|
8054
8245
|
throw new Refusal("Malformed session token. Run `deepspace auth login` again.", "not_authenticated", {
|
|
8055
|
-
action:
|
|
8246
|
+
action: loginAction()
|
|
8056
8247
|
});
|
|
8057
8248
|
}
|
|
8058
8249
|
const isTestAccount = !!payload.email?.endsWith("@deepspace.test");
|
|
@@ -8563,7 +8754,7 @@ var usage_default = defineDeepspaceCommand({
|
|
|
8563
8754
|
});
|
|
8564
8755
|
|
|
8565
8756
|
// src/cli/commands/add.ts
|
|
8566
|
-
import { existsSync as existsSync23, readFileSync as
|
|
8757
|
+
import { existsSync as existsSync23, readFileSync as readFileSync20, realpathSync as realpathSync4 } from "fs";
|
|
8567
8758
|
import { dirname as dirname10, join as join23, resolve as resolve17 } from "path";
|
|
8568
8759
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
8569
8760
|
|
|
@@ -8576,10 +8767,10 @@ import {
|
|
|
8576
8767
|
mkdirSync as mkdirSync9,
|
|
8577
8768
|
mkdtempSync,
|
|
8578
8769
|
openSync as openSync2,
|
|
8579
|
-
readFileSync as
|
|
8770
|
+
readFileSync as readFileSync19,
|
|
8580
8771
|
readSync,
|
|
8581
8772
|
readdirSync as readdirSync8,
|
|
8582
|
-
rmSync as
|
|
8773
|
+
rmSync as rmSync8,
|
|
8583
8774
|
writeFileSync as writeFileSync7
|
|
8584
8775
|
} from "fs";
|
|
8585
8776
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
@@ -8593,7 +8784,7 @@ function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
|
8593
8784
|
const packagePath = join22(dir, "package.json");
|
|
8594
8785
|
if (existsSync22(packagePath)) {
|
|
8595
8786
|
try {
|
|
8596
|
-
const pkg2 = JSON.parse(
|
|
8787
|
+
const pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
8597
8788
|
if (pkg2.name === "deepspace") return dir;
|
|
8598
8789
|
} catch {
|
|
8599
8790
|
}
|
|
@@ -8610,7 +8801,7 @@ function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
|
8610
8801
|
const configPath = join22(packageRoot, "features", id, "feature.json");
|
|
8611
8802
|
if (!existsSync22(configPath)) return null;
|
|
8612
8803
|
try {
|
|
8613
|
-
const config = JSON.parse(
|
|
8804
|
+
const config = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
8614
8805
|
if (typeof config.id !== "string" || typeof config.name !== "string" || !Array.isArray(config.files)) {
|
|
8615
8806
|
return null;
|
|
8616
8807
|
}
|
|
@@ -8662,7 +8853,7 @@ function copyFile(src, dest) {
|
|
|
8662
8853
|
function copyFileWithImportShift(src, dest, levels) {
|
|
8663
8854
|
mkdirSync9(dirname9(dest), { recursive: true });
|
|
8664
8855
|
const prefix = "../".repeat(levels);
|
|
8665
|
-
const shifted =
|
|
8856
|
+
const shifted = readFileSync19(src, "utf-8").replace(
|
|
8666
8857
|
/(from\s+|import\s+|import\()(['"])(\.\.\/)/g,
|
|
8667
8858
|
`$1$2${prefix}$3`
|
|
8668
8859
|
);
|
|
@@ -8721,7 +8912,7 @@ function integrateSchema(config, targetDir, emit) {
|
|
|
8721
8912
|
if (!existsSync22(schemasPath)) {
|
|
8722
8913
|
return [unresolvedSchema(config.schema, "src/schemas.ts was not found.", emit)];
|
|
8723
8914
|
}
|
|
8724
|
-
let content =
|
|
8915
|
+
let content = readFileSync19(schemasPath, "utf-8");
|
|
8725
8916
|
const { exportName, importPath, spreadOperator } = config.schema;
|
|
8726
8917
|
const importPattern = new RegExp(`^import\\s+\\{[^}]*\\b${exportName}\\b`, "m");
|
|
8727
8918
|
if (importPattern.test(content)) {
|
|
@@ -8778,7 +8969,7 @@ function integrateActions(config, targetDir, emit) {
|
|
|
8778
8969
|
if (!existsSync22(actionsPath)) {
|
|
8779
8970
|
return [unresolvedActions(config.actions, "src/actions/index.ts was not found.", emit)];
|
|
8780
8971
|
}
|
|
8781
|
-
let content =
|
|
8972
|
+
let content = readFileSync19(actionsPath, "utf-8");
|
|
8782
8973
|
const registryPattern = /export const actions:\s*Record<string,\s*ActionHandler(?:<[^>]*>)?>\s*=\s*\{/;
|
|
8783
8974
|
if (!registryPattern.test(content)) {
|
|
8784
8975
|
const reason = "src/actions/index.ts has an unexpected structure.";
|
|
@@ -8833,7 +9024,7 @@ function integrateCode(config, targetDir, emit) {
|
|
|
8833
9024
|
});
|
|
8834
9025
|
continue;
|
|
8835
9026
|
}
|
|
8836
|
-
const original =
|
|
9027
|
+
const original = readFileSync19(targetPath, "utf-8");
|
|
8837
9028
|
if (original.includes(insertion.insert.trim())) {
|
|
8838
9029
|
emit(` Integration already present: ${insertion.file}`);
|
|
8839
9030
|
continue;
|
|
@@ -8871,7 +9062,7 @@ ${content.slice(
|
|
|
8871
9062
|
function integrateIgnore(config, targetDir) {
|
|
8872
9063
|
if (!config.ignore?.length) return;
|
|
8873
9064
|
const targetPath = join22(targetDir, ".gitignore");
|
|
8874
|
-
const current = existsSync22(targetPath) ?
|
|
9065
|
+
const current = existsSync22(targetPath) ? readFileSync19(targetPath, "utf-8") : "";
|
|
8875
9066
|
const present = new Set(current.split(/\r?\n/).map((line) => line.trim()));
|
|
8876
9067
|
const missing = config.ignore.filter((pattern) => !present.has(pattern));
|
|
8877
9068
|
if (missing.length === 0) return;
|
|
@@ -8891,7 +9082,7 @@ function integrateWrangler(config, targetDir, emit) {
|
|
|
8891
9082
|
if (!existsSync22(targetPath)) {
|
|
8892
9083
|
return [{ area: "wrangler", reason: "wrangler.toml was not found.", steps }];
|
|
8893
9084
|
}
|
|
8894
|
-
let source =
|
|
9085
|
+
let source = readFileSync19(targetPath, "utf-8");
|
|
8895
9086
|
if (runWorkerFirst && !/^\[assets\]\s*$/m.test(source)) {
|
|
8896
9087
|
return [{ area: "wrangler", reason: "wrangler.toml has no [assets] section.", steps }];
|
|
8897
9088
|
}
|
|
@@ -8988,7 +9179,7 @@ function integrateRoute(config, targetDir, emit) {
|
|
|
8988
9179
|
if (!existsSync22(navPath)) {
|
|
8989
9180
|
return [unresolvedRoute(config.route, config, "src/nav.ts was not found.", emit)];
|
|
8990
9181
|
}
|
|
8991
|
-
let content =
|
|
9182
|
+
let content = readFileSync19(navPath, "utf-8");
|
|
8992
9183
|
const routePath = config.route.path;
|
|
8993
9184
|
if (content.includes(`'${routePath}'`)) {
|
|
8994
9185
|
emit(` Nav already present: ${routePath}`);
|
|
@@ -9050,7 +9241,7 @@ function runPackageInstall(packageManager, targetDir, outputVisible) {
|
|
|
9050
9241
|
};
|
|
9051
9242
|
} finally {
|
|
9052
9243
|
if (outputFd !== void 0) closeSync2(outputFd);
|
|
9053
|
-
|
|
9244
|
+
rmSync8(captureDir, { recursive: true, force: true });
|
|
9054
9245
|
}
|
|
9055
9246
|
}
|
|
9056
9247
|
function integrateDependencies(config, targetDir, runInstall, outputVisible, emit) {
|
|
@@ -9069,7 +9260,7 @@ function integrateDependencies(config, targetDir, runInstall, outputVisible, emi
|
|
|
9069
9260
|
}
|
|
9070
9261
|
let pkg2;
|
|
9071
9262
|
try {
|
|
9072
|
-
pkg2 = JSON.parse(
|
|
9263
|
+
pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
9073
9264
|
} catch (error) {
|
|
9074
9265
|
emit(
|
|
9075
9266
|
` Could not patch package.json (parse error: ${error instanceof Error ? error.message : String(error)})`
|
|
@@ -9129,7 +9320,7 @@ ${child.diagnosticTail}` : "";
|
|
|
9129
9320
|
}
|
|
9130
9321
|
function dependencySnapshot(targetDir) {
|
|
9131
9322
|
try {
|
|
9132
|
-
const pkg2 = JSON.parse(
|
|
9323
|
+
const pkg2 = JSON.parse(readFileSync19(join22(targetDir, "package.json"), "utf-8"));
|
|
9133
9324
|
return {
|
|
9134
9325
|
dependencies: pkg2.dependencies ?? {},
|
|
9135
9326
|
devDependencies: pkg2.devDependencies ?? {}
|
|
@@ -9377,7 +9568,7 @@ function isDeepSpaceApp(dir) {
|
|
|
9377
9568
|
const packagePath = join23(dir, "package.json");
|
|
9378
9569
|
if (!existsSync23(packagePath)) return false;
|
|
9379
9570
|
try {
|
|
9380
|
-
const pkg2 = JSON.parse(
|
|
9571
|
+
const pkg2 = JSON.parse(readFileSync20(packagePath, "utf-8"));
|
|
9381
9572
|
return Boolean(pkg2.dependencies?.deepspace || pkg2.devDependencies?.deepspace);
|
|
9382
9573
|
} catch {
|
|
9383
9574
|
return false;
|
|
@@ -9849,10 +10040,10 @@ var domain_default = defineCommand5({
|
|
|
9849
10040
|
// src/cli/commands/app-files.ts
|
|
9850
10041
|
import { defineCommand as defineCommand6 } from "citty";
|
|
9851
10042
|
import { basename as basename4, resolve as resolve18 } from "path";
|
|
9852
|
-
import { existsSync as existsSync24, statSync as
|
|
10043
|
+
import { existsSync as existsSync24, statSync as statSync5 } from "fs";
|
|
9853
10044
|
|
|
9854
10045
|
// src/cli/lib/app-files-api.ts
|
|
9855
|
-
import { createWriteStream, openAsBlob, statSync as
|
|
10046
|
+
import { createWriteStream, openAsBlob, statSync as statSync4 } from "fs";
|
|
9856
10047
|
import { basename as basename3, extname } from "path";
|
|
9857
10048
|
import { Readable } from "stream";
|
|
9858
10049
|
import { pipeline } from "stream/promises";
|
|
@@ -9962,7 +10153,7 @@ Content-Type: ${contentType}\r
|
|
|
9962
10153
|
}
|
|
9963
10154
|
async function uploadAppFile(baseUrl, token, appId, localPath, key, onProgress) {
|
|
9964
10155
|
const path = filesPath(appId, `/upload?key=${encodeKeyPath(key)}`);
|
|
9965
|
-
const size =
|
|
10156
|
+
const size = statSync4(localPath).size;
|
|
9966
10157
|
if (size > MAX_APP_FILE_BYTES) {
|
|
9967
10158
|
throw new ApiError(oversizeMessage(size), 0, "too_large", path);
|
|
9968
10159
|
}
|
|
@@ -10128,7 +10319,7 @@ var put = defineDeepspaceCommand({
|
|
|
10128
10319
|
},
|
|
10129
10320
|
async run({ args }) {
|
|
10130
10321
|
const localPath = resolve18(String(args.file));
|
|
10131
|
-
if (!existsSync24(localPath) || !
|
|
10322
|
+
if (!existsSync24(localPath) || !statSync5(localPath).isFile()) {
|
|
10132
10323
|
throw new Refusal(`No such file: ${args.file}`, "file_not_found");
|
|
10133
10324
|
}
|
|
10134
10325
|
const key = requireKey(args.key ?? basename4(localPath));
|
|
@@ -10638,7 +10829,7 @@ var transfer_default = defineCommand8({
|
|
|
10638
10829
|
import { defineCommand as defineCommand9 } from "citty";
|
|
10639
10830
|
|
|
10640
10831
|
// src/cli/commands/_invoke-impl.ts
|
|
10641
|
-
import { readFileSync as
|
|
10832
|
+
import { readFileSync as readFileSync21 } from "fs";
|
|
10642
10833
|
import * as p15 from "@clack/prompts";
|
|
10643
10834
|
var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
10644
10835
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -10685,7 +10876,7 @@ async function resolveBody(opts) {
|
|
|
10685
10876
|
"no_stdin"
|
|
10686
10877
|
);
|
|
10687
10878
|
}
|
|
10688
|
-
raw = opts.bodyFile === "-" ? await readStreamText(process.stdin) :
|
|
10879
|
+
raw = opts.bodyFile === "-" ? await readStreamText(process.stdin) : readFileSync21(opts.bodyFile, "utf-8");
|
|
10689
10880
|
if (opts.bodyFile === "-" && raw.trim() === "") {
|
|
10690
10881
|
throw new Refusal(
|
|
10691
10882
|
"Nothing arrived on stdin \u2014 check the command feeding this one, or pass --body / a file path.",
|
|
@@ -10704,12 +10895,12 @@ async function resolveBody(opts) {
|
|
|
10704
10895
|
return raw;
|
|
10705
10896
|
}
|
|
10706
10897
|
async function fetchCatalog(opts = {}) {
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10898
|
+
try {
|
|
10899
|
+
return await fetchIntegrationCatalog(API_URL7, { summary: opts.summary });
|
|
10900
|
+
} catch (err) {
|
|
10901
|
+
if (err instanceof ApiError) throw new Refusal(err.message, err.code ?? "catalog_unavailable");
|
|
10902
|
+
throw err;
|
|
10711
10903
|
}
|
|
10712
|
-
return await res.json();
|
|
10713
10904
|
}
|
|
10714
10905
|
function findEndpoint(catalog, integration, endpoint) {
|
|
10715
10906
|
const endpoints = catalog.integrations[integration];
|
|
@@ -10793,9 +10984,13 @@ function requireEndpoint(catalog, integration, endpoint) {
|
|
|
10793
10984
|
const available = catalog.integrations[integration];
|
|
10794
10985
|
if (!available) {
|
|
10795
10986
|
const names = Object.keys(catalog.integrations).sort().join(", ");
|
|
10796
|
-
throw new Refusal(
|
|
10797
|
-
|
|
10798
|
-
|
|
10987
|
+
throw new Refusal(
|
|
10988
|
+
`Unknown integration '${integration}'. Available: ${names}`,
|
|
10989
|
+
"unknown_integration",
|
|
10990
|
+
{
|
|
10991
|
+
action: cliAction("deepspace", "integrations", "list")
|
|
10992
|
+
}
|
|
10993
|
+
);
|
|
10799
10994
|
}
|
|
10800
10995
|
const endpoints = available.map((e) => e.endpoint).join(", ");
|
|
10801
10996
|
throw new Refusal(
|
|
@@ -10811,9 +11006,7 @@ async function runInfo(args) {
|
|
|
10811
11006
|
if (!args.json) {
|
|
10812
11007
|
console.log(`${integration}/${endpoint}`);
|
|
10813
11008
|
if (info2.description) console.log(` ${info2.description}`);
|
|
10814
|
-
console.log(
|
|
10815
|
-
` billing: ${priceLabel(info2.billing)}`
|
|
10816
|
-
);
|
|
11009
|
+
console.log(` billing: ${priceLabel(info2.billing)}`);
|
|
10817
11010
|
if (info2.requiresOAuth) {
|
|
10818
11011
|
console.log(
|
|
10819
11012
|
" Requires OAuth: without a connected account, a call succeeds with data { requiresOAuth: true, authUrl } \u2014 open the authUrl, then retry."
|
|
@@ -10870,7 +11063,7 @@ async function runInvoke(args) {
|
|
|
10870
11063
|
} catch (err) {
|
|
10871
11064
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10872
11065
|
throw new Refusal(msg, "not_authenticated", {
|
|
10873
|
-
action:
|
|
11066
|
+
action: loginAction()
|
|
10874
11067
|
});
|
|
10875
11068
|
}
|
|
10876
11069
|
const controller = new AbortController();
|
|
@@ -10926,7 +11119,7 @@ async function runInvoke(args) {
|
|
|
10926
11119
|
delete rest.message;
|
|
10927
11120
|
delete rest.code;
|
|
10928
11121
|
throw new Refusal(lines.join("\n"), code, {
|
|
10929
|
-
...res.status === 401 ? { action:
|
|
11122
|
+
...res.status === 401 ? { action: loginAction() } : {},
|
|
10930
11123
|
extra: rest
|
|
10931
11124
|
});
|
|
10932
11125
|
}
|
|
@@ -11332,7 +11525,7 @@ async function callAgent(target2, path, init, timeout) {
|
|
|
11332
11525
|
throw new Refusal(
|
|
11333
11526
|
"Authentication was rejected. Run `deepspace auth login` and try again.",
|
|
11334
11527
|
"not_authenticated",
|
|
11335
|
-
{ action:
|
|
11528
|
+
{ action: loginAction() }
|
|
11336
11529
|
);
|
|
11337
11530
|
}
|
|
11338
11531
|
}
|
|
@@ -11423,7 +11616,7 @@ var agent_default = defineCommand10({
|
|
|
11423
11616
|
|
|
11424
11617
|
// src/cli/commands/feedback.ts
|
|
11425
11618
|
import * as p16 from "@clack/prompts";
|
|
11426
|
-
import { existsSync as existsSync25, readFileSync as
|
|
11619
|
+
import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
|
|
11427
11620
|
import { dirname as dirname11, join as join24 } from "path";
|
|
11428
11621
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11429
11622
|
import { release } from "os";
|
|
@@ -11452,7 +11645,7 @@ function readCliVersion() {
|
|
|
11452
11645
|
];
|
|
11453
11646
|
for (const path of candidates) {
|
|
11454
11647
|
if (!existsSync25(path)) continue;
|
|
11455
|
-
const pkg2 = JSON.parse(
|
|
11648
|
+
const pkg2 = JSON.parse(readFileSync22(path, "utf-8"));
|
|
11456
11649
|
if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
|
|
11457
11650
|
}
|
|
11458
11651
|
} catch {
|
|
@@ -11627,7 +11820,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
11627
11820
|
throw new Refusal(
|
|
11628
11821
|
err.message ?? "Not signed in. Run `deepspace auth login`.",
|
|
11629
11822
|
"not_authenticated",
|
|
11630
|
-
{ action:
|
|
11823
|
+
{ action: loginAction() }
|
|
11631
11824
|
);
|
|
11632
11825
|
}
|
|
11633
11826
|
const result = await api3(token, "/api/feedback", {
|
|
@@ -11648,7 +11841,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
|
|
|
11648
11841
|
|
|
11649
11842
|
// src/cli/commands/secrets.ts
|
|
11650
11843
|
import { defineCommand as defineCommand11 } from "citty";
|
|
11651
|
-
import { readFileSync as
|
|
11844
|
+
import { readFileSync as readFileSync23 } from "fs";
|
|
11652
11845
|
|
|
11653
11846
|
// src/cli/lib/citty-args.ts
|
|
11654
11847
|
function dedupePositionals(bound, rest) {
|
|
@@ -11963,7 +12156,7 @@ async function readUploadSource(file) {
|
|
|
11963
12156
|
return readStreamText(process.stdin, MAX_STDIN_BYTES);
|
|
11964
12157
|
}
|
|
11965
12158
|
try {
|
|
11966
|
-
return
|
|
12159
|
+
return readFileSync23(file, "utf-8");
|
|
11967
12160
|
} catch (err) {
|
|
11968
12161
|
const errno = err.code;
|
|
11969
12162
|
if (typeof errno !== "string" || errno.length === 0) throw err;
|
|
@@ -12013,47 +12206,6 @@ var download = defineCommand11({
|
|
|
12013
12206
|
process.stdout.write(formatSecretsDownload(secrets, format));
|
|
12014
12207
|
}
|
|
12015
12208
|
});
|
|
12016
|
-
var pull = defineCommand11({
|
|
12017
|
-
meta: { name: "pull", description: "Refresh the .dev.vars cache from the app store" },
|
|
12018
|
-
args: { ...COMMON_ARGS },
|
|
12019
|
-
async run({ args }) {
|
|
12020
|
-
const wranglerEnv = args.env?.trim() || void 0;
|
|
12021
|
-
const appDir = findAppDir();
|
|
12022
|
-
if (!appDir)
|
|
12023
|
-
throw new InputError(
|
|
12024
|
-
"Run from a DeepSpace app directory (one containing wrangler.toml).",
|
|
12025
|
-
"not_in_app_repo"
|
|
12026
|
-
);
|
|
12027
|
-
const t = await resolveTarget(args, { register: true });
|
|
12028
|
-
const ownerId = decodeJwtPayload(t.token).sub;
|
|
12029
|
-
const refreshed = await refreshSecretsCache(
|
|
12030
|
-
DEPLOY_URL12,
|
|
12031
|
-
t.token,
|
|
12032
|
-
t.appId,
|
|
12033
|
-
wranglerEnv,
|
|
12034
|
-
t.configName
|
|
12035
|
-
);
|
|
12036
|
-
try {
|
|
12037
|
-
await writeDevVars(appDir, ownerId, t.token, wranglerEnv, {
|
|
12038
|
-
appId: t.appId,
|
|
12039
|
-
generatedSecretsCache: refreshed.rendered
|
|
12040
|
-
});
|
|
12041
|
-
} catch (err) {
|
|
12042
|
-
if (args.app && err instanceof Refusal && err.code === "app_not_found") {
|
|
12043
|
-
throw new Refusal(err.message, err.code);
|
|
12044
|
-
}
|
|
12045
|
-
throw err;
|
|
12046
|
-
}
|
|
12047
|
-
const count = Object.keys(refreshed.pulled?.values ?? {}).length;
|
|
12048
|
-
ok(
|
|
12049
|
-
args.json === true,
|
|
12050
|
-
{ appId: t.appId, config: t.configName, pulled: count },
|
|
12051
|
-
() => console.log(
|
|
12052
|
-
refreshed.pulled ? `Pulled ${count} secrets (${t.configName}) into .dev.vars.` : `Config ${t.configName} does not exist yet; regenerated .dev.vars without app secrets.`
|
|
12053
|
-
)
|
|
12054
|
-
);
|
|
12055
|
-
}
|
|
12056
|
-
});
|
|
12057
12209
|
var configsList = defineCommand11({
|
|
12058
12210
|
meta: { name: "list", description: "List the app\u2019s configs" },
|
|
12059
12211
|
args: { ...COMMON_ARGS },
|
|
@@ -12163,7 +12315,6 @@ var secrets_default = defineCommand11({
|
|
|
12163
12315
|
delete: del2,
|
|
12164
12316
|
upload,
|
|
12165
12317
|
download,
|
|
12166
|
-
pull,
|
|
12167
12318
|
configs
|
|
12168
12319
|
}
|
|
12169
12320
|
});
|
|
@@ -12320,7 +12471,7 @@ var init_default = defineDeepspaceCommand({
|
|
|
12320
12471
|
// src/cli/commands/status.ts
|
|
12321
12472
|
import { defineCommand as defineCommand12 } from "citty";
|
|
12322
12473
|
import * as p17 from "@clack/prompts";
|
|
12323
|
-
import { existsSync as existsSync26, readFileSync as
|
|
12474
|
+
import { existsSync as existsSync26, readFileSync as readFileSync24 } from "fs";
|
|
12324
12475
|
function timeAgo(iso) {
|
|
12325
12476
|
const ms = Date.now() - Date.parse(iso);
|
|
12326
12477
|
if (!Number.isFinite(ms) || ms < 0) return iso;
|
|
@@ -12424,7 +12575,7 @@ var status_default = defineCommand12({
|
|
|
12424
12575
|
let undecodableToken = false;
|
|
12425
12576
|
try {
|
|
12426
12577
|
const payload = decodeJwtPayload(
|
|
12427
|
-
|
|
12578
|
+
readFileSync24(TOKEN_PATH, "utf-8").trim()
|
|
12428
12579
|
);
|
|
12429
12580
|
if (payload.email) who = payload.email;
|
|
12430
12581
|
userId = payload.sub ?? null;
|
|
@@ -13272,7 +13423,7 @@ var pull_default = defineDeepspaceCommand({
|
|
|
13272
13423
|
|
|
13273
13424
|
// src/cli/commands/clone.ts
|
|
13274
13425
|
import * as p20 from "@clack/prompts";
|
|
13275
|
-
import { existsSync as existsSync27, readdirSync as readdirSync9, rmSync as
|
|
13426
|
+
import { existsSync as existsSync27, readdirSync as readdirSync9, rmSync as rmSync9 } from "fs";
|
|
13276
13427
|
import { resolve as resolve19, basename as basename5, join as join25 } from "path";
|
|
13277
13428
|
function cleanFailedCloneDir(dir) {
|
|
13278
13429
|
let entries;
|
|
@@ -13283,7 +13434,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
13283
13434
|
}
|
|
13284
13435
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
13285
13436
|
try {
|
|
13286
|
-
|
|
13437
|
+
rmSync9(join25(dir, ".git"), { recursive: true, force: true });
|
|
13287
13438
|
return [];
|
|
13288
13439
|
} catch {
|
|
13289
13440
|
return entries;
|
|
@@ -13385,7 +13536,7 @@ var clone_default = defineDeepspaceCommand({
|
|
|
13385
13536
|
},
|
|
13386
13537
|
// One runnable follow-up instead of the old five-line "Next steps" block:
|
|
13387
13538
|
// nothing else in the clone works until the deps are installed. Secrets
|
|
13388
|
-
//
|
|
13539
|
+
// and `dev` (which refreshes `.dev.vars` itself) follow from there.
|
|
13389
13540
|
action: { cwd: dir, argv: [detectPackageManager(dir), "install"] }
|
|
13390
13541
|
};
|
|
13391
13542
|
}
|
|
@@ -13525,6 +13676,12 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
13525
13676
|
type: "boolean",
|
|
13526
13677
|
description: "Proceed even though the target release declares fewer Durable Object classes than the current one \u2014 THEIR STORED DATA IS DELETED.",
|
|
13527
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
|
|
13528
13685
|
}
|
|
13529
13686
|
},
|
|
13530
13687
|
async run({ args }) {
|
|
@@ -13556,7 +13713,15 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
13556
13713
|
if ("error" in picked) throw new Refusal(picked.error, picked.code);
|
|
13557
13714
|
releaseId = picked.releaseId;
|
|
13558
13715
|
}
|
|
13559
|
-
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`);
|
|
13560
13725
|
let result;
|
|
13561
13726
|
try {
|
|
13562
13727
|
result = await apiFetch(DEPLOY_URL15, token, `/api/deploy/${appId}/rollback`, {
|
|
@@ -13773,10 +13938,10 @@ import * as p24 from "@clack/prompts";
|
|
|
13773
13938
|
import {
|
|
13774
13939
|
existsSync as existsSync28,
|
|
13775
13940
|
mkdirSync as mkdirSync10,
|
|
13776
|
-
readFileSync as
|
|
13941
|
+
readFileSync as readFileSync25,
|
|
13777
13942
|
realpathSync as realpathSync6,
|
|
13778
13943
|
renameSync as renameSync2,
|
|
13779
|
-
statSync as
|
|
13944
|
+
statSync as statSync6,
|
|
13780
13945
|
writeFileSync as writeFileSync8
|
|
13781
13946
|
} from "fs";
|
|
13782
13947
|
import { dirname as dirname12, isAbsolute as isAbsolute6, join as join26, relative as relative4, sep as sep4 } from "path";
|
|
@@ -13836,7 +14001,7 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
13836
14001
|
const markerPath = worktreeMarkerPath(worktreeRoot);
|
|
13837
14002
|
if (!markerPath) return false;
|
|
13838
14003
|
try {
|
|
13839
|
-
const marker = JSON.parse(
|
|
14004
|
+
const marker = JSON.parse(readFileSync25(markerPath, "utf-8"));
|
|
13840
14005
|
return marker.version === 1 && marker.workspaceId === workspaceId && marker.mode === "managed-linked";
|
|
13841
14006
|
} catch {
|
|
13842
14007
|
return false;
|
|
@@ -13879,7 +14044,7 @@ function rematerializeWorkspaceWorktree(appDir, worktreeRoot, branch, workspaceI
|
|
|
13879
14044
|
function inOwnLinkedWorktree(appDir, id) {
|
|
13880
14045
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
13881
14046
|
try {
|
|
13882
|
-
return
|
|
14047
|
+
return statSync6(join26(repoToplevel(appDir), ".git")).isFile();
|
|
13883
14048
|
} catch {
|
|
13884
14049
|
return false;
|
|
13885
14050
|
}
|
|
@@ -14325,7 +14490,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
14325
14490
|
|
|
14326
14491
|
// src/cli/commands/workspace/attach.ts
|
|
14327
14492
|
import * as p26 from "@clack/prompts";
|
|
14328
|
-
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";
|
|
14329
14494
|
import { isAbsolute as isAbsolute8, resolve as resolve21 } from "path";
|
|
14330
14495
|
function samePath(a, b) {
|
|
14331
14496
|
const real = (p34) => {
|
|
@@ -14356,7 +14521,7 @@ function cleanFailedFreshAttachDir(dir) {
|
|
|
14356
14521
|
return entries;
|
|
14357
14522
|
}
|
|
14358
14523
|
try {
|
|
14359
|
-
|
|
14524
|
+
rmSync10(dir, { recursive: true, force: true });
|
|
14360
14525
|
return [];
|
|
14361
14526
|
} catch {
|
|
14362
14527
|
return entries.length > 0 ? entries : ["<cleanup-failed>"];
|
|
@@ -14892,13 +15057,13 @@ import * as p30 from "@clack/prompts";
|
|
|
14892
15057
|
|
|
14893
15058
|
// src/cli/lib/validation.ts
|
|
14894
15059
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
14895
|
-
import { readFileSync as
|
|
15060
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
14896
15061
|
import { join as join27 } from "path";
|
|
14897
15062
|
var MAX_SUMMARY_CHARS = 4e3;
|
|
14898
15063
|
var MAX_OUTPUT_BUFFER = 64 * 1024 * 1024;
|
|
14899
15064
|
function configuredCommand(appDir) {
|
|
14900
15065
|
try {
|
|
14901
|
-
const pkg2 = JSON.parse(
|
|
15066
|
+
const pkg2 = JSON.parse(readFileSync26(join27(appDir, "package.json"), "utf-8"));
|
|
14902
15067
|
if (pkg2.scripts?.validate) return `${detectPackageManager(appDir)} run --silent validate`;
|
|
14903
15068
|
} catch {
|
|
14904
15069
|
}
|
|
@@ -15850,13 +16015,13 @@ function reportSource(appId, state, json) {
|
|
|
15850
16015
|
|
|
15851
16016
|
// src/cli/commands/update.ts
|
|
15852
16017
|
import * as p33 from "@clack/prompts";
|
|
15853
|
-
import { existsSync as existsSync30, readFileSync as
|
|
16018
|
+
import { existsSync as existsSync30, readFileSync as readFileSync27 } from "fs";
|
|
15854
16019
|
import { join as join28, resolve as resolve22 } from "path";
|
|
15855
16020
|
|
|
15856
16021
|
// package.json
|
|
15857
16022
|
var package_default = {
|
|
15858
16023
|
name: "deepspace",
|
|
15859
|
-
version: "0.
|
|
16024
|
+
version: "0.30.0",
|
|
15860
16025
|
engines: {
|
|
15861
16026
|
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
15862
16027
|
},
|
|
@@ -16038,7 +16203,7 @@ function readManifest(appDir) {
|
|
|
16038
16203
|
throw new Refusal("This app has no package.json \u2014 nothing to update.", "not_in_app_repo");
|
|
16039
16204
|
}
|
|
16040
16205
|
try {
|
|
16041
|
-
return JSON.parse(
|
|
16206
|
+
return JSON.parse(readFileSync27(path, "utf8"));
|
|
16042
16207
|
} catch {
|
|
16043
16208
|
throw new Refusal("package.json must contain valid JSON.", "invalid_package_manifest");
|
|
16044
16209
|
}
|
|
@@ -16074,7 +16239,7 @@ function usersSchemaVisibilityUpgradeInstruction(appDir) {
|
|
|
16074
16239
|
const schemaName = "src/schemas/users-schema.ts";
|
|
16075
16240
|
const path = join28(appDir, schemaName);
|
|
16076
16241
|
if (!existsSync30(path)) return null;
|
|
16077
|
-
const source =
|
|
16242
|
+
const source = readFileSync27(path, "utf8");
|
|
16078
16243
|
if (!/\bmember\s*:\s*\{[^}]*\bread\s*:\s*true\b/s.test(source)) return null;
|
|
16079
16244
|
return `${schemaName}: review member user-row visibility at ${USERS_SCHEMA_VISIBILITY_GUIDE}; leave the app-owned schema unchanged until you choose its policy.`;
|
|
16080
16245
|
}
|
|
@@ -16174,7 +16339,7 @@ process.stdout.on("error", (error) => {
|
|
|
16174
16339
|
throw error;
|
|
16175
16340
|
});
|
|
16176
16341
|
var __dirname = dirname13(fileURLToPath3(import.meta.url));
|
|
16177
|
-
var pkg = JSON.parse(
|
|
16342
|
+
var pkg = JSON.parse(readFileSync28(join29(__dirname, "..", "package.json"), "utf-8"));
|
|
16178
16343
|
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync31("/etc/ssl/certs/ca-certificates.crt")) {
|
|
16179
16344
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
16180
16345
|
}
|