deepspace 0.20.0 → 0.21.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 +18 -0
- package/dist/{chunk-A7UFIOWO.js → chunk-KDCDRHBA.js} +7 -2
- package/dist/chunk-KDCDRHBA.js.map +1 -0
- package/dist/cli.js +193 -62
- 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 +21 -0
- package/dist/server.js +148 -39
- 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 +48 -3
- package/dist/worker.js +234 -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
|
@@ -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) {
|
|
@@ -2677,11 +2677,15 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2677
2677
|
}
|
|
2678
2678
|
const url = `http://${host === DEFAULT_DEV_HOST ? "localhost" : host}:${port}`;
|
|
2679
2679
|
say("Starting dev server...\n");
|
|
2680
|
-
const vite = spawn2(
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2680
|
+
const vite = spawn2(
|
|
2681
|
+
"npx",
|
|
2682
|
+
["vite", "--port", String(port), "--strictPort", "--host", host, "--clearScreen", "false"],
|
|
2683
|
+
{
|
|
2684
|
+
cwd: appDir,
|
|
2685
|
+
stdio: "inherit",
|
|
2686
|
+
env: wranglerViteEnv(process.env, wranglerConfig, { DEEPSPACE_PORT: String(port) })
|
|
2687
|
+
}
|
|
2688
|
+
);
|
|
2685
2689
|
const readiness = new AbortController();
|
|
2686
2690
|
if (args.json) {
|
|
2687
2691
|
void waitForPortListening(port, host, READINESS_TIMEOUT_MS, readiness.signal).then((ready) => {
|
|
@@ -3195,7 +3199,7 @@ async function syncTestAccountStore() {
|
|
|
3195
3199
|
// src/cli/commands/test.ts
|
|
3196
3200
|
var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
|
|
3197
3201
|
var PLAYWRIGHT_OUTPUT_DIR = ".deepspace/test-results";
|
|
3198
|
-
function playwrightTestArgs(testFiles) {
|
|
3202
|
+
function playwrightTestArgs(testFiles, flags = {}) {
|
|
3199
3203
|
return [
|
|
3200
3204
|
"playwright",
|
|
3201
3205
|
"test",
|
|
@@ -3203,6 +3207,9 @@ function playwrightTestArgs(testFiles) {
|
|
|
3203
3207
|
"tests/playwright.config.ts",
|
|
3204
3208
|
"--output",
|
|
3205
3209
|
PLAYWRIGHT_OUTPUT_DIR,
|
|
3210
|
+
...flags.grep ? ["--grep", flags.grep] : [],
|
|
3211
|
+
...flags.project ? ["--project", flags.project] : [],
|
|
3212
|
+
...flags.headed ? ["--headed"] : [],
|
|
3206
3213
|
...testFiles
|
|
3207
3214
|
];
|
|
3208
3215
|
}
|
|
@@ -3223,6 +3230,21 @@ var test_default = defineDeepspaceCommand({
|
|
|
3223
3230
|
description: `Port for vite/webServer (default ${DEFAULT_PORT}, or $DEEPSPACE_PORT)`,
|
|
3224
3231
|
required: false
|
|
3225
3232
|
},
|
|
3233
|
+
grep: {
|
|
3234
|
+
type: "string",
|
|
3235
|
+
description: "Only run Playwright tests matching this pattern (forwarded to --grep)",
|
|
3236
|
+
required: false
|
|
3237
|
+
},
|
|
3238
|
+
project: {
|
|
3239
|
+
type: "string",
|
|
3240
|
+
description: "Playwright project to run (forwarded to --project)",
|
|
3241
|
+
required: false
|
|
3242
|
+
},
|
|
3243
|
+
headed: {
|
|
3244
|
+
type: "boolean",
|
|
3245
|
+
description: "Run Playwright browsers headed (forwarded to --headed)",
|
|
3246
|
+
default: false
|
|
3247
|
+
},
|
|
3226
3248
|
env: {
|
|
3227
3249
|
type: "string",
|
|
3228
3250
|
alias: "e",
|
|
@@ -3237,6 +3259,11 @@ var test_default = defineDeepspaceCommand({
|
|
|
3237
3259
|
preflightNodeVersion("test run");
|
|
3238
3260
|
const suite = args.suite ?? "default";
|
|
3239
3261
|
const wranglerEnv = typeof args.env === "string" && args.env.trim() ? args.env.trim() : void 0;
|
|
3262
|
+
const forwarded = {
|
|
3263
|
+
grep: typeof args.grep === "string" && args.grep ? args.grep : void 0,
|
|
3264
|
+
project: typeof args.project === "string" && args.project ? args.project : void 0,
|
|
3265
|
+
headed: Boolean(args.headed)
|
|
3266
|
+
};
|
|
3240
3267
|
const start = resolve9(".");
|
|
3241
3268
|
const appDir = findAppDir(start);
|
|
3242
3269
|
if (!appDir) {
|
|
@@ -3293,32 +3320,36 @@ var test_default = defineDeepspaceCommand({
|
|
|
3293
3320
|
let exitCode = 0;
|
|
3294
3321
|
switch (suite) {
|
|
3295
3322
|
case "smoke":
|
|
3296
|
-
exitCode = runPlaywright(appDir, ["tests/smoke.spec.ts"], port, wranglerEnv);
|
|
3323
|
+
exitCode = runPlaywright(appDir, ["tests/smoke.spec.ts"], port, wranglerEnv, forwarded);
|
|
3297
3324
|
break;
|
|
3298
3325
|
case "api":
|
|
3299
|
-
exitCode = runPlaywright(appDir, ["tests/api.spec.ts"], port, wranglerEnv);
|
|
3326
|
+
exitCode = runPlaywright(appDir, ["tests/api.spec.ts"], port, wranglerEnv, forwarded);
|
|
3300
3327
|
break;
|
|
3301
3328
|
case "e2e":
|
|
3302
|
-
exitCode = runPlaywright(appDir, [], port, wranglerEnv);
|
|
3329
|
+
exitCode = runPlaywright(appDir, [], port, wranglerEnv, forwarded);
|
|
3303
3330
|
break;
|
|
3304
3331
|
case "unit":
|
|
3332
|
+
if (forwarded.grep || forwarded.project || forwarded.headed) {
|
|
3333
|
+
console.error("note: --grep/--project/--headed apply to Playwright suites and are ignored by `unit`");
|
|
3334
|
+
}
|
|
3305
3335
|
exitCode = runVitest(appDir);
|
|
3306
3336
|
break;
|
|
3307
3337
|
case "all":
|
|
3308
3338
|
exitCode = runVitest(appDir);
|
|
3309
|
-
if (exitCode === 0) exitCode = runPlaywright(appDir, [], port, wranglerEnv);
|
|
3339
|
+
if (exitCode === 0) exitCode = runPlaywright(appDir, [], port, wranglerEnv, forwarded);
|
|
3310
3340
|
break;
|
|
3311
3341
|
case "default":
|
|
3312
3342
|
exitCode = runPlaywright(
|
|
3313
3343
|
appDir,
|
|
3314
3344
|
["tests/smoke.spec.ts", "tests/api.spec.ts"],
|
|
3315
3345
|
port,
|
|
3316
|
-
wranglerEnv
|
|
3346
|
+
wranglerEnv,
|
|
3347
|
+
forwarded
|
|
3317
3348
|
);
|
|
3318
3349
|
break;
|
|
3319
3350
|
default:
|
|
3320
3351
|
if (suite.endsWith(".spec.ts")) {
|
|
3321
|
-
exitCode = runPlaywright(appDir, [suite], port, wranglerEnv);
|
|
3352
|
+
exitCode = runPlaywright(appDir, [suite], port, wranglerEnv, forwarded);
|
|
3322
3353
|
} else {
|
|
3323
3354
|
throw new Refusal(
|
|
3324
3355
|
`Unknown test suite: ${suite}
|
|
@@ -3335,7 +3366,7 @@ Available: smoke, api, e2e, unit, all`,
|
|
|
3335
3366
|
return { data: { suite, port, appDir, wranglerEnv: wranglerEnv ?? null } };
|
|
3336
3367
|
}
|
|
3337
3368
|
});
|
|
3338
|
-
function runPlaywright(appDir, testFiles, port, wranglerEnv) {
|
|
3369
|
+
function runPlaywright(appDir, testFiles, port, wranglerEnv, flags) {
|
|
3339
3370
|
let wranglerConfig;
|
|
3340
3371
|
try {
|
|
3341
3372
|
wranglerConfig = prepareWranglerEnvConfig(appDir, wranglerEnv);
|
|
@@ -3344,7 +3375,7 @@ function runPlaywright(appDir, testFiles, port, wranglerEnv) {
|
|
|
3344
3375
|
return 1;
|
|
3345
3376
|
}
|
|
3346
3377
|
try {
|
|
3347
|
-
const result = spawnSync4("npx", playwrightTestArgs(testFiles), {
|
|
3378
|
+
const result = spawnSync4("npx", playwrightTestArgs(testFiles, flags), {
|
|
3348
3379
|
cwd: appDir,
|
|
3349
3380
|
stdio: "inherit",
|
|
3350
3381
|
env: wranglerViteEnv(process.env, wranglerConfig, {
|
|
@@ -3453,7 +3484,7 @@ var create = defineDeepspaceCommand({
|
|
|
3453
3484
|
await ensureToken();
|
|
3454
3485
|
const email = args.email;
|
|
3455
3486
|
const password = args.password;
|
|
3456
|
-
const name = args.name;
|
|
3487
|
+
const name = args.name ?? email.split("@")[0];
|
|
3457
3488
|
const label = args.label;
|
|
3458
3489
|
let account;
|
|
3459
3490
|
try {
|
|
@@ -3477,6 +3508,7 @@ var create = defineDeepspaceCommand({
|
|
|
3477
3508
|
console.log(`Created test account:`);
|
|
3478
3509
|
console.log(` ID: ${account.id}`);
|
|
3479
3510
|
console.log(` Email: ${account.email}`);
|
|
3511
|
+
console.log(` Selector: ${name}`);
|
|
3480
3512
|
console.log(` Password: ${password}`);
|
|
3481
3513
|
console.log(` UserID: ${account.userId}`);
|
|
3482
3514
|
if (account.label) console.log(` Label: ${account.label}`);
|
|
@@ -3487,6 +3519,7 @@ Saved to ${TEST_ACCOUNTS_PATH}`);
|
|
|
3487
3519
|
data: {
|
|
3488
3520
|
id: account.id,
|
|
3489
3521
|
email: account.email,
|
|
3522
|
+
name,
|
|
3490
3523
|
// The password is already echoed on the human path and stored 0600 in
|
|
3491
3524
|
// ACCOUNTS_PATH — withholding it from --json would only force scripts
|
|
3492
3525
|
// to parse the file themselves.
|
|
@@ -3504,6 +3537,18 @@ var list = defineDeepspaceCommand({
|
|
|
3504
3537
|
name: "list",
|
|
3505
3538
|
description: "List your test accounts"
|
|
3506
3539
|
},
|
|
3540
|
+
args: {
|
|
3541
|
+
usable: {
|
|
3542
|
+
type: "boolean",
|
|
3543
|
+
description: "Only accounts with locally saved credentials (usable by the users() fixture)",
|
|
3544
|
+
default: false
|
|
3545
|
+
},
|
|
3546
|
+
reveal: {
|
|
3547
|
+
type: "boolean",
|
|
3548
|
+
description: "Print locally saved passwords instead of masking them",
|
|
3549
|
+
default: false
|
|
3550
|
+
}
|
|
3551
|
+
},
|
|
3507
3552
|
async run({ args }) {
|
|
3508
3553
|
await ensureToken();
|
|
3509
3554
|
let remote;
|
|
@@ -3512,42 +3557,47 @@ var list = defineDeepspaceCommand({
|
|
|
3512
3557
|
} catch (err) {
|
|
3513
3558
|
throw new Refusal(`Failed: ${err.message}`, "test_accounts_list_failed");
|
|
3514
3559
|
}
|
|
3515
|
-
const
|
|
3516
|
-
const
|
|
3517
|
-
|
|
3560
|
+
const localByEmail = new Map(loadAllTestAccounts().map((a) => [a.email, a]));
|
|
3561
|
+
const accounts = remote.map((a) => {
|
|
3562
|
+
const stored = localByEmail.get(a.email);
|
|
3563
|
+
return {
|
|
3564
|
+
id: a.id,
|
|
3565
|
+
email: a.email,
|
|
3566
|
+
userId: a.userId,
|
|
3567
|
+
label: a.label,
|
|
3568
|
+
createdAt: a.createdAt,
|
|
3569
|
+
name: stored?.name ?? null,
|
|
3570
|
+
password: stored?.password ?? null,
|
|
3571
|
+
usableByFixture: Boolean(stored?.password)
|
|
3572
|
+
};
|
|
3573
|
+
}).filter((a) => !args.usable || a.usableByFixture);
|
|
3574
|
+
if (accounts.length === 0) {
|
|
3518
3575
|
if (!args.json) {
|
|
3519
3576
|
console.log(
|
|
3520
|
-
"No test accounts. Create one with: deepspace test accounts create --email <email> --password <password>"
|
|
3577
|
+
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
3578
|
);
|
|
3522
3579
|
}
|
|
3523
3580
|
return { data: { accounts: [], count: 0, limit: 10 } };
|
|
3524
3581
|
}
|
|
3525
3582
|
if (!args.json) {
|
|
3526
|
-
console.log(`Test accounts (${remote.length}/10):
|
|
3583
|
+
console.log(`Test accounts (${remote.length}/10${args.usable ? ", usable only" : ""}):
|
|
3527
3584
|
`);
|
|
3528
|
-
for (const a of
|
|
3529
|
-
const stored = localByEmail.get(a.email);
|
|
3585
|
+
for (const a of accounts) {
|
|
3530
3586
|
const date = new Date(a.createdAt).toLocaleDateString();
|
|
3531
3587
|
console.log(` ${a.email}${a.label ? ` (${a.label})` : ""}`);
|
|
3532
3588
|
console.log(` ID: ${a.id} UserID: ${a.userId} Created: ${date}`);
|
|
3533
|
-
|
|
3534
|
-
|
|
3589
|
+
console.log(` Selector: ${a.name ?? "(none)"}`);
|
|
3590
|
+
if (a.usableByFixture) {
|
|
3591
|
+
console.log(` Password: ${args.reveal ? a.password : "(saved locally)"}`);
|
|
3535
3592
|
} else {
|
|
3536
|
-
console.log(` Password: (not saved locally)`);
|
|
3593
|
+
console.log(` Password: (not saved locally \u2014 not usable by the users() fixture)`);
|
|
3537
3594
|
}
|
|
3538
3595
|
}
|
|
3539
3596
|
}
|
|
3540
3597
|
return {
|
|
3541
3598
|
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,
|
|
3599
|
+
accounts,
|
|
3600
|
+
count: accounts.length,
|
|
3551
3601
|
limit: 10
|
|
3552
3602
|
}
|
|
3553
3603
|
};
|
|
@@ -4417,6 +4467,7 @@ async function buildDeployBundle(options) {
|
|
|
4417
4467
|
if (lintFindings && lintFindings.length > 0) {
|
|
4418
4468
|
p6.log.warn(formatSchemaLintFindings(lintFindings).join("\n"));
|
|
4419
4469
|
}
|
|
4470
|
+
const buildStarted = Date.now();
|
|
4420
4471
|
spinner2.start("Building...");
|
|
4421
4472
|
let preparedWranglerConfig;
|
|
4422
4473
|
try {
|
|
@@ -4439,7 +4490,7 @@ async function buildDeployBundle(options) {
|
|
|
4439
4490
|
} finally {
|
|
4440
4491
|
preparedWranglerConfig?.cleanup();
|
|
4441
4492
|
}
|
|
4442
|
-
spinner2.stop(
|
|
4493
|
+
spinner2.stop(`Built (${Math.round((Date.now() - buildStarted) / 1e3)}s)`);
|
|
4443
4494
|
const deployConfigPath = join15(appDir, ".wrangler", "deploy", "config.json");
|
|
4444
4495
|
if (!existsSync14(deployConfigPath)) {
|
|
4445
4496
|
output.die(
|
|
@@ -4601,6 +4652,51 @@ import * as p7 from "@clack/prompts";
|
|
|
4601
4652
|
import { existsSync as existsSync15 } from "fs";
|
|
4602
4653
|
import { join as join16 } from "path";
|
|
4603
4654
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4655
|
+
|
|
4656
|
+
// src/shared/api-error.ts
|
|
4657
|
+
var SLUG_RE = /^[a-z0-9]+(?:[_.-][a-z0-9]+)*$/;
|
|
4658
|
+
var HUMAN_MESSAGES = {
|
|
4659
|
+
owner_connect_not_ready: "This app isn't ready to accept payments yet \u2014 the app owner needs to finish payment setup.",
|
|
4660
|
+
invalid_json: "The request body was not valid JSON.",
|
|
4661
|
+
invalid_body: "The request body is invalid.",
|
|
4662
|
+
invalid_product_id: "Invalid product id.",
|
|
4663
|
+
duplicate_product_id: "Duplicate product id.",
|
|
4664
|
+
unknown_product: "Unknown product.",
|
|
4665
|
+
too_many_products: "Too many products declared.",
|
|
4666
|
+
invalid_amount: "Invalid amount.",
|
|
4667
|
+
invalid_name: "Invalid product name.",
|
|
4668
|
+
invalid_description: "Invalid product description.",
|
|
4669
|
+
unsupported_currency: "Unsupported currency.",
|
|
4670
|
+
unknown_app: "Unknown app.",
|
|
4671
|
+
not_app_owner: "Only the app owner (or a collaborator) can do this.",
|
|
4672
|
+
invalid_return_url: "Invalid return URL.",
|
|
4673
|
+
invalid_cancel_url: "Invalid cancel URL.",
|
|
4674
|
+
unknown_plan: "Unknown subscription plan.",
|
|
4675
|
+
unknown_price: "No price is configured for that billing interval.",
|
|
4676
|
+
no_subscription: "No subscription found for this account."
|
|
4677
|
+
};
|
|
4678
|
+
function normalizeApiError(status3, body) {
|
|
4679
|
+
const payload = body !== null && typeof body === "object" ? body : {};
|
|
4680
|
+
const rawError = typeof payload.error === "string" ? payload.error : void 0;
|
|
4681
|
+
const message = typeof payload.message === "string" ? payload.message : void 0;
|
|
4682
|
+
const humanError = rawError !== void 0 && !SLUG_RE.test(rawError) ? rawError : void 0;
|
|
4683
|
+
const code = rawError !== void 0 && SLUG_RE.test(rawError) ? rawError : typeof payload.code === "string" && SLUG_RE.test(payload.code) ? payload.code : void 0;
|
|
4684
|
+
const details = {};
|
|
4685
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
4686
|
+
if (key === "success" || key === "error" || key === "message" || key === "issues" || key === "code")
|
|
4687
|
+
continue;
|
|
4688
|
+
details[key] = value;
|
|
4689
|
+
}
|
|
4690
|
+
return {
|
|
4691
|
+
error: message ?? humanError ?? (code !== void 0 ? HUMAN_MESSAGES[code] : void 0) ?? rawError ?? `Request failed (${status3})`,
|
|
4692
|
+
...code !== void 0 ? { code } : {},
|
|
4693
|
+
status: status3,
|
|
4694
|
+
...Object.keys(details).length > 0 ? { details } : {},
|
|
4695
|
+
...Array.isArray(payload.issues) ? { issues: payload.issues } : {}
|
|
4696
|
+
};
|
|
4697
|
+
}
|
|
4698
|
+
|
|
4699
|
+
// src/cli/commands/deploy/commerce.ts
|
|
4604
4700
|
var API_URL2 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4605
4701
|
function errorMessage2(error) {
|
|
4606
4702
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -4674,7 +4770,7 @@ Stripe will keep charging them until you cancel. Cancel at the end of their curr
|
|
|
4674
4770
|
});
|
|
4675
4771
|
const body = await response.json().catch(() => ({}));
|
|
4676
4772
|
if (!response.ok || !body.success) {
|
|
4677
|
-
lastError = body.error
|
|
4773
|
+
lastError = normalizeApiError(response.status, body).error;
|
|
4678
4774
|
spinner2.stop(`Cancel failed for ${change.slug}: ${lastError}`);
|
|
4679
4775
|
stopped = true;
|
|
4680
4776
|
break;
|
|
@@ -4732,7 +4828,7 @@ async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
|
4732
4828
|
if (!response.ok || !body.ok) {
|
|
4733
4829
|
spinner2.stop("Plan sync skipped");
|
|
4734
4830
|
p7.log.warn(
|
|
4735
|
-
`Plan sync failed: ${body.error
|
|
4831
|
+
`Plan sync failed: ${normalizeApiError(response.status, body).error}${body.hint ? ` \u2014 ${body.hint}` : ""}`
|
|
4736
4832
|
);
|
|
4737
4833
|
return;
|
|
4738
4834
|
}
|
|
@@ -4790,7 +4886,7 @@ async function syncOneTimeProducts(appDir, appName, token) {
|
|
|
4790
4886
|
}
|
|
4791
4887
|
spinner2?.stop("Product sync skipped");
|
|
4792
4888
|
p7.log.warn(
|
|
4793
|
-
`Product sync failed: ${body.error
|
|
4889
|
+
`Product sync failed: ${normalizeApiError(response.status, body).error}${body.details ? ` \u2014 ${JSON.stringify(body.details)}` : ""}`
|
|
4794
4890
|
);
|
|
4795
4891
|
} catch (error) {
|
|
4796
4892
|
spinner2?.stop("Product sync skipped");
|
|
@@ -5658,7 +5754,7 @@ function detachedHeadRefusal() {
|
|
|
5658
5754
|
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
5755
|
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
5756
|
var REQUIRED_ASSET_TRANSPORT = "content-addressed-v1";
|
|
5661
|
-
var UPLOAD_CONCURRENCY =
|
|
5757
|
+
var UPLOAD_CONCURRENCY = 16;
|
|
5662
5758
|
async function deployBuiltBundle(options) {
|
|
5663
5759
|
const {
|
|
5664
5760
|
deployUrl,
|
|
@@ -5747,15 +5843,19 @@ async function deployBuiltBundle(options) {
|
|
|
5747
5843
|
form.append("deployKey", repository.deployKey);
|
|
5748
5844
|
return form;
|
|
5749
5845
|
};
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5846
|
+
let commitStarted = Date.now();
|
|
5847
|
+
const postCommit = async () => {
|
|
5848
|
+
commitStarted = Date.now();
|
|
5849
|
+
return postWithRetry(
|
|
5850
|
+
`${deployUrl}/api/deploy/${appId}`,
|
|
5851
|
+
() => ({
|
|
5852
|
+
method: "POST",
|
|
5853
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
5854
|
+
body: makeForm()
|
|
5855
|
+
}),
|
|
5856
|
+
{ retryServerErrors: false, attempts: 2, timeoutMs: 24e4 }
|
|
5857
|
+
);
|
|
5858
|
+
};
|
|
5759
5859
|
let response;
|
|
5760
5860
|
try {
|
|
5761
5861
|
response = await postCommit();
|
|
@@ -5802,6 +5902,7 @@ async function deployBuiltBundle(options) {
|
|
|
5802
5902
|
body.code
|
|
5803
5903
|
);
|
|
5804
5904
|
}
|
|
5905
|
+
p10.log.info(`Platform commit: ${Math.round((Date.now() - commitStarted) / 1e3)}s`);
|
|
5805
5906
|
if (body.onBehalfOfOwner) {
|
|
5806
5907
|
p10.log.warn("This release is attributed to the app's owner, not to your account.");
|
|
5807
5908
|
}
|
|
@@ -5920,8 +6021,12 @@ async function uploadDeployAssets(options) {
|
|
|
5920
6021
|
spinner2.message(`Uploading assets \u2014 ${uploaded}/${total}...`);
|
|
5921
6022
|
}
|
|
5922
6023
|
};
|
|
6024
|
+
const uploadStarted = Date.now();
|
|
5923
6025
|
try {
|
|
5924
6026
|
await Promise.all(Array.from({ length: Math.min(UPLOAD_CONCURRENCY, missing.length) }, worker));
|
|
6027
|
+
p10.log.info(
|
|
6028
|
+
`Uploaded ${total} file(s) in ${Math.round((Date.now() - uploadStarted) / 1e3)}s`
|
|
6029
|
+
);
|
|
5925
6030
|
} catch (error) {
|
|
5926
6031
|
spinner2.stop("Deploy failed");
|
|
5927
6032
|
if (error instanceof AssetUploadError) {
|
|
@@ -5967,13 +6072,14 @@ function errorMessage4(error) {
|
|
|
5967
6072
|
}
|
|
5968
6073
|
async function postWithRetry(url, makeInit, {
|
|
5969
6074
|
attempts = 4,
|
|
5970
|
-
retryServerErrors = true
|
|
6075
|
+
retryServerErrors = true,
|
|
6076
|
+
timeoutMs = 6e4
|
|
5971
6077
|
} = {}) {
|
|
5972
6078
|
let lastResponse;
|
|
5973
6079
|
let lastError;
|
|
5974
6080
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
5975
6081
|
try {
|
|
5976
|
-
const response = await fetch(url, makeInit());
|
|
6082
|
+
const response = await fetch(url, { ...makeInit(), signal: AbortSignal.timeout(timeoutMs) });
|
|
5977
6083
|
const transient = retryServerErrors && (response.status >= 500 || response.status === 408 || response.status === 429);
|
|
5978
6084
|
if (!transient) return response;
|
|
5979
6085
|
lastResponse = response;
|
|
@@ -6218,6 +6324,7 @@ var deploy_default = defineCommand3({
|
|
|
6218
6324
|
spinner: spinner2
|
|
6219
6325
|
});
|
|
6220
6326
|
let serving = "unverifiable";
|
|
6327
|
+
const edgeWaitStarted = Date.now();
|
|
6221
6328
|
if (body.url) {
|
|
6222
6329
|
spinner2.message("Waiting for the edge to serve this release...");
|
|
6223
6330
|
serving = await waitForLiveRelease(body.url, body.releaseStamp, 9e4);
|
|
@@ -6247,7 +6354,9 @@ var deploy_default = defineCommand3({
|
|
|
6247
6354
|
return;
|
|
6248
6355
|
}
|
|
6249
6356
|
}
|
|
6250
|
-
spinner2.stop(
|
|
6357
|
+
spinner2.stop(
|
|
6358
|
+
`Deployed! (edge confirmed in ${Math.round((Date.now() - edgeWaitStarted) / 1e3)}s)`
|
|
6359
|
+
);
|
|
6251
6360
|
p12.log.success(`Live at: ${body.url}`);
|
|
6252
6361
|
await syncCommerce(appDir, appId, token, output.nonInteractive);
|
|
6253
6362
|
if (output.json) {
|
|
@@ -6508,7 +6617,10 @@ var undeploy_default = defineDeepspaceCommand({
|
|
|
6508
6617
|
}
|
|
6509
6618
|
);
|
|
6510
6619
|
}
|
|
6511
|
-
throw new Refusal(
|
|
6620
|
+
throw new Refusal(
|
|
6621
|
+
body.error ?? `Undeploy error (${res.status})`,
|
|
6622
|
+
body.code ?? "undeploy_failed"
|
|
6623
|
+
);
|
|
6512
6624
|
}
|
|
6513
6625
|
s?.stop("Removed");
|
|
6514
6626
|
const hosts = body.releasedHosts ?? [];
|
|
@@ -9205,7 +9317,9 @@ async function runList(args) {
|
|
|
9205
9317
|
for (const ep of endpoints) {
|
|
9206
9318
|
const pad = ep.endpoint.padEnd(widest);
|
|
9207
9319
|
const cost = formatCurrency(ep.billing.baseCost, ep.billing.currency);
|
|
9208
|
-
|
|
9320
|
+
const oauth = ep.requiresOAuth ? " [oauth]" : "";
|
|
9321
|
+
console.log(` ${pad} ${ep.billing.model.padEnd(12)} ${cost}${oauth}`);
|
|
9322
|
+
if (ep.description) console.log(` ${ep.description}`);
|
|
9209
9323
|
}
|
|
9210
9324
|
console.log();
|
|
9211
9325
|
}
|
|
@@ -9234,9 +9348,15 @@ async function runInfo(args) {
|
|
|
9234
9348
|
}
|
|
9235
9349
|
if (!args.json) {
|
|
9236
9350
|
console.log(`${integration}/${endpoint}`);
|
|
9351
|
+
if (info2.description) console.log(` ${info2.description}`);
|
|
9237
9352
|
console.log(
|
|
9238
9353
|
` billing: ${formatCurrency(info2.billing.baseCost, info2.billing.currency)} ${billingUnit(info2.billing.model)}`
|
|
9239
9354
|
);
|
|
9355
|
+
if (info2.requiresOAuth) {
|
|
9356
|
+
console.log(
|
|
9357
|
+
" Requires OAuth: without a connected account, a call succeeds with data { requiresOAuth: true, authUrl } \u2014 open the authUrl, then retry."
|
|
9358
|
+
);
|
|
9359
|
+
}
|
|
9240
9360
|
console.log();
|
|
9241
9361
|
console.log("Input schema:");
|
|
9242
9362
|
console.log(
|
|
@@ -9245,6 +9365,11 @@ async function runInfo(args) {
|
|
|
9245
9365
|
console.log();
|
|
9246
9366
|
console.log("Example body:");
|
|
9247
9367
|
console.log(info2.example ? JSON.stringify(info2.example, null, 2) : " (no example available)");
|
|
9368
|
+
if (info2.outputSchema) {
|
|
9369
|
+
console.log();
|
|
9370
|
+
console.log("Output schema:");
|
|
9371
|
+
console.log(JSON.stringify(info2.outputSchema, null, 2));
|
|
9372
|
+
}
|
|
9248
9373
|
}
|
|
9249
9374
|
return { data: info2 };
|
|
9250
9375
|
}
|
|
@@ -9325,17 +9450,19 @@ async function runInvoke(args) {
|
|
|
9325
9450
|
}
|
|
9326
9451
|
return { data: payload };
|
|
9327
9452
|
}
|
|
9328
|
-
const
|
|
9329
|
-
const lines = [`${integration}/${endpoint} (${res.status}, ${elapsed}ms): ${
|
|
9330
|
-
if (
|
|
9331
|
-
for (const issue of
|
|
9453
|
+
const norm = normalizeApiError(res.status, payload);
|
|
9454
|
+
const lines = [`${integration}/${endpoint} (${res.status}, ${elapsed}ms): ${norm.error}`];
|
|
9455
|
+
if (norm.issues) {
|
|
9456
|
+
for (const issue of norm.issues) {
|
|
9332
9457
|
const path = issue.path?.length ? issue.path.join(".") : "(root)";
|
|
9333
9458
|
lines.push(` - ${path}: ${issue.message}`);
|
|
9334
9459
|
}
|
|
9335
9460
|
}
|
|
9336
|
-
const code =
|
|
9461
|
+
const code = norm.code ?? "integration_call_failed";
|
|
9337
9462
|
const rest = { ...payload };
|
|
9338
9463
|
delete rest.error;
|
|
9464
|
+
delete rest.message;
|
|
9465
|
+
delete rest.code;
|
|
9339
9466
|
throw new Refusal(lines.join("\n"), code, {
|
|
9340
9467
|
...res.status === 401 ? { action: cliAction("deepspace", "auth", "login") } : {},
|
|
9341
9468
|
extra: rest
|
|
@@ -12581,7 +12708,7 @@ function conflictMarkerFiles(diffCheckOutput) {
|
|
|
12581
12708
|
function pullAfterLandAction(primaryDir, intoBranch, landedOid) {
|
|
12582
12709
|
if (currentBranch(primaryDir) !== intoBranch) return null;
|
|
12583
12710
|
if (resolveCommit(primaryDir, "HEAD") === landedOid) return null;
|
|
12584
|
-
return { cwd: primaryDir, argv: ["deepspace", "pull"] };
|
|
12711
|
+
return executableAction({ cwd: primaryDir, argv: ["deepspace", "pull"] });
|
|
12585
12712
|
}
|
|
12586
12713
|
function landResumeArgv(args) {
|
|
12587
12714
|
const argv = ["deepspace", "workspace", "land"];
|
|
@@ -12862,6 +12989,7 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12862
12989
|
}
|
|
12863
12990
|
spinner2?.stop(`Landed ${id} into ${intoBranch} at ${landedOid.slice(0, 10)}.`);
|
|
12864
12991
|
const primaryDir = primaryAppDir(appDir);
|
|
12992
|
+
const action = pullAfterLandAction(primaryDir, intoBranch, landedOid);
|
|
12865
12993
|
const cleanup = keepWorktree ? null : cleanupWorkspaceLocal(appDir, id, intoBranch, { expectedBranchOid: landedOid });
|
|
12866
12994
|
const inOwnWorktree = !cleanup && inOwnLinkedWorktree(appDir, id);
|
|
12867
12995
|
const retainedWorktree = cleanup?.worktreeRetained ?? (keepWorktree || inOwnWorktree ? appDir : null);
|
|
@@ -12895,7 +13023,6 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12895
13023
|
{ actionRequired: true, action: action2, extra: data }
|
|
12896
13024
|
);
|
|
12897
13025
|
}
|
|
12898
|
-
const action = pullAfterLandAction(primaryDir, intoBranch, landedOid);
|
|
12899
13026
|
return { data, ...action ? { action } : {} };
|
|
12900
13027
|
}
|
|
12901
13028
|
});
|
|
@@ -13622,7 +13749,7 @@ import { join as join23, resolve as resolve20 } from "path";
|
|
|
13622
13749
|
// package.json
|
|
13623
13750
|
var package_default = {
|
|
13624
13751
|
name: "deepspace",
|
|
13625
|
-
version: "0.
|
|
13752
|
+
version: "0.21.0",
|
|
13626
13753
|
engines: {
|
|
13627
13754
|
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
13628
13755
|
},
|
|
@@ -13655,6 +13782,10 @@ var package_default = {
|
|
|
13655
13782
|
types: "./dist/testing.d.ts",
|
|
13656
13783
|
import: "./dist/testing.js"
|
|
13657
13784
|
},
|
|
13785
|
+
"./testing/mcp": {
|
|
13786
|
+
types: "./dist/testing-mcp.d.ts",
|
|
13787
|
+
import: "./dist/testing-mcp.js"
|
|
13788
|
+
},
|
|
13658
13789
|
"./documentation": {
|
|
13659
13790
|
types: "./dist/documentation.d.ts",
|
|
13660
13791
|
import: "./dist/documentation.js"
|