deepspace 0.20.0 → 0.22.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 +28 -0
- package/dist/{chunk-A7UFIOWO.js → chunk-7TDBFEB7.js} +7 -2
- package/dist/chunk-7TDBFEB7.js.map +1 -0
- package/dist/cli.js +288 -120
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.d.ts +3 -2
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +48 -48
- package/dist/documentation-react.d.ts +2 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +7 -7
- package/dist/documentation-server-core.d.ts +3 -2
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.d.ts +40 -12
- package/dist/documentation.js +40 -7
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +225 -21
- package/dist/index.js +239 -100
- package/dist/index.js.map +1 -1
- package/dist/{public-CFAj1hL2.d.ts → public-DenQ1TsZ.d.ts} +36 -11
- package/dist/server.d.ts +32 -4
- package/dist/server.js +177 -43
- package/dist/server.js.map +1 -1
- package/dist/testing-mcp.d.ts +69 -0
- package/dist/testing-mcp.js +99 -0
- package/dist/testing-mcp.js.map +1 -0
- package/dist/testing.d.ts +17 -20
- package/dist/testing.js +47 -25
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +57 -5
- package/dist/worker.js +262 -62
- package/dist/worker.js.map +1 -1
- package/features/ai-chat/feature.json +2 -2
- package/features/ai-chat/src/AiChatPage.tsx +56 -21
- package/features/ai-chat/src/ChatPanel.tsx +33 -10
- package/features/ai-chat/src/__tests__/ChatPanel.lifecycle.test.tsx +156 -0
- package/features/cron/src/CronLogPage.tsx +107 -69
- package/features/file-attachments/feature.json +2 -1
- package/features/file-manager/feature.json +2 -1
- package/features/file-manager/src/FileManagerPage.tsx +227 -194
- package/features/integration-test/src/IntegrationTestPage.tsx +54 -34
- package/package.json +5 -1
- package/dist/chunk-A7UFIOWO.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
renderUsage
|
|
9
9
|
} from "citty";
|
|
10
10
|
import { sync as spawnSync8 } from "cross-spawn";
|
|
11
|
-
import { readFileSync as readFileSync28, existsSync as
|
|
12
|
-
import { dirname as dirname12, join as
|
|
11
|
+
import { readFileSync as readFileSync28, existsSync as existsSync27 } from "fs";
|
|
12
|
+
import { dirname as dirname12, join as join25 } from "path";
|
|
13
13
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14
14
|
|
|
15
15
|
// src/cli/lib/spinner.ts
|
|
@@ -530,7 +530,7 @@ import { readFileSync as readFileSync2, existsSync, mkdirSync } from "fs";
|
|
|
530
530
|
import { join } from "path";
|
|
531
531
|
import { homedir } from "os";
|
|
532
532
|
|
|
533
|
-
// src/
|
|
533
|
+
// src/shared/jwt.ts
|
|
534
534
|
function decodeJwtPayload(token) {
|
|
535
535
|
const payloadSegment = token.split(".")[1];
|
|
536
536
|
if (!payloadSegment) {
|
|
@@ -913,8 +913,6 @@ import { parse as parseToml } from "smol-toml";
|
|
|
913
913
|
// src/server/utils/registry-client.ts
|
|
914
914
|
var APP_ID_RE = /^app_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
915
915
|
var STRICT_APP_ID_RE = APP_ID_RE;
|
|
916
|
-
|
|
917
|
-
// src/cli/lib/app-identity.ts
|
|
918
916
|
var CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
919
917
|
function mintUlid(now = Date.now()) {
|
|
920
918
|
let ts = "";
|
|
@@ -938,9 +936,8 @@ function mintUlid(now = Date.now()) {
|
|
|
938
936
|
}
|
|
939
937
|
return `${ts}${rs}`.slice(0, 26);
|
|
940
938
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
}
|
|
939
|
+
|
|
940
|
+
// src/cli/lib/app-identity.ts
|
|
944
941
|
function readWranglerIdentityConfig(cwd) {
|
|
945
942
|
const wranglerPath = join2(resolve2(cwd), "wrangler.toml");
|
|
946
943
|
if (!existsSync3(wranglerPath)) return null;
|
|
@@ -996,6 +993,18 @@ ${line}
|
|
|
996
993
|
}
|
|
997
994
|
writeFileSync2(wranglerPath, src);
|
|
998
995
|
}
|
|
996
|
+
var APP_ID_PLACEHOLDER = "__APP_ID__";
|
|
997
|
+
function stampAppIdInSources(cwd, appId, previousAppId) {
|
|
998
|
+
const constantsPath = join2(resolve2(cwd), "src", "constants.ts");
|
|
999
|
+
if (!existsSync3(constantsPath)) return false;
|
|
1000
|
+
const needles = [APP_ID_PLACEHOLDER, ...previousAppId ? [previousAppId] : []];
|
|
1001
|
+
const content = readFileSync5(constantsPath, "utf-8");
|
|
1002
|
+
let next = content;
|
|
1003
|
+
for (const needle of needles) next = next.replaceAll(needle, appId);
|
|
1004
|
+
if (next === content) return false;
|
|
1005
|
+
writeFileSync2(constantsPath, next);
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
999
1008
|
|
|
1000
1009
|
// src/cli/commands/dev.ts
|
|
1001
1010
|
import { resolve as resolve8, basename as basename2, join as join11 } from "path";
|
|
@@ -2677,11 +2686,15 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2677
2686
|
}
|
|
2678
2687
|
const url = `http://${host === DEFAULT_DEV_HOST ? "localhost" : host}:${port}`;
|
|
2679
2688
|
say("Starting dev server...\n");
|
|
2680
|
-
const vite = spawn2(
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2689
|
+
const vite = spawn2(
|
|
2690
|
+
"npx",
|
|
2691
|
+
["vite", "--port", String(port), "--strictPort", "--host", host, "--clearScreen", "false"],
|
|
2692
|
+
{
|
|
2693
|
+
cwd: appDir,
|
|
2694
|
+
stdio: "inherit",
|
|
2695
|
+
env: wranglerViteEnv(process.env, wranglerConfig, { DEEPSPACE_PORT: String(port) })
|
|
2696
|
+
}
|
|
2697
|
+
);
|
|
2685
2698
|
const readiness = new AbortController();
|
|
2686
2699
|
if (args.json) {
|
|
2687
2700
|
void waitForPortListening(port, host, READINESS_TIMEOUT_MS, readiness.signal).then((ready) => {
|
|
@@ -3195,7 +3208,7 @@ async function syncTestAccountStore() {
|
|
|
3195
3208
|
// src/cli/commands/test.ts
|
|
3196
3209
|
var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3197
3210
|
var PLAYWRIGHT_OUTPUT_DIR = ".deepspace/test-results";
|
|
3198
|
-
function playwrightTestArgs(testFiles) {
|
|
3211
|
+
function playwrightTestArgs(testFiles, flags = {}) {
|
|
3199
3212
|
return [
|
|
3200
3213
|
"playwright",
|
|
3201
3214
|
"test",
|
|
@@ -3203,6 +3216,9 @@ function playwrightTestArgs(testFiles) {
|
|
|
3203
3216
|
"tests/playwright.config.ts",
|
|
3204
3217
|
"--output",
|
|
3205
3218
|
PLAYWRIGHT_OUTPUT_DIR,
|
|
3219
|
+
...flags.grep ? ["--grep", flags.grep] : [],
|
|
3220
|
+
...flags.project ? ["--project", flags.project] : [],
|
|
3221
|
+
...flags.headed ? ["--headed"] : [],
|
|
3206
3222
|
...testFiles
|
|
3207
3223
|
];
|
|
3208
3224
|
}
|
|
@@ -3223,6 +3239,21 @@ var test_default = defineDeepspaceCommand({
|
|
|
3223
3239
|
description: `Port for vite/webServer (default ${DEFAULT_PORT}, or $DEEPSPACE_PORT)`,
|
|
3224
3240
|
required: false
|
|
3225
3241
|
},
|
|
3242
|
+
grep: {
|
|
3243
|
+
type: "string",
|
|
3244
|
+
description: "Only run Playwright tests matching this pattern (forwarded to --grep)",
|
|
3245
|
+
required: false
|
|
3246
|
+
},
|
|
3247
|
+
project: {
|
|
3248
|
+
type: "string",
|
|
3249
|
+
description: "Playwright project to run (forwarded to --project)",
|
|
3250
|
+
required: false
|
|
3251
|
+
},
|
|
3252
|
+
headed: {
|
|
3253
|
+
type: "boolean",
|
|
3254
|
+
description: "Run Playwright browsers headed (forwarded to --headed)",
|
|
3255
|
+
default: false
|
|
3256
|
+
},
|
|
3226
3257
|
env: {
|
|
3227
3258
|
type: "string",
|
|
3228
3259
|
alias: "e",
|
|
@@ -3237,6 +3268,11 @@ var test_default = defineDeepspaceCommand({
|
|
|
3237
3268
|
preflightNodeVersion("test run");
|
|
3238
3269
|
const suite = args.suite ?? "default";
|
|
3239
3270
|
const wranglerEnv = typeof args.env === "string" && args.env.trim() ? args.env.trim() : void 0;
|
|
3271
|
+
const forwarded = {
|
|
3272
|
+
grep: typeof args.grep === "string" && args.grep ? args.grep : void 0,
|
|
3273
|
+
project: typeof args.project === "string" && args.project ? args.project : void 0,
|
|
3274
|
+
headed: Boolean(args.headed)
|
|
3275
|
+
};
|
|
3240
3276
|
const start = resolve9(".");
|
|
3241
3277
|
const appDir = findAppDir(start);
|
|
3242
3278
|
if (!appDir) {
|
|
@@ -3293,32 +3329,36 @@ var test_default = defineDeepspaceCommand({
|
|
|
3293
3329
|
let exitCode = 0;
|
|
3294
3330
|
switch (suite) {
|
|
3295
3331
|
case "smoke":
|
|
3296
|
-
exitCode = runPlaywright(appDir, ["tests/smoke.spec.ts"], port, wranglerEnv);
|
|
3332
|
+
exitCode = runPlaywright(appDir, ["tests/smoke.spec.ts"], port, wranglerEnv, forwarded);
|
|
3297
3333
|
break;
|
|
3298
3334
|
case "api":
|
|
3299
|
-
exitCode = runPlaywright(appDir, ["tests/api.spec.ts"], port, wranglerEnv);
|
|
3335
|
+
exitCode = runPlaywright(appDir, ["tests/api.spec.ts"], port, wranglerEnv, forwarded);
|
|
3300
3336
|
break;
|
|
3301
3337
|
case "e2e":
|
|
3302
|
-
exitCode = runPlaywright(appDir, [], port, wranglerEnv);
|
|
3338
|
+
exitCode = runPlaywright(appDir, [], port, wranglerEnv, forwarded);
|
|
3303
3339
|
break;
|
|
3304
3340
|
case "unit":
|
|
3341
|
+
if (forwarded.grep || forwarded.project || forwarded.headed) {
|
|
3342
|
+
console.error("note: --grep/--project/--headed apply to Playwright suites and are ignored by `unit`");
|
|
3343
|
+
}
|
|
3305
3344
|
exitCode = runVitest(appDir);
|
|
3306
3345
|
break;
|
|
3307
3346
|
case "all":
|
|
3308
3347
|
exitCode = runVitest(appDir);
|
|
3309
|
-
if (exitCode === 0) exitCode = runPlaywright(appDir, [], port, wranglerEnv);
|
|
3348
|
+
if (exitCode === 0) exitCode = runPlaywright(appDir, [], port, wranglerEnv, forwarded);
|
|
3310
3349
|
break;
|
|
3311
3350
|
case "default":
|
|
3312
3351
|
exitCode = runPlaywright(
|
|
3313
3352
|
appDir,
|
|
3314
3353
|
["tests/smoke.spec.ts", "tests/api.spec.ts"],
|
|
3315
3354
|
port,
|
|
3316
|
-
wranglerEnv
|
|
3355
|
+
wranglerEnv,
|
|
3356
|
+
forwarded
|
|
3317
3357
|
);
|
|
3318
3358
|
break;
|
|
3319
3359
|
default:
|
|
3320
3360
|
if (suite.endsWith(".spec.ts")) {
|
|
3321
|
-
exitCode = runPlaywright(appDir, [suite], port, wranglerEnv);
|
|
3361
|
+
exitCode = runPlaywright(appDir, [suite], port, wranglerEnv, forwarded);
|
|
3322
3362
|
} else {
|
|
3323
3363
|
throw new Refusal(
|
|
3324
3364
|
`Unknown test suite: ${suite}
|
|
@@ -3335,7 +3375,7 @@ Available: smoke, api, e2e, unit, all`,
|
|
|
3335
3375
|
return { data: { suite, port, appDir, wranglerEnv: wranglerEnv ?? null } };
|
|
3336
3376
|
}
|
|
3337
3377
|
});
|
|
3338
|
-
function runPlaywright(appDir, testFiles, port, wranglerEnv) {
|
|
3378
|
+
function runPlaywright(appDir, testFiles, port, wranglerEnv, flags) {
|
|
3339
3379
|
let wranglerConfig;
|
|
3340
3380
|
try {
|
|
3341
3381
|
wranglerConfig = prepareWranglerEnvConfig(appDir, wranglerEnv);
|
|
@@ -3344,7 +3384,7 @@ function runPlaywright(appDir, testFiles, port, wranglerEnv) {
|
|
|
3344
3384
|
return 1;
|
|
3345
3385
|
}
|
|
3346
3386
|
try {
|
|
3347
|
-
const result = spawnSync4("npx", playwrightTestArgs(testFiles), {
|
|
3387
|
+
const result = spawnSync4("npx", playwrightTestArgs(testFiles, flags), {
|
|
3348
3388
|
cwd: appDir,
|
|
3349
3389
|
stdio: "inherit",
|
|
3350
3390
|
env: wranglerViteEnv(process.env, wranglerConfig, {
|
|
@@ -3453,7 +3493,7 @@ var create = defineDeepspaceCommand({
|
|
|
3453
3493
|
await ensureToken();
|
|
3454
3494
|
const email = args.email;
|
|
3455
3495
|
const password = args.password;
|
|
3456
|
-
const name = args.name;
|
|
3496
|
+
const name = args.name ?? email.split("@")[0];
|
|
3457
3497
|
const label = args.label;
|
|
3458
3498
|
let account;
|
|
3459
3499
|
try {
|
|
@@ -3477,6 +3517,7 @@ var create = defineDeepspaceCommand({
|
|
|
3477
3517
|
console.log(`Created test account:`);
|
|
3478
3518
|
console.log(` ID: ${account.id}`);
|
|
3479
3519
|
console.log(` Email: ${account.email}`);
|
|
3520
|
+
console.log(` Selector: ${name}`);
|
|
3480
3521
|
console.log(` Password: ${password}`);
|
|
3481
3522
|
console.log(` UserID: ${account.userId}`);
|
|
3482
3523
|
if (account.label) console.log(` Label: ${account.label}`);
|
|
@@ -3487,6 +3528,7 @@ Saved to ${TEST_ACCOUNTS_PATH}`);
|
|
|
3487
3528
|
data: {
|
|
3488
3529
|
id: account.id,
|
|
3489
3530
|
email: account.email,
|
|
3531
|
+
name,
|
|
3490
3532
|
// The password is already echoed on the human path and stored 0600 in
|
|
3491
3533
|
// ACCOUNTS_PATH — withholding it from --json would only force scripts
|
|
3492
3534
|
// to parse the file themselves.
|
|
@@ -3504,6 +3546,18 @@ var list = defineDeepspaceCommand({
|
|
|
3504
3546
|
name: "list",
|
|
3505
3547
|
description: "List your test accounts"
|
|
3506
3548
|
},
|
|
3549
|
+
args: {
|
|
3550
|
+
usable: {
|
|
3551
|
+
type: "boolean",
|
|
3552
|
+
description: "Only accounts with locally saved credentials (usable by the users() fixture)",
|
|
3553
|
+
default: false
|
|
3554
|
+
},
|
|
3555
|
+
reveal: {
|
|
3556
|
+
type: "boolean",
|
|
3557
|
+
description: "Print locally saved passwords instead of masking them",
|
|
3558
|
+
default: false
|
|
3559
|
+
}
|
|
3560
|
+
},
|
|
3507
3561
|
async run({ args }) {
|
|
3508
3562
|
await ensureToken();
|
|
3509
3563
|
let remote;
|
|
@@ -3512,42 +3566,47 @@ var list = defineDeepspaceCommand({
|
|
|
3512
3566
|
} catch (err) {
|
|
3513
3567
|
throw new Refusal(`Failed: ${err.message}`, "test_accounts_list_failed");
|
|
3514
3568
|
}
|
|
3515
|
-
const
|
|
3516
|
-
const
|
|
3517
|
-
|
|
3569
|
+
const localByEmail = new Map(loadAllTestAccounts().map((a) => [a.email, a]));
|
|
3570
|
+
const accounts = remote.map((a) => {
|
|
3571
|
+
const stored = localByEmail.get(a.email);
|
|
3572
|
+
return {
|
|
3573
|
+
id: a.id,
|
|
3574
|
+
email: a.email,
|
|
3575
|
+
userId: a.userId,
|
|
3576
|
+
label: a.label,
|
|
3577
|
+
createdAt: a.createdAt,
|
|
3578
|
+
name: stored?.name ?? null,
|
|
3579
|
+
password: stored?.password ?? null,
|
|
3580
|
+
usableByFixture: Boolean(stored?.password)
|
|
3581
|
+
};
|
|
3582
|
+
}).filter((a) => !args.usable || a.usableByFixture);
|
|
3583
|
+
if (accounts.length === 0) {
|
|
3518
3584
|
if (!args.json) {
|
|
3519
3585
|
console.log(
|
|
3520
|
-
"No test accounts. Create one with: deepspace test accounts create --email <email> --password <password>"
|
|
3586
|
+
remote.length > 0 ? `No test accounts with locally saved credentials (${remote.length} remote-only). Recreate them with: deepspace test accounts create --email <email> --password <password>` : "No test accounts. Create one with: deepspace test accounts create --email <email> --password <password>"
|
|
3521
3587
|
);
|
|
3522
3588
|
}
|
|
3523
3589
|
return { data: { accounts: [], count: 0, limit: 10 } };
|
|
3524
3590
|
}
|
|
3525
3591
|
if (!args.json) {
|
|
3526
|
-
console.log(`Test accounts (${remote.length}/10):
|
|
3592
|
+
console.log(`Test accounts (${remote.length}/10${args.usable ? ", usable only" : ""}):
|
|
3527
3593
|
`);
|
|
3528
|
-
for (const a of
|
|
3529
|
-
const stored = localByEmail.get(a.email);
|
|
3594
|
+
for (const a of accounts) {
|
|
3530
3595
|
const date = new Date(a.createdAt).toLocaleDateString();
|
|
3531
3596
|
console.log(` ${a.email}${a.label ? ` (${a.label})` : ""}`);
|
|
3532
3597
|
console.log(` ID: ${a.id} UserID: ${a.userId} Created: ${date}`);
|
|
3533
|
-
|
|
3534
|
-
|
|
3598
|
+
console.log(` Selector: ${a.name ?? "(none)"}`);
|
|
3599
|
+
if (a.usableByFixture) {
|
|
3600
|
+
console.log(` Password: ${args.reveal ? a.password : "(saved locally)"}`);
|
|
3535
3601
|
} else {
|
|
3536
|
-
console.log(` Password: (not saved locally)`);
|
|
3602
|
+
console.log(` Password: (not saved locally \u2014 not usable by the users() fixture)`);
|
|
3537
3603
|
}
|
|
3538
3604
|
}
|
|
3539
3605
|
}
|
|
3540
3606
|
return {
|
|
3541
3607
|
data: {
|
|
3542
|
-
accounts
|
|
3543
|
-
|
|
3544
|
-
email: a.email,
|
|
3545
|
-
userId: a.userId,
|
|
3546
|
-
label: a.label,
|
|
3547
|
-
createdAt: a.createdAt,
|
|
3548
|
-
password: localByEmail.get(a.email)?.password ?? null
|
|
3549
|
-
})),
|
|
3550
|
-
count: remote.length,
|
|
3608
|
+
accounts,
|
|
3609
|
+
count: accounts.length,
|
|
3551
3610
|
limit: 10
|
|
3552
3611
|
}
|
|
3553
3612
|
};
|
|
@@ -4417,6 +4476,7 @@ async function buildDeployBundle(options) {
|
|
|
4417
4476
|
if (lintFindings && lintFindings.length > 0) {
|
|
4418
4477
|
p6.log.warn(formatSchemaLintFindings(lintFindings).join("\n"));
|
|
4419
4478
|
}
|
|
4479
|
+
const buildStarted = Date.now();
|
|
4420
4480
|
spinner2.start("Building...");
|
|
4421
4481
|
let preparedWranglerConfig;
|
|
4422
4482
|
try {
|
|
@@ -4439,7 +4499,7 @@ async function buildDeployBundle(options) {
|
|
|
4439
4499
|
} finally {
|
|
4440
4500
|
preparedWranglerConfig?.cleanup();
|
|
4441
4501
|
}
|
|
4442
|
-
spinner2.stop(
|
|
4502
|
+
spinner2.stop(`Built (${Math.round((Date.now() - buildStarted) / 1e3)}s)`);
|
|
4443
4503
|
const deployConfigPath = join15(appDir, ".wrangler", "deploy", "config.json");
|
|
4444
4504
|
if (!existsSync14(deployConfigPath)) {
|
|
4445
4505
|
output.die(
|
|
@@ -4601,6 +4661,51 @@ import * as p7 from "@clack/prompts";
|
|
|
4601
4661
|
import { existsSync as existsSync15 } from "fs";
|
|
4602
4662
|
import { join as join16 } from "path";
|
|
4603
4663
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4664
|
+
|
|
4665
|
+
// src/shared/api-error.ts
|
|
4666
|
+
var SLUG_RE = /^[a-z0-9]+(?:[_.-][a-z0-9]+)*$/;
|
|
4667
|
+
var HUMAN_MESSAGES = {
|
|
4668
|
+
owner_connect_not_ready: "This app isn't ready to accept payments yet \u2014 the app owner needs to finish payment setup.",
|
|
4669
|
+
invalid_json: "The request body was not valid JSON.",
|
|
4670
|
+
invalid_body: "The request body is invalid.",
|
|
4671
|
+
invalid_product_id: "Invalid product id.",
|
|
4672
|
+
duplicate_product_id: "Duplicate product id.",
|
|
4673
|
+
unknown_product: "Unknown product.",
|
|
4674
|
+
too_many_products: "Too many products declared.",
|
|
4675
|
+
invalid_amount: "Invalid amount.",
|
|
4676
|
+
invalid_name: "Invalid product name.",
|
|
4677
|
+
invalid_description: "Invalid product description.",
|
|
4678
|
+
unsupported_currency: "Unsupported currency.",
|
|
4679
|
+
unknown_app: "Unknown app.",
|
|
4680
|
+
not_app_owner: "Only the app owner (or a collaborator) can do this.",
|
|
4681
|
+
invalid_return_url: "Invalid return URL.",
|
|
4682
|
+
invalid_cancel_url: "Invalid cancel URL.",
|
|
4683
|
+
unknown_plan: "Unknown subscription plan.",
|
|
4684
|
+
unknown_price: "No price is configured for that billing interval.",
|
|
4685
|
+
no_subscription: "No subscription found for this account."
|
|
4686
|
+
};
|
|
4687
|
+
function normalizeApiError(status3, body) {
|
|
4688
|
+
const payload = body !== null && typeof body === "object" ? body : {};
|
|
4689
|
+
const rawError = typeof payload.error === "string" ? payload.error : void 0;
|
|
4690
|
+
const message = typeof payload.message === "string" ? payload.message : void 0;
|
|
4691
|
+
const humanError = rawError !== void 0 && !SLUG_RE.test(rawError) ? rawError : void 0;
|
|
4692
|
+
const code = rawError !== void 0 && SLUG_RE.test(rawError) ? rawError : typeof payload.code === "string" && SLUG_RE.test(payload.code) ? payload.code : void 0;
|
|
4693
|
+
const details = {};
|
|
4694
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
4695
|
+
if (key === "success" || key === "error" || key === "message" || key === "issues" || key === "code")
|
|
4696
|
+
continue;
|
|
4697
|
+
details[key] = value;
|
|
4698
|
+
}
|
|
4699
|
+
return {
|
|
4700
|
+
error: message ?? humanError ?? (code !== void 0 ? HUMAN_MESSAGES[code] : void 0) ?? rawError ?? `Request failed (${status3})`,
|
|
4701
|
+
...code !== void 0 ? { code } : {},
|
|
4702
|
+
status: status3,
|
|
4703
|
+
...Object.keys(details).length > 0 ? { details } : {},
|
|
4704
|
+
...Array.isArray(payload.issues) ? { issues: payload.issues } : {}
|
|
4705
|
+
};
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
// src/cli/commands/deploy/commerce.ts
|
|
4604
4709
|
var API_URL2 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4605
4710
|
function errorMessage2(error) {
|
|
4606
4711
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -4674,7 +4779,7 @@ Stripe will keep charging them until you cancel. Cancel at the end of their curr
|
|
|
4674
4779
|
});
|
|
4675
4780
|
const body = await response.json().catch(() => ({}));
|
|
4676
4781
|
if (!response.ok || !body.success) {
|
|
4677
|
-
lastError = body.error
|
|
4782
|
+
lastError = normalizeApiError(response.status, body).error;
|
|
4678
4783
|
spinner2.stop(`Cancel failed for ${change.slug}: ${lastError}`);
|
|
4679
4784
|
stopped = true;
|
|
4680
4785
|
break;
|
|
@@ -4732,7 +4837,7 @@ async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
|
4732
4837
|
if (!response.ok || !body.ok) {
|
|
4733
4838
|
spinner2.stop("Plan sync skipped");
|
|
4734
4839
|
p7.log.warn(
|
|
4735
|
-
`Plan sync failed: ${body.error
|
|
4840
|
+
`Plan sync failed: ${normalizeApiError(response.status, body).error}${body.hint ? ` \u2014 ${body.hint}` : ""}`
|
|
4736
4841
|
);
|
|
4737
4842
|
return;
|
|
4738
4843
|
}
|
|
@@ -4790,7 +4895,7 @@ async function syncOneTimeProducts(appDir, appName, token) {
|
|
|
4790
4895
|
}
|
|
4791
4896
|
spinner2?.stop("Product sync skipped");
|
|
4792
4897
|
p7.log.warn(
|
|
4793
|
-
`Product sync failed: ${body.error
|
|
4898
|
+
`Product sync failed: ${normalizeApiError(response.status, body).error}${body.details ? ` \u2014 ${JSON.stringify(body.details)}` : ""}`
|
|
4794
4899
|
);
|
|
4795
4900
|
} catch (error) {
|
|
4796
4901
|
spinner2?.stop("Product sync skipped");
|
|
@@ -5522,7 +5627,7 @@ async function syncDeployRepository(options) {
|
|
|
5522
5627
|
p9.log.info(`Workspace ${workspaceBranchId} is synced at ${tip.slice(0, 10)}.`);
|
|
5523
5628
|
} else if (secretFiles.length > 0) {
|
|
5524
5629
|
p9.log.warn(
|
|
5525
|
-
`Skipping cloud-repo push \u2014 the branch tracks secret file(s): ${secretFiles.join(", ")}. Untrack with \`git rm --cached ${secretFiles[0]}\` (add to .gitignore), re-commit, then \`deepspace push\`.
|
|
5630
|
+
`Skipping cloud-repo push \u2014 the branch tracks secret file(s): ${secretFiles.join(", ")}. Untrack with \`git rm --cached ${secretFiles[0]}\` (add to .gitignore), re-commit, then \`deepspace push\`. Without the push this deploy carries no source lineage: if the live release has one, the server refuses it as stale (--ignore-stale replaces it anyway), and this release's source isn't recoverable until the push works.`
|
|
5526
5631
|
);
|
|
5527
5632
|
} else {
|
|
5528
5633
|
const pushResult = await pushWithTransientRetry(
|
|
@@ -5658,7 +5763,7 @@ function detachedHeadRefusal() {
|
|
|
5658
5763
|
var CLOUDFLARE_DEPLOY_ERROR_HINT = "Deployment reached the DeepSpace deploy worker, but Cloudflare's deployment control-plane API failed. This is often caused by a Cloudflare Dashboard/API incident or Workers for Platforms entitlement outage. Already deployed apps should keep serving; wait for Cloudflare to recover and retry.";
|
|
5659
5764
|
var DEPLOY_SERVICE_LIMIT_HINT = "The DeepSpace deploy service hit a resource limit processing this deploy (the deploy worker was terminated before it could answer). This is a DeepSpace-side failure, not a Cloudflare incident \u2014 your app was not changed. Retry; if it keeps happening, report the app id and asset count.";
|
|
5660
5765
|
var REQUIRED_ASSET_TRANSPORT = "content-addressed-v1";
|
|
5661
|
-
var UPLOAD_CONCURRENCY =
|
|
5766
|
+
var UPLOAD_CONCURRENCY = 16;
|
|
5662
5767
|
async function deployBuiltBundle(options) {
|
|
5663
5768
|
const {
|
|
5664
5769
|
deployUrl,
|
|
@@ -5747,15 +5852,19 @@ async function deployBuiltBundle(options) {
|
|
|
5747
5852
|
form.append("deployKey", repository.deployKey);
|
|
5748
5853
|
return form;
|
|
5749
5854
|
};
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5855
|
+
let commitStarted = Date.now();
|
|
5856
|
+
const postCommit = async () => {
|
|
5857
|
+
commitStarted = Date.now();
|
|
5858
|
+
return postWithRetry(
|
|
5859
|
+
`${deployUrl}/api/deploy/${appId}`,
|
|
5860
|
+
() => ({
|
|
5861
|
+
method: "POST",
|
|
5862
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
5863
|
+
body: makeForm()
|
|
5864
|
+
}),
|
|
5865
|
+
{ retryServerErrors: false, attempts: 2, timeoutMs: 24e4 }
|
|
5866
|
+
);
|
|
5867
|
+
};
|
|
5759
5868
|
let response;
|
|
5760
5869
|
try {
|
|
5761
5870
|
response = await postCommit();
|
|
@@ -5802,6 +5911,7 @@ async function deployBuiltBundle(options) {
|
|
|
5802
5911
|
body.code
|
|
5803
5912
|
);
|
|
5804
5913
|
}
|
|
5914
|
+
p10.log.info(`Platform commit: ${Math.round((Date.now() - commitStarted) / 1e3)}s`);
|
|
5805
5915
|
if (body.onBehalfOfOwner) {
|
|
5806
5916
|
p10.log.warn("This release is attributed to the app's owner, not to your account.");
|
|
5807
5917
|
}
|
|
@@ -5920,8 +6030,12 @@ async function uploadDeployAssets(options) {
|
|
|
5920
6030
|
spinner2.message(`Uploading assets \u2014 ${uploaded}/${total}...`);
|
|
5921
6031
|
}
|
|
5922
6032
|
};
|
|
6033
|
+
const uploadStarted = Date.now();
|
|
5923
6034
|
try {
|
|
5924
6035
|
await Promise.all(Array.from({ length: Math.min(UPLOAD_CONCURRENCY, missing.length) }, worker));
|
|
6036
|
+
p10.log.info(
|
|
6037
|
+
`Uploaded ${total} file(s) in ${Math.round((Date.now() - uploadStarted) / 1e3)}s`
|
|
6038
|
+
);
|
|
5925
6039
|
} catch (error) {
|
|
5926
6040
|
spinner2.stop("Deploy failed");
|
|
5927
6041
|
if (error instanceof AssetUploadError) {
|
|
@@ -5967,13 +6081,14 @@ function errorMessage4(error) {
|
|
|
5967
6081
|
}
|
|
5968
6082
|
async function postWithRetry(url, makeInit, {
|
|
5969
6083
|
attempts = 4,
|
|
5970
|
-
retryServerErrors = true
|
|
6084
|
+
retryServerErrors = true,
|
|
6085
|
+
timeoutMs = 6e4
|
|
5971
6086
|
} = {}) {
|
|
5972
6087
|
let lastResponse;
|
|
5973
6088
|
let lastError;
|
|
5974
6089
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
5975
6090
|
try {
|
|
5976
|
-
const response = await fetch(url, makeInit());
|
|
6091
|
+
const response = await fetch(url, { ...makeInit(), signal: AbortSignal.timeout(timeoutMs) });
|
|
5977
6092
|
const transient = retryServerErrors && (response.status >= 500 || response.status === 408 || response.status === 429);
|
|
5978
6093
|
if (!transient) return response;
|
|
5979
6094
|
lastResponse = response;
|
|
@@ -6146,13 +6261,14 @@ var deploy_default = defineCommand3({
|
|
|
6146
6261
|
);
|
|
6147
6262
|
}
|
|
6148
6263
|
const appName = nameResult.name;
|
|
6149
|
-
|
|
6264
|
+
const appId = readAppId(appDir, envName);
|
|
6150
6265
|
p12.log.info(envName ? `App: ${appName} (env: ${envName})` : `App: ${appName}`);
|
|
6151
6266
|
const { token, ownerId } = await authenticate(appDir, output);
|
|
6152
6267
|
if (!appId) {
|
|
6153
|
-
|
|
6154
|
-
|
|
6155
|
-
|
|
6268
|
+
return output.die(
|
|
6269
|
+
`No app id in wrangler.toml${envName ? ` for [env.${envName}]` : ""}. Run \`deepspace app init${envName ? ` --env ${envName}` : ""}\` to register this app, then re-deploy.`,
|
|
6270
|
+
"app_not_initialized"
|
|
6271
|
+
);
|
|
6156
6272
|
}
|
|
6157
6273
|
p12.log.info(`Id: ${appId}`);
|
|
6158
6274
|
const secretsCache = await loadDeploySecrets({
|
|
@@ -6218,6 +6334,7 @@ var deploy_default = defineCommand3({
|
|
|
6218
6334
|
spinner: spinner2
|
|
6219
6335
|
});
|
|
6220
6336
|
let serving = "unverifiable";
|
|
6337
|
+
const edgeWaitStarted = Date.now();
|
|
6221
6338
|
if (body.url) {
|
|
6222
6339
|
spinner2.message("Waiting for the edge to serve this release...");
|
|
6223
6340
|
serving = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
@@ -6247,7 +6364,9 @@ var deploy_default = defineCommand3({
|
|
|
6247
6364
|
return;
|
|
6248
6365
|
}
|
|
6249
6366
|
}
|
|
6250
|
-
spinner2.stop(
|
|
6367
|
+
spinner2.stop(
|
|
6368
|
+
`Deployed! (edge confirmed in ${Math.round((Date.now() - edgeWaitStarted) / 1e3)}s)`
|
|
6369
|
+
);
|
|
6251
6370
|
p12.log.success(`Live at: ${body.url}`);
|
|
6252
6371
|
await syncCommerce(appDir, appId, token, output.nonInteractive);
|
|
6253
6372
|
if (output.json) {
|
|
@@ -6508,7 +6627,10 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
6508
6627
|
}
|
|
6509
6628
|
);
|
|
6510
6629
|
}
|
|
6511
|
-
throw new Refusal(
|
|
6630
|
+
throw new Refusal(
|
|
6631
|
+
body.error ?? `Undeploy error (${res.status})`,
|
|
6632
|
+
body.code ?? "undeploy_failed"
|
|
6633
|
+
);
|
|
6512
6634
|
}
|
|
6513
6635
|
s?.stop("Removed");
|
|
6514
6636
|
const hosts = body.releasedHosts ?? [];
|
|
@@ -9205,7 +9327,9 @@ async function runList(args) {
|
|
|
9205
9327
|
for (const ep of endpoints) {
|
|
9206
9328
|
const pad = ep.endpoint.padEnd(widest);
|
|
9207
9329
|
const cost = formatCurrency(ep.billing.baseCost, ep.billing.currency);
|
|
9208
|
-
|
|
9330
|
+
const oauth = ep.requiresOAuth ? " [oauth]" : "";
|
|
9331
|
+
console.log(` ${pad} ${ep.billing.model.padEnd(12)} ${cost}${oauth}`);
|
|
9332
|
+
if (ep.description) console.log(` ${ep.description}`);
|
|
9209
9333
|
}
|
|
9210
9334
|
console.log();
|
|
9211
9335
|
}
|
|
@@ -9234,9 +9358,15 @@ async function runInfo(args) {
|
|
|
9234
9358
|
}
|
|
9235
9359
|
if (!args.json) {
|
|
9236
9360
|
console.log(`${integration}/${endpoint}`);
|
|
9361
|
+
if (info2.description) console.log(` ${info2.description}`);
|
|
9237
9362
|
console.log(
|
|
9238
9363
|
` billing: ${formatCurrency(info2.billing.baseCost, info2.billing.currency)} ${billingUnit(info2.billing.model)}`
|
|
9239
9364
|
);
|
|
9365
|
+
if (info2.requiresOAuth) {
|
|
9366
|
+
console.log(
|
|
9367
|
+
" Requires OAuth: without a connected account, a call succeeds with data { requiresOAuth: true, authUrl } \u2014 open the authUrl, then retry."
|
|
9368
|
+
);
|
|
9369
|
+
}
|
|
9240
9370
|
console.log();
|
|
9241
9371
|
console.log("Input schema:");
|
|
9242
9372
|
console.log(
|
|
@@ -9245,6 +9375,11 @@ async function runInfo(args) {
|
|
|
9245
9375
|
console.log();
|
|
9246
9376
|
console.log("Example body:");
|
|
9247
9377
|
console.log(info2.example ? JSON.stringify(info2.example, null, 2) : " (no example available)");
|
|
9378
|
+
if (info2.outputSchema) {
|
|
9379
|
+
console.log();
|
|
9380
|
+
console.log("Output schema:");
|
|
9381
|
+
console.log(JSON.stringify(info2.outputSchema, null, 2));
|
|
9382
|
+
}
|
|
9248
9383
|
}
|
|
9249
9384
|
return { data: info2 };
|
|
9250
9385
|
}
|
|
@@ -9325,17 +9460,19 @@ async function runInvoke(args) {
|
|
|
9325
9460
|
}
|
|
9326
9461
|
return { data: payload };
|
|
9327
9462
|
}
|
|
9328
|
-
const
|
|
9329
|
-
const lines = [`${integration}/${endpoint} (${res.status}, ${elapsed}ms): ${
|
|
9330
|
-
if (
|
|
9331
|
-
for (const issue of
|
|
9463
|
+
const norm = normalizeApiError(res.status, payload);
|
|
9464
|
+
const lines = [`${integration}/${endpoint} (${res.status}, ${elapsed}ms): ${norm.error}`];
|
|
9465
|
+
if (norm.issues) {
|
|
9466
|
+
for (const issue of norm.issues) {
|
|
9332
9467
|
const path = issue.path?.length ? issue.path.join(".") : "(root)";
|
|
9333
9468
|
lines.push(` - ${path}: ${issue.message}`);
|
|
9334
9469
|
}
|
|
9335
9470
|
}
|
|
9336
|
-
const code =
|
|
9471
|
+
const code = norm.code ?? "integration_call_failed";
|
|
9337
9472
|
const rest = { ...payload };
|
|
9338
9473
|
delete rest.error;
|
|
9474
|
+
delete rest.message;
|
|
9475
|
+
delete rest.code;
|
|
9339
9476
|
throw new Refusal(lines.join("\n"), code, {
|
|
9340
9477
|
...res.status === 401 ? { action: cliAction("deepspace", "auth", "login") } : {},
|
|
9341
9478
|
extra: rest
|
|
@@ -10106,10 +10243,29 @@ var secrets_default = defineCommand10({
|
|
|
10106
10243
|
});
|
|
10107
10244
|
|
|
10108
10245
|
// src/cli/commands/init.ts
|
|
10246
|
+
import { existsSync as existsSync21 } from "fs";
|
|
10247
|
+
import { join as join20 } from "path";
|
|
10248
|
+
var DEPLOY_URL12 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
10249
|
+
function commitScaffoldIfUnborn(appDir, token) {
|
|
10250
|
+
try {
|
|
10251
|
+
if (!existsSync21(join20(appDir, ".git"))) return false;
|
|
10252
|
+
if (runGit(appDir, ["rev-parse", "--verify", "HEAD"], { allowFail: true }).status === 0) {
|
|
10253
|
+
return false;
|
|
10254
|
+
}
|
|
10255
|
+
ensureGitIdentity(appDir, token);
|
|
10256
|
+
if (runGit(appDir, ["add", "-A"], { allowFail: true }).status !== 0) return false;
|
|
10257
|
+
const commit = runGit(appDir, ["commit", "-m", "Initial DeepSpace scaffold", "--no-verify"], {
|
|
10258
|
+
allowFail: true
|
|
10259
|
+
});
|
|
10260
|
+
return commit.status === 0;
|
|
10261
|
+
} catch {
|
|
10262
|
+
return false;
|
|
10263
|
+
}
|
|
10264
|
+
}
|
|
10109
10265
|
var init_default = defineDeepspaceCommand({
|
|
10110
10266
|
meta: {
|
|
10111
10267
|
name: "init",
|
|
10112
|
-
description: "
|
|
10268
|
+
description: "Register this app: mint its immutable DEEPSPACE_APP_ID into wrangler.toml"
|
|
10113
10269
|
},
|
|
10114
10270
|
args: {
|
|
10115
10271
|
"new-id": {
|
|
@@ -10143,23 +10299,31 @@ var init_default = defineDeepspaceCommand({
|
|
|
10143
10299
|
data: { status: "already_initialized", appId: existing, appDir, env: envName ?? null }
|
|
10144
10300
|
};
|
|
10145
10301
|
}
|
|
10146
|
-
const
|
|
10302
|
+
const token = await ensureToken();
|
|
10303
|
+
const { appId } = await apiFetch(DEPLOY_URL12, token, "/api/apps/mint", {
|
|
10304
|
+
method: "POST"
|
|
10305
|
+
});
|
|
10147
10306
|
writeAppId(appDir, appId, { wranglerEnv: envName, force: Boolean(args["new-id"]) });
|
|
10307
|
+
if (!envName) stampAppIdInSources(appDir, appId, existing);
|
|
10308
|
+
const committedScaffold = commitScaffoldIfUnborn(appDir, token);
|
|
10148
10309
|
if (!args.json) {
|
|
10149
10310
|
if (existing) {
|
|
10150
10311
|
console.log(`Forked: ${existing} \u2192 ${appId}${envName ? ` (env: ${envName})` : ""}`);
|
|
10151
|
-
console.log("
|
|
10312
|
+
console.log("Registered as a NEW app under your account; the original is untouched.");
|
|
10152
10313
|
} else {
|
|
10153
|
-
console.log(
|
|
10154
|
-
|
|
10314
|
+
console.log(
|
|
10315
|
+
`Registered ${appId}${envName ? ` (env: ${envName})` : ""} to your account` + (committedScaffold ? " \u2014 initial scaffold commit created." : " \u2014 commit wrangler.toml.")
|
|
10316
|
+
);
|
|
10317
|
+
console.log("The first deploy claims the `name` subdomain.");
|
|
10155
10318
|
}
|
|
10156
10319
|
console.log(`App dir: ${appDir}`);
|
|
10157
10320
|
}
|
|
10158
10321
|
return {
|
|
10159
10322
|
data: {
|
|
10160
|
-
status: existing ? "forked" : "
|
|
10323
|
+
status: existing ? "forked" : "registered",
|
|
10161
10324
|
appId,
|
|
10162
10325
|
...existing ? { previousAppId: existing } : {},
|
|
10326
|
+
committedScaffold,
|
|
10163
10327
|
appDir,
|
|
10164
10328
|
env: envName ?? null
|
|
10165
10329
|
}
|
|
@@ -10170,7 +10334,7 @@ var init_default = defineDeepspaceCommand({
|
|
|
10170
10334
|
// src/cli/commands/status.ts
|
|
10171
10335
|
import { defineCommand as defineCommand11 } from "citty";
|
|
10172
10336
|
import * as p17 from "@clack/prompts";
|
|
10173
|
-
import { existsSync as
|
|
10337
|
+
import { existsSync as existsSync22, readFileSync as readFileSync24 } from "fs";
|
|
10174
10338
|
function timeAgo(iso) {
|
|
10175
10339
|
const ms = Date.now() - Date.parse(iso);
|
|
10176
10340
|
if (!Number.isFinite(ms) || ms < 0) return iso;
|
|
@@ -10255,7 +10419,7 @@ var status_default = defineCommand11({
|
|
|
10255
10419
|
json.services = urls;
|
|
10256
10420
|
if (urlOverrides.length > 0) json.urlOverrides = urlOverrides;
|
|
10257
10421
|
}
|
|
10258
|
-
facts.loggedIn =
|
|
10422
|
+
facts.loggedIn = existsSync22(SESSION_PATH);
|
|
10259
10423
|
let userId = null;
|
|
10260
10424
|
if (!facts.loggedIn) {
|
|
10261
10425
|
lines.push(["Session", "not logged in"]);
|
|
@@ -10944,18 +11108,18 @@ var pull_default = defineDeepspaceCommand({
|
|
|
10944
11108
|
|
|
10945
11109
|
// src/cli/commands/clone.ts
|
|
10946
11110
|
import * as p20 from "@clack/prompts";
|
|
10947
|
-
import { existsSync as
|
|
10948
|
-
import { resolve as resolve17, basename as basename5, join as
|
|
11111
|
+
import { existsSync as existsSync23, readdirSync as readdirSync6, rmSync as rmSync5 } from "fs";
|
|
11112
|
+
import { resolve as resolve17, basename as basename5, join as join21 } from "path";
|
|
10949
11113
|
function cleanFailedCloneDir(dir) {
|
|
10950
11114
|
let entries;
|
|
10951
11115
|
try {
|
|
10952
11116
|
entries = readdirSync6(dir);
|
|
10953
11117
|
} catch {
|
|
10954
|
-
return
|
|
11118
|
+
return existsSync23(dir) ? ["<unreadable>"] : [];
|
|
10955
11119
|
}
|
|
10956
11120
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
10957
11121
|
try {
|
|
10958
|
-
rmSync5(
|
|
11122
|
+
rmSync5(join21(dir, ".git"), { recursive: true, force: true });
|
|
10959
11123
|
return [];
|
|
10960
11124
|
} catch {
|
|
10961
11125
|
return entries;
|
|
@@ -10964,7 +11128,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
10964
11128
|
return entries;
|
|
10965
11129
|
}
|
|
10966
11130
|
function validateCloneTarget(dir) {
|
|
10967
|
-
if (!
|
|
11131
|
+
if (!existsSync23(dir)) return false;
|
|
10968
11132
|
let entries;
|
|
10969
11133
|
try {
|
|
10970
11134
|
entries = readdirSync6(dir);
|
|
@@ -11087,7 +11251,7 @@ async function actorLabels(token, appId) {
|
|
|
11087
11251
|
}
|
|
11088
11252
|
|
|
11089
11253
|
// src/cli/commands/releases.ts
|
|
11090
|
-
var
|
|
11254
|
+
var DEPLOY_URL13 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
11091
11255
|
var releases_default = defineDeepspaceCommand({
|
|
11092
11256
|
meta: {
|
|
11093
11257
|
name: "releases",
|
|
@@ -11122,8 +11286,8 @@ var releases_default = defineDeepspaceCommand({
|
|
|
11122
11286
|
const spinner2 = args.json ? null : createSpinner();
|
|
11123
11287
|
spinner2?.start("Loading release history\u2026");
|
|
11124
11288
|
const token = await ensureToken();
|
|
11125
|
-
const appId = await resolveAppTarget(
|
|
11126
|
-
const { releases } = await repoApi(
|
|
11289
|
+
const appId = await resolveAppTarget(DEPLOY_URL13, token, appArg, { wranglerEnv: envArg });
|
|
11290
|
+
const { releases } = await repoApi(DEPLOY_URL13, token, appId).listReleases(limit);
|
|
11127
11291
|
spinner2?.stop(`Loaded ${releases.length} ${releases.length === 1 ? "release" : "releases"}.`);
|
|
11128
11292
|
if (!args.json) {
|
|
11129
11293
|
if (releases.length === 0) {
|
|
@@ -11156,7 +11320,7 @@ Retry in a moment, or re-run with --allow-do-deletion to accept the risk.`,
|
|
|
11156
11320
|
"do_guard_unavailable"
|
|
11157
11321
|
);
|
|
11158
11322
|
}
|
|
11159
|
-
var
|
|
11323
|
+
var DEPLOY_URL14 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
11160
11324
|
function pickPreviousRelease(releases) {
|
|
11161
11325
|
if (releases.length === 0) {
|
|
11162
11326
|
return { error: "No releases recorded yet \u2014 nothing to roll back to.", code: "no_releases" };
|
|
@@ -11218,8 +11382,8 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
11218
11382
|
const spinner2 = args.json ? null : createSpinner();
|
|
11219
11383
|
spinner2?.start("Preparing rollback\u2026");
|
|
11220
11384
|
const token = await ensureToken();
|
|
11221
|
-
const appId = await resolveAppTarget(
|
|
11222
|
-
const api4 = repoApi(
|
|
11385
|
+
const appId = await resolveAppTarget(DEPLOY_URL14, token, appArg, { wranglerEnv: envArg });
|
|
11386
|
+
const api4 = repoApi(DEPLOY_URL14, token, appId);
|
|
11223
11387
|
let releaseId = args.release ? String(args.release).trim() : "";
|
|
11224
11388
|
if (!releaseId) {
|
|
11225
11389
|
const { releases } = await api4.listReleases(2);
|
|
@@ -11230,7 +11394,7 @@ var rollback_default = defineDeepspaceCommand({
|
|
|
11230
11394
|
spinner2?.message(`Rolling back to ${releaseId}\u2026`);
|
|
11231
11395
|
let result;
|
|
11232
11396
|
try {
|
|
11233
|
-
result = await apiFetch(
|
|
11397
|
+
result = await apiFetch(DEPLOY_URL14, token, `/api/deploy/${appId}/rollback`, {
|
|
11234
11398
|
method: "POST",
|
|
11235
11399
|
body: JSON.stringify({
|
|
11236
11400
|
releaseId,
|
|
@@ -11441,7 +11605,7 @@ function printOverlaps(overlaps, json) {
|
|
|
11441
11605
|
// src/cli/commands/workspace/local.ts
|
|
11442
11606
|
import * as p24 from "@clack/prompts";
|
|
11443
11607
|
import {
|
|
11444
|
-
existsSync as
|
|
11608
|
+
existsSync as existsSync24,
|
|
11445
11609
|
mkdirSync as mkdirSync7,
|
|
11446
11610
|
readFileSync as readFileSync25,
|
|
11447
11611
|
realpathSync as realpathSync6,
|
|
@@ -11449,7 +11613,7 @@ import {
|
|
|
11449
11613
|
statSync as statSync3,
|
|
11450
11614
|
writeFileSync as writeFileSync7
|
|
11451
11615
|
} from "fs";
|
|
11452
|
-
import { dirname as dirname11, isAbsolute as isAbsolute5, join as
|
|
11616
|
+
import { dirname as dirname11, isAbsolute as isAbsolute5, join as join22, relative as relative2, sep as sep2 } from "path";
|
|
11453
11617
|
var WORKSPACE_MARKER = "deepspace-workspace.json";
|
|
11454
11618
|
function excludeWorktreeDir(appDir, dir) {
|
|
11455
11619
|
try {
|
|
@@ -11470,7 +11634,7 @@ function worktreeMarkerPath(worktreeRoot) {
|
|
|
11470
11634
|
const result = runGit(worktreeRoot, ["rev-parse", "--absolute-git-dir"], { allowFail: true });
|
|
11471
11635
|
if (result.status !== 0) return null;
|
|
11472
11636
|
const gitDir = result.stdout.toString("utf-8").trim();
|
|
11473
|
-
return isAbsolute5(gitDir) ?
|
|
11637
|
+
return isAbsolute5(gitDir) ? join22(gitDir, WORKSPACE_MARKER) : null;
|
|
11474
11638
|
} catch {
|
|
11475
11639
|
return null;
|
|
11476
11640
|
}
|
|
@@ -11515,11 +11679,11 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
11515
11679
|
function defaultWorkspaceRoot(appDir, workspaceId) {
|
|
11516
11680
|
const primary = listWorktrees(appDir)[0];
|
|
11517
11681
|
if (!primary) throw new Error("Git did not report a primary worktree");
|
|
11518
|
-
return
|
|
11682
|
+
return join22(primary.path, ".deepspace", "ws", workspaceId.slice(3).toLowerCase());
|
|
11519
11683
|
}
|
|
11520
11684
|
function appDirInWorktree(appDir, worktreeRoot) {
|
|
11521
11685
|
const appRelative = relative2(realpathSync6(repoToplevel(appDir)), realpathSync6(appDir));
|
|
11522
|
-
return appRelative ?
|
|
11686
|
+
return appRelative ? join22(worktreeRoot, appRelative) : worktreeRoot;
|
|
11523
11687
|
}
|
|
11524
11688
|
function primaryAppDir(appDir) {
|
|
11525
11689
|
const primary = listWorktrees(appDir)[0];
|
|
@@ -11554,7 +11718,7 @@ function rematerializeWorkspaceWorktree(appDir, worktreeRoot, branch, workspaceI
|
|
|
11554
11718
|
function inOwnLinkedWorktree(appDir, id) {
|
|
11555
11719
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
11556
11720
|
try {
|
|
11557
|
-
return statSync3(
|
|
11721
|
+
return statSync3(join22(repoToplevel(appDir), ".git")).isFile();
|
|
11558
11722
|
} catch {
|
|
11559
11723
|
return false;
|
|
11560
11724
|
}
|
|
@@ -11679,7 +11843,7 @@ function cleanupWorkspaceLocal(appDir, id, trunkBranch, options = {}) {
|
|
|
11679
11843
|
}
|
|
11680
11844
|
runGit(mainDir, ["worktree", "prune"], { allowFail: true });
|
|
11681
11845
|
out.worktreeDir = null;
|
|
11682
|
-
const leftover =
|
|
11846
|
+
const leftover = existsSync24(linked.path);
|
|
11683
11847
|
if (leftover) out.leftoverDir = linked.path;
|
|
11684
11848
|
else out.worktreeRemoved = linked.path;
|
|
11685
11849
|
deleteWsBranch(mainDir, branch, expectedBranchOid, out);
|
|
@@ -11977,7 +12141,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11977
12141
|
|
|
11978
12142
|
// src/cli/commands/workspace/attach.ts
|
|
11979
12143
|
import * as p26 from "@clack/prompts";
|
|
11980
|
-
import { existsSync as
|
|
12144
|
+
import { existsSync as existsSync25, readdirSync as readdirSync7, realpathSync as realpathSync7, rmSync as rmSync6 } from "fs";
|
|
11981
12145
|
import { isAbsolute as isAbsolute7, resolve as resolve19 } from "path";
|
|
11982
12146
|
function samePath(a, b) {
|
|
11983
12147
|
const real = (p35) => {
|
|
@@ -11997,7 +12161,7 @@ function finishedWorkspaceMessage(id, view) {
|
|
|
11997
12161
|
return `Workspace ${id} is ${workspace.status} \u2014 its ref is retained briefly (fetch ${workspace.ref} to inspect), but attach only works on active workspaces.`;
|
|
11998
12162
|
}
|
|
11999
12163
|
function cleanFailedFreshAttachDir(dir) {
|
|
12000
|
-
if (!
|
|
12164
|
+
if (!existsSync25(dir)) return [];
|
|
12001
12165
|
let entries;
|
|
12002
12166
|
try {
|
|
12003
12167
|
entries = readdirSync7(dir);
|
|
@@ -12079,7 +12243,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12079
12243
|
const localTip = resolveCommit(appDir, `refs/heads/${branch}`);
|
|
12080
12244
|
if (localTip) {
|
|
12081
12245
|
let existing = resolveWorkspaceWorktree(listWorktrees(appDir), id);
|
|
12082
|
-
if (existing && !
|
|
12246
|
+
if (existing && !existsSync25(existing)) {
|
|
12083
12247
|
runGit(appDir, ["worktree", "prune"], { allowFail: true });
|
|
12084
12248
|
existing = null;
|
|
12085
12249
|
}
|
|
@@ -12197,7 +12361,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12197
12361
|
process.cwd(),
|
|
12198
12362
|
(typeof args.dir === "string" ? args.dir.trim() : "") || `ws-${id.slice(3).toLowerCase()}`
|
|
12199
12363
|
);
|
|
12200
|
-
if (
|
|
12364
|
+
if (existsSync25(dir)) {
|
|
12201
12365
|
spinner2?.stop("Target exists.");
|
|
12202
12366
|
throw new Refusal(`${dir} already exists \u2014 pass a different directory.`, "dir_exists");
|
|
12203
12367
|
}
|
|
@@ -12535,12 +12699,12 @@ import * as p30 from "@clack/prompts";
|
|
|
12535
12699
|
// src/cli/lib/validation.ts
|
|
12536
12700
|
import { sync as spawnSync7 } from "cross-spawn";
|
|
12537
12701
|
import { readFileSync as readFileSync26 } from "fs";
|
|
12538
|
-
import { join as
|
|
12702
|
+
import { join as join23 } from "path";
|
|
12539
12703
|
var MAX_SUMMARY_CHARS = 4e3;
|
|
12540
12704
|
var MAX_OUTPUT_BUFFER = 64 * 1024 * 1024;
|
|
12541
12705
|
function configuredCommand(appDir) {
|
|
12542
12706
|
try {
|
|
12543
|
-
const pkg2 = JSON.parse(readFileSync26(
|
|
12707
|
+
const pkg2 = JSON.parse(readFileSync26(join23(appDir, "package.json"), "utf-8"));
|
|
12544
12708
|
if (pkg2.scripts?.validate) return `${detectPackageManager(appDir)} run --silent validate`;
|
|
12545
12709
|
} catch {
|
|
12546
12710
|
}
|
|
@@ -12581,7 +12745,7 @@ function conflictMarkerFiles(diffCheckOutput) {
|
|
|
12581
12745
|
function pullAfterLandAction(primaryDir, intoBranch, landedOid) {
|
|
12582
12746
|
if (currentBranch(primaryDir) !== intoBranch) return null;
|
|
12583
12747
|
if (resolveCommit(primaryDir, "HEAD") === landedOid) return null;
|
|
12584
|
-
return { cwd: primaryDir, argv: ["deepspace", "pull"] };
|
|
12748
|
+
return executableAction({ cwd: primaryDir, argv: ["deepspace", "pull"] });
|
|
12585
12749
|
}
|
|
12586
12750
|
function landResumeArgv(args) {
|
|
12587
12751
|
const argv = ["deepspace", "workspace", "land"];
|
|
@@ -12862,6 +13026,7 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12862
13026
|
}
|
|
12863
13027
|
spinner2?.stop(`Landed ${id} into ${intoBranch} at ${landedOid.slice(0, 10)}.`);
|
|
12864
13028
|
const primaryDir = primaryAppDir(appDir);
|
|
13029
|
+
const action = pullAfterLandAction(primaryDir, intoBranch, landedOid);
|
|
12865
13030
|
const cleanup = keepWorktree ? null : cleanupWorkspaceLocal(appDir, id, intoBranch, { expectedBranchOid: landedOid });
|
|
12866
13031
|
const inOwnWorktree = !cleanup && inOwnLinkedWorktree(appDir, id);
|
|
12867
13032
|
const retainedWorktree = cleanup?.worktreeRetained ?? (keepWorktree || inOwnWorktree ? appDir : null);
|
|
@@ -12895,7 +13060,6 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12895
13060
|
{ actionRequired: true, action: action2, extra: data }
|
|
12896
13061
|
);
|
|
12897
13062
|
}
|
|
12898
|
-
const action = pullAfterLandAction(primaryDir, intoBranch, landedOid);
|
|
12899
13063
|
return { data, ...action ? { action } : {} };
|
|
12900
13064
|
}
|
|
12901
13065
|
});
|
|
@@ -13616,13 +13780,13 @@ function sameRefs(left, right) {
|
|
|
13616
13780
|
|
|
13617
13781
|
// src/cli/commands/update.ts
|
|
13618
13782
|
import * as p34 from "@clack/prompts";
|
|
13619
|
-
import { existsSync as
|
|
13620
|
-
import { join as
|
|
13783
|
+
import { existsSync as existsSync26, readFileSync as readFileSync27, writeFileSync as writeFileSync8 } from "fs";
|
|
13784
|
+
import { join as join24, resolve as resolve20 } from "path";
|
|
13621
13785
|
|
|
13622
13786
|
// package.json
|
|
13623
13787
|
var package_default = {
|
|
13624
13788
|
name: "deepspace",
|
|
13625
|
-
version: "0.
|
|
13789
|
+
version: "0.22.0",
|
|
13626
13790
|
engines: {
|
|
13627
13791
|
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
13628
13792
|
},
|
|
@@ -13655,6 +13819,10 @@ var package_default = {
|
|
|
13655
13819
|
types: "./dist/testing.d.ts",
|
|
13656
13820
|
import: "./dist/testing.js"
|
|
13657
13821
|
},
|
|
13822
|
+
"./testing/mcp": {
|
|
13823
|
+
types: "./dist/testing-mcp.d.ts",
|
|
13824
|
+
import: "./dist/testing-mcp.js"
|
|
13825
|
+
},
|
|
13658
13826
|
"./documentation": {
|
|
13659
13827
|
types: "./dist/documentation.d.ts",
|
|
13660
13828
|
import: "./dist/documentation.js"
|
|
@@ -13789,18 +13957,18 @@ function gapIsTooWide(from, to) {
|
|
|
13789
13957
|
return from.major === 0 && from.minor < OLDEST_SUPPORTED_MINOR;
|
|
13790
13958
|
}
|
|
13791
13959
|
function readAppSdkVersion(appDir) {
|
|
13792
|
-
const installed =
|
|
13793
|
-
if (
|
|
13960
|
+
const installed = join24(appDir, "node_modules", "deepspace", "package.json");
|
|
13961
|
+
if (existsSync26(installed)) {
|
|
13794
13962
|
const parsed2 = JSON.parse(readFileSync27(installed, "utf8"));
|
|
13795
13963
|
if (typeof parsed2.version === "string") return parsed2.version;
|
|
13796
13964
|
}
|
|
13797
|
-
const manifest =
|
|
13798
|
-
if (!
|
|
13965
|
+
const manifest = join24(appDir, "package.json");
|
|
13966
|
+
if (!existsSync26(manifest)) return null;
|
|
13799
13967
|
const parsed = JSON.parse(readFileSync27(manifest, "utf8"));
|
|
13800
13968
|
return parsed.dependencies?.deepspace ?? null;
|
|
13801
13969
|
}
|
|
13802
13970
|
function pinSdkVersion(appDir, version) {
|
|
13803
|
-
const path =
|
|
13971
|
+
const path = join24(appDir, "package.json");
|
|
13804
13972
|
const source = readFileSync27(path, "utf8");
|
|
13805
13973
|
const manifest = JSON.parse(source);
|
|
13806
13974
|
const dependencies = manifest.dependencies;
|
|
@@ -13827,16 +13995,16 @@ function buildPreviewSecretsUpgradeInstruction(appDir) {
|
|
|
13827
13995
|
"vite.config.mts",
|
|
13828
13996
|
"vite.config.js",
|
|
13829
13997
|
"vite.config.mjs"
|
|
13830
|
-
].find((candidate) =>
|
|
13998
|
+
].find((candidate) => existsSync26(join24(appDir, candidate)));
|
|
13831
13999
|
if (!configName) return null;
|
|
13832
|
-
const source = readFileSync27(
|
|
14000
|
+
const source = readFileSync27(join24(appDir, configName), "utf8");
|
|
13833
14001
|
if (source.includes("deepspace-remove-build-preview-secrets")) return null;
|
|
13834
14002
|
return `${configName}: add the build-preview secret cleanup from ${BUILD_PREVIEW_SECRETS_GUIDE}; app update left this app-owned file unchanged.`;
|
|
13835
14003
|
}
|
|
13836
14004
|
function usersSchemaVisibilityUpgradeInstruction(appDir) {
|
|
13837
14005
|
const schemaName = "src/schemas/users-schema.ts";
|
|
13838
|
-
const path =
|
|
13839
|
-
if (!
|
|
14006
|
+
const path = join24(appDir, schemaName);
|
|
14007
|
+
if (!existsSync26(path)) return null;
|
|
13840
14008
|
const source = readFileSync27(path, "utf8");
|
|
13841
14009
|
if (!/\bmember\s*:\s*\{[^}]*\bread\s*:\s*true\b/s.test(source)) return null;
|
|
13842
14010
|
return `${schemaName}: review the member user-row visibility change at ${USERS_SCHEMA_VISIBILITY_GUIDE}; app update left this app-owned schema unchanged.`;
|
|
@@ -13988,8 +14156,8 @@ var update_default = defineDeepspaceCommand({
|
|
|
13988
14156
|
|
|
13989
14157
|
// src/cli/cli.ts
|
|
13990
14158
|
var __dirname = dirname12(fileURLToPath3(import.meta.url));
|
|
13991
|
-
var pkg = JSON.parse(readFileSync28(
|
|
13992
|
-
if (process.platform === "linux" && !process.env.SSL_CERT_FILE &&
|
|
14159
|
+
var pkg = JSON.parse(readFileSync28(join25(__dirname, "..", "package.json"), "utf-8"));
|
|
14160
|
+
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync27("/etc/ssl/certs/ca-certificates.crt")) {
|
|
13993
14161
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
13994
14162
|
}
|
|
13995
14163
|
var create2 = defineCommand14({
|