deepspace 0.19.0 → 0.19.2
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 +32 -0
- package/dist/cli.js +558 -261
- package/dist/cli.js.map +1 -1
- package/dist/feature-installer.js +14 -5
- package/dist/feature-installer.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.js +42 -11
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +12 -7
- package/dist/server.js +63 -19
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +9 -2
- package/dist/worker.js +63 -19
- package/dist/worker.js.map +1 -1
- package/features/admin-page/feature.json +3 -4
- package/features/admin-page/src/AdminPage.tsx +4 -4
- package/features/cron/feature.json +8 -5
- package/features/documents/feature.json +2 -1
- package/features/documents/src/DocumentsEditorPage.tsx +31 -10
- package/features/documents/src/DocumentsListPage.tsx +59 -26
- package/features/documents/src/InviteDialog.tsx +49 -14
- package/features/documents/src/LibrarySidebar.tsx +92 -84
- package/features/documents/src/__tests__/documents-presence-access.test.ts +15 -2
- package/features/documents/src/documents-library-types.ts +6 -0
- package/features/tasks/src/TasksPage.tsx +1 -1
- package/features/tasks/src/tasks-schema.ts +1 -1
- package/package.json +5 -5
- package/features/cron/src/cron.ts +0 -25
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
|
|
11
|
+
import { readFileSync as readFileSync28, existsSync as existsSync26 } from "fs";
|
|
12
|
+
import { dirname as dirname12, join as join24 } from "path";
|
|
13
13
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
14
14
|
|
|
15
15
|
// src/cli/lib/spinner.ts
|
|
@@ -205,6 +205,13 @@ var InputError = class extends Error {
|
|
|
205
205
|
this.code = code;
|
|
206
206
|
}
|
|
207
207
|
};
|
|
208
|
+
var CliExit = class extends Error {
|
|
209
|
+
constructor(exitCode) {
|
|
210
|
+
super(`exit ${exitCode}`);
|
|
211
|
+
this.exitCode = exitCode;
|
|
212
|
+
this.name = "CliExit";
|
|
213
|
+
}
|
|
214
|
+
};
|
|
208
215
|
function errorCode(err) {
|
|
209
216
|
if (err instanceof ApiError || err instanceof InputError) return err.code;
|
|
210
217
|
if (err instanceof Error && err.name === "GitError") return err.code ?? "git_error";
|
|
@@ -230,12 +237,17 @@ function formatCliError(err) {
|
|
|
230
237
|
${hint}` : message;
|
|
231
238
|
}
|
|
232
239
|
function renderCliError(err) {
|
|
240
|
+
if (err instanceof CliExit) {
|
|
241
|
+
process.exitCode = err.exitCode;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
233
244
|
stopActiveSpinner();
|
|
234
245
|
const message = formatCliError(err);
|
|
235
246
|
const slug = errorCode(err);
|
|
236
247
|
if (process.argv.includes("--json")) {
|
|
237
248
|
console.log(JSON.stringify({ ok: false, ...slug ? { code: slug } : {}, error: message }));
|
|
238
|
-
process.
|
|
249
|
+
process.exitCode = 1;
|
|
250
|
+
return;
|
|
239
251
|
}
|
|
240
252
|
console.error(slug ? withSlug(message, slug) : message);
|
|
241
253
|
if (process.env.DEBUG) {
|
|
@@ -244,7 +256,7 @@ function renderCliError(err) {
|
|
|
244
256
|
API ${apiPath}${status3 ? ` (${status3})` : ""}`);
|
|
245
257
|
if (err instanceof Error && err.stack) console.error("\n" + err.stack);
|
|
246
258
|
}
|
|
247
|
-
process.
|
|
259
|
+
process.exitCode = 1;
|
|
248
260
|
}
|
|
249
261
|
function wrapCommandErrors(cmd) {
|
|
250
262
|
const run2 = cmd.run;
|
|
@@ -301,10 +313,9 @@ function withoutReservedKeys(payload) {
|
|
|
301
313
|
)
|
|
302
314
|
);
|
|
303
315
|
}
|
|
304
|
-
function
|
|
305
|
-
|
|
306
|
-
process.
|
|
307
|
-
return void 0;
|
|
316
|
+
function finishCommand(code) {
|
|
317
|
+
stopActiveSpinner();
|
|
318
|
+
process.exitCode = code;
|
|
308
319
|
}
|
|
309
320
|
function nameVariants(name) {
|
|
310
321
|
return [
|
|
@@ -398,9 +409,9 @@ function defineDeepspaceCommand(def) {
|
|
|
398
409
|
else p3.log.error(line);
|
|
399
410
|
if (refusal?.action) printAction(refusal.action);
|
|
400
411
|
}
|
|
401
|
-
|
|
412
|
+
finishCommand(refusal?.actionRequired ? 2 : 1);
|
|
402
413
|
}
|
|
403
|
-
if (succeeded)
|
|
414
|
+
if (succeeded) finishCommand(0);
|
|
404
415
|
}
|
|
405
416
|
});
|
|
406
417
|
}
|
|
@@ -515,7 +526,7 @@ function effectivePlatformUrls(env = process.env) {
|
|
|
515
526
|
var DASHBOARD_URL = DEEPSPACE_ENV === "production" ? "https://dashboard.deep.space" : DEEPSPACE_ENV === "staging" ? "https://dashboard.deepspacesites.com" : "http://127.0.0.1:9";
|
|
516
527
|
|
|
517
528
|
// src/cli/auth.ts
|
|
518
|
-
import { readFileSync as readFileSync2,
|
|
529
|
+
import { readFileSync as readFileSync2, existsSync, mkdirSync } from "fs";
|
|
519
530
|
import { join } from "path";
|
|
520
531
|
import { homedir } from "os";
|
|
521
532
|
|
|
@@ -543,6 +554,16 @@ async function exchangeSession(authUrl, sessionToken) {
|
|
|
543
554
|
return data.token ?? null;
|
|
544
555
|
}
|
|
545
556
|
|
|
557
|
+
// src/cli/lib/secure-file.ts
|
|
558
|
+
import { chmodSync, writeFileSync } from "fs";
|
|
559
|
+
function writeSecretFileSync(path, content) {
|
|
560
|
+
writeFileSync(path, content, { mode: 384 });
|
|
561
|
+
try {
|
|
562
|
+
chmodSync(path, 384);
|
|
563
|
+
} catch {
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
546
567
|
// src/cli/auth.ts
|
|
547
568
|
var AUTH_URL = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
|
|
548
569
|
var PROD_AUTH_URL = "https://auth.deep.space";
|
|
@@ -585,7 +606,7 @@ async function ensureToken() {
|
|
|
585
606
|
);
|
|
586
607
|
}
|
|
587
608
|
mkdirSync(DIR, { recursive: true, mode: 448 });
|
|
588
|
-
|
|
609
|
+
writeSecretFileSync(TOKEN_PATH, token);
|
|
589
610
|
return token;
|
|
590
611
|
}
|
|
591
612
|
function isTokenValid(jwt) {
|
|
@@ -603,7 +624,7 @@ registerAuthRefresh(async () => {
|
|
|
603
624
|
const token = await exchangeSession(AUTH_URL, sessionToken);
|
|
604
625
|
if (!token) return null;
|
|
605
626
|
mkdirSync(DIR, { recursive: true, mode: 448 });
|
|
606
|
-
|
|
627
|
+
writeSecretFileSync(TOKEN_PATH, token);
|
|
607
628
|
return token;
|
|
608
629
|
} catch {
|
|
609
630
|
return null;
|
|
@@ -611,19 +632,18 @@ registerAuthRefresh(async () => {
|
|
|
611
632
|
});
|
|
612
633
|
|
|
613
634
|
// src/cli/commands/login.ts
|
|
614
|
-
import {
|
|
615
|
-
import {
|
|
616
|
-
import { homedir as homedir2 } from "os";
|
|
635
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3 } from "fs";
|
|
636
|
+
import { dirname as dirname2 } from "path";
|
|
617
637
|
import { randomBytes, createHash } from "crypto";
|
|
618
638
|
import * as p4 from "@clack/prompts";
|
|
619
639
|
|
|
620
640
|
// src/cli/lib/open-browser.ts
|
|
621
|
-
import {
|
|
641
|
+
import { spawn } from "child_process";
|
|
622
642
|
function openBrowser(url) {
|
|
623
643
|
const quoted = JSON.stringify(url);
|
|
624
644
|
const cmd = process.platform === "darwin" ? `open ${quoted}` : process.platform === "win32" ? `start "" ${quoted}` : `xdg-open ${quoted}`;
|
|
625
|
-
|
|
626
|
-
});
|
|
645
|
+
spawn(cmd, { shell: true, detached: true, stdio: "ignore", windowsHide: true }).on("error", () => {
|
|
646
|
+
}).unref();
|
|
627
647
|
}
|
|
628
648
|
|
|
629
649
|
// src/cli/commands/login.ts
|
|
@@ -716,9 +736,13 @@ var login_default = defineDeepspaceCommand({
|
|
|
716
736
|
if (!json) s.start("Waiting for authentication...");
|
|
717
737
|
const result = await pollForCompletion(sessionId, codeVerifier);
|
|
718
738
|
if (!result) {
|
|
719
|
-
throw new Refusal(
|
|
720
|
-
|
|
721
|
-
|
|
739
|
+
throw new Refusal(
|
|
740
|
+
"Login timed out. Run `deepspace auth login` to try again.",
|
|
741
|
+
"login_timeout",
|
|
742
|
+
{
|
|
743
|
+
action: cliAction("deepspace", "auth", "login")
|
|
744
|
+
}
|
|
745
|
+
);
|
|
722
746
|
}
|
|
723
747
|
storeCredentials(result.sessionToken, result.jwt);
|
|
724
748
|
await provisionProfile(result.jwt);
|
|
@@ -798,11 +822,10 @@ async function pollForCompletion(sessionId, codeVerifier) {
|
|
|
798
822
|
return null;
|
|
799
823
|
}
|
|
800
824
|
function storeCredentials(sessionToken, jwt) {
|
|
801
|
-
const dir = join2(homedir2(), ".deepspace");
|
|
802
|
-
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
803
825
|
const { sessionPath, tokenPath } = credentialPaths(AUTH_URL2);
|
|
804
|
-
|
|
805
|
-
|
|
826
|
+
mkdirSync2(dirname2(sessionPath), { recursive: true, mode: 448 });
|
|
827
|
+
writeSecretFileSync(sessionPath, sessionToken);
|
|
828
|
+
writeSecretFileSync(tokenPath, jwt);
|
|
806
829
|
}
|
|
807
830
|
async function provisionProfile(jwt) {
|
|
808
831
|
try {
|
|
@@ -883,8 +906,8 @@ var logout_default = defineDeepspaceCommand({
|
|
|
883
906
|
});
|
|
884
907
|
|
|
885
908
|
// src/cli/lib/app-identity.ts
|
|
886
|
-
import { existsSync as existsSync3, readFileSync as readFileSync5, writeFileSync as
|
|
887
|
-
import { join as
|
|
909
|
+
import { existsSync as existsSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
910
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
888
911
|
import { parse as parseToml } from "smol-toml";
|
|
889
912
|
|
|
890
913
|
// src/server/utils/registry-client.ts
|
|
@@ -919,7 +942,7 @@ function mintAppId(now = Date.now()) {
|
|
|
919
942
|
return `app_${mintUlid(now)}`;
|
|
920
943
|
}
|
|
921
944
|
function readWranglerIdentityConfig(cwd) {
|
|
922
|
-
const wranglerPath =
|
|
945
|
+
const wranglerPath = join2(resolve2(cwd), "wrangler.toml");
|
|
923
946
|
if (!existsSync3(wranglerPath)) return null;
|
|
924
947
|
try {
|
|
925
948
|
return parseToml(readFileSync5(wranglerPath, "utf-8"));
|
|
@@ -938,7 +961,7 @@ function readAppId(cwd = process.cwd(), wranglerEnv) {
|
|
|
938
961
|
return typeof id === "string" && APP_ID_RE.test(id) ? id : null;
|
|
939
962
|
}
|
|
940
963
|
function writeAppId(cwd, appId, opts = {}) {
|
|
941
|
-
const wranglerPath =
|
|
964
|
+
const wranglerPath = join2(resolve2(cwd), "wrangler.toml");
|
|
942
965
|
if (!existsSync3(wranglerPath)) {
|
|
943
966
|
throw new Error(`No wrangler.toml in ${resolve2(cwd)}`);
|
|
944
967
|
}
|
|
@@ -971,19 +994,19 @@ ${header}
|
|
|
971
994
|
${line}
|
|
972
995
|
`;
|
|
973
996
|
}
|
|
974
|
-
|
|
997
|
+
writeFileSync2(wranglerPath, src);
|
|
975
998
|
}
|
|
976
999
|
|
|
977
1000
|
// src/cli/commands/dev.ts
|
|
978
|
-
import { resolve as resolve8, basename as basename2, join as
|
|
979
|
-
import
|
|
1001
|
+
import { resolve as resolve8, basename as basename2, join as join11 } from "path";
|
|
1002
|
+
import spawn2 from "cross-spawn";
|
|
980
1003
|
|
|
981
1004
|
// src/cli/lib/app-context.ts
|
|
982
1005
|
import { existsSync as existsSync4, readFileSync as readFileSync6, readdirSync } from "fs";
|
|
983
|
-
import { dirname as
|
|
1006
|
+
import { dirname as dirname3, join as join3, resolve as resolve3 } from "path";
|
|
984
1007
|
import { parse as parseToml2 } from "smol-toml";
|
|
985
1008
|
function detectAppName(cwd = process.cwd()) {
|
|
986
|
-
const wranglerPath =
|
|
1009
|
+
const wranglerPath = join3(resolve3(cwd), "wrangler.toml");
|
|
987
1010
|
if (!existsSync4(wranglerPath)) return null;
|
|
988
1011
|
try {
|
|
989
1012
|
const config = parseToml2(readFileSync6(wranglerPath, "utf-8"));
|
|
@@ -998,15 +1021,15 @@ function detectAppName(cwd = process.cwd()) {
|
|
|
998
1021
|
function findAppDir(start = process.cwd()) {
|
|
999
1022
|
let dir = resolve3(start);
|
|
1000
1023
|
for (; ; ) {
|
|
1001
|
-
if (existsSync4(
|
|
1002
|
-
const parent =
|
|
1024
|
+
if (existsSync4(join3(dir, "wrangler.toml"))) return dir;
|
|
1025
|
+
const parent = dirname3(dir);
|
|
1003
1026
|
if (parent === dir) return null;
|
|
1004
1027
|
dir = parent;
|
|
1005
1028
|
}
|
|
1006
1029
|
}
|
|
1007
1030
|
function findChildApps(dir) {
|
|
1008
1031
|
try {
|
|
1009
|
-
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync4(
|
|
1032
|
+
return readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync4(join3(dir, entry.name, "wrangler.toml"))).map((entry) => entry.name).sort();
|
|
1010
1033
|
} catch {
|
|
1011
1034
|
return [];
|
|
1012
1035
|
}
|
|
@@ -1017,16 +1040,16 @@ import {
|
|
|
1017
1040
|
existsSync as existsSync5,
|
|
1018
1041
|
readFileSync as readFileSync8,
|
|
1019
1042
|
realpathSync as realpathSync2,
|
|
1020
|
-
writeFileSync as
|
|
1043
|
+
writeFileSync as writeFileSync3,
|
|
1021
1044
|
mkdirSync as mkdirSync4,
|
|
1022
1045
|
renameSync,
|
|
1023
1046
|
unlinkSync
|
|
1024
1047
|
} from "fs";
|
|
1025
|
-
import { join as
|
|
1048
|
+
import { join as join5, resolve as resolve5, dirname as dirname5, basename, isAbsolute as isAbsolute2, sep } from "path";
|
|
1026
1049
|
|
|
1027
1050
|
// src/cli/lib/git/repository.ts
|
|
1028
1051
|
import { appendFileSync, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "fs";
|
|
1029
|
-
import { dirname as
|
|
1052
|
+
import { dirname as dirname4, join as join4, resolve as resolve4 } from "path";
|
|
1030
1053
|
|
|
1031
1054
|
// src/cli/lib/git/process.ts
|
|
1032
1055
|
import { sync as spawnSync } from "cross-spawn";
|
|
@@ -1230,7 +1253,7 @@ function listWorktrees(cwd) {
|
|
|
1230
1253
|
}
|
|
1231
1254
|
function ensureLocalExclude(cwd, pattern) {
|
|
1232
1255
|
const commonDir = resolve4(cwd, gitLine(cwd, ["rev-parse", "--git-common-dir"]));
|
|
1233
|
-
const excludePath =
|
|
1256
|
+
const excludePath = join4(commonDir, "info", "exclude");
|
|
1234
1257
|
let current = "";
|
|
1235
1258
|
try {
|
|
1236
1259
|
current = readFileSync7(excludePath, "utf-8");
|
|
@@ -1238,7 +1261,7 @@ function ensureLocalExclude(cwd, pattern) {
|
|
|
1238
1261
|
}
|
|
1239
1262
|
if (current.split("\n").some((line) => line.trim() === pattern)) return;
|
|
1240
1263
|
try {
|
|
1241
|
-
mkdirSync3(
|
|
1264
|
+
mkdirSync3(dirname4(excludePath), { recursive: true });
|
|
1242
1265
|
appendFileSync(
|
|
1243
1266
|
excludePath,
|
|
1244
1267
|
`${current.endsWith("\n") || current === "" ? "" : "\n"}${pattern}
|
|
@@ -1250,9 +1273,9 @@ function ensureLocalExclude(cwd, pattern) {
|
|
|
1250
1273
|
|
|
1251
1274
|
// src/cli/lib/launch-config.ts
|
|
1252
1275
|
function writeLaunchFile(launchPath, config) {
|
|
1253
|
-
mkdirSync4(
|
|
1276
|
+
mkdirSync4(dirname5(launchPath), { recursive: true });
|
|
1254
1277
|
const tmpPath = `${launchPath}.${process.pid}.tmp`;
|
|
1255
|
-
|
|
1278
|
+
writeFileSync3(tmpPath, JSON.stringify(config, null, 2) + "\n");
|
|
1256
1279
|
try {
|
|
1257
1280
|
renameSync(tmpPath, launchPath);
|
|
1258
1281
|
} catch (err) {
|
|
@@ -1273,7 +1296,7 @@ function readLaunchFile(launchPath) {
|
|
|
1273
1296
|
return parsed;
|
|
1274
1297
|
}
|
|
1275
1298
|
function writeLaunchConfigIfMissing(appDir, appName, port, opts = {}) {
|
|
1276
|
-
const launchPath =
|
|
1299
|
+
const launchPath = join5(appDir, ".claude", "launch.json");
|
|
1277
1300
|
try {
|
|
1278
1301
|
const config = readLaunchFile(launchPath);
|
|
1279
1302
|
if (!config) return;
|
|
@@ -1314,7 +1337,7 @@ function writeLaunchConfigIfMissing(appDir, appName, port, opts = {}) {
|
|
|
1314
1337
|
}
|
|
1315
1338
|
function resolveAppLaunchPort(appDir) {
|
|
1316
1339
|
try {
|
|
1317
|
-
const config = readLaunchFile(
|
|
1340
|
+
const config = readLaunchFile(join5(appDir, ".claude", "launch.json"));
|
|
1318
1341
|
if (!config) return null;
|
|
1319
1342
|
const appName = detectAppName(appDir) ?? basename(appDir);
|
|
1320
1343
|
const entry = config.configurations.find((c) => c?.name === appName) ?? (config.configurations.length === 1 ? config.configurations[0] : void 0);
|
|
@@ -1331,10 +1354,10 @@ function detectClaudeWorktree(appDir) {
|
|
|
1331
1354
|
listWorktrees(appDir).map((worktree) => canonicalPath(worktree.path))
|
|
1332
1355
|
);
|
|
1333
1356
|
if (!registered.has(worktreeRoot)) return null;
|
|
1334
|
-
const worktreesDir =
|
|
1335
|
-
const claudeDir =
|
|
1357
|
+
const worktreesDir = dirname5(worktreeRoot);
|
|
1358
|
+
const claudeDir = dirname5(worktreesDir);
|
|
1336
1359
|
if (basename(worktreesDir) !== "worktrees" || basename(claudeDir) !== ".claude") return null;
|
|
1337
|
-
const ownerRoot = canonicalPath(
|
|
1360
|
+
const ownerRoot = canonicalPath(dirname5(claudeDir));
|
|
1338
1361
|
if (!registered.has(ownerRoot)) return null;
|
|
1339
1362
|
return { mainRepoRoot: ownerRoot, worktreeName: basename(worktreeRoot) };
|
|
1340
1363
|
} catch {
|
|
@@ -1368,12 +1391,12 @@ function deriveWorktreePort(worktreeKey) {
|
|
|
1368
1391
|
return WORKTREE_PORT_MIN + hash % WORKTREE_PORT_RANGE;
|
|
1369
1392
|
}
|
|
1370
1393
|
function upsertWorktreeLaunchConfig(mainRepoRoot, worktreeName, appDir, opts) {
|
|
1371
|
-
const launchPath =
|
|
1394
|
+
const launchPath = join5(mainRepoRoot, ".claude", "launch.json");
|
|
1372
1395
|
const entryName = WORKTREE_ENTRY_PREFIX + worktreeName;
|
|
1373
1396
|
try {
|
|
1374
1397
|
const config = readLaunchFile(launchPath);
|
|
1375
1398
|
if (!config) return null;
|
|
1376
|
-
const worktreesRoot =
|
|
1399
|
+
const worktreesRoot = join5(mainRepoRoot, ".claude", "worktrees") + sep;
|
|
1377
1400
|
config.configurations = config.configurations.filter((c) => {
|
|
1378
1401
|
if (c?.name === entryName) return false;
|
|
1379
1402
|
const isStaleWorktreeEntry = typeof c?.name === "string" && c.name.startsWith(WORKTREE_ENTRY_PREFIX) && typeof c.cwd === "string" && isAbsolute2(c.cwd) && c.cwd.startsWith(worktreesRoot) && !existsSync5(c.cwd);
|
|
@@ -1411,7 +1434,7 @@ function resolveWorktreePort(appDir) {
|
|
|
1411
1434
|
const claude = detectClaudeWorktree(appDir);
|
|
1412
1435
|
if (claude) {
|
|
1413
1436
|
try {
|
|
1414
|
-
const config = readLaunchFile(
|
|
1437
|
+
const config = readLaunchFile(join5(claude.mainRepoRoot, ".claude", "launch.json"));
|
|
1415
1438
|
const entry = config?.configurations.find(
|
|
1416
1439
|
(c) => c?.name === WORKTREE_ENTRY_PREFIX + claude.worktreeName
|
|
1417
1440
|
);
|
|
@@ -1472,19 +1495,9 @@ async function fetchAppIdentityToken(deployUrl, callerJwt, appId) {
|
|
|
1472
1495
|
return body.token;
|
|
1473
1496
|
}
|
|
1474
1497
|
|
|
1475
|
-
// src/cli/lib/secure-file.ts
|
|
1476
|
-
import { chmodSync, writeFileSync as writeFileSync5 } from "fs";
|
|
1477
|
-
function writeSecretFileSync(path, content) {
|
|
1478
|
-
writeFileSync5(path, content, { mode: 384 });
|
|
1479
|
-
try {
|
|
1480
|
-
chmodSync(path, 384);
|
|
1481
|
-
} catch {
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
1498
|
// src/cli/lib/wrangler-env.ts
|
|
1486
|
-
import { existsSync as existsSync6, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as
|
|
1487
|
-
import { join as
|
|
1499
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
1500
|
+
import { join as join6 } from "path";
|
|
1488
1501
|
import { parse as parseToml3, stringify as stringifyToml } from "smol-toml";
|
|
1489
1502
|
|
|
1490
1503
|
// src/server/rooms/app-name.ts
|
|
@@ -1585,7 +1598,7 @@ function resolveAppNameForEnv(config, envName) {
|
|
|
1585
1598
|
return resolveAppName(envBlock.name);
|
|
1586
1599
|
}
|
|
1587
1600
|
function devVarsPathFor(appDir) {
|
|
1588
|
-
return
|
|
1601
|
+
return join6(appDir, ".dev.vars");
|
|
1589
1602
|
}
|
|
1590
1603
|
function prepareWranglerEnvConfig(appDir, envName) {
|
|
1591
1604
|
if (!envName) return { cleanup() {
|
|
@@ -1594,11 +1607,11 @@ function prepareWranglerEnvConfig(appDir, envName) {
|
|
|
1594
1607
|
const resolved = resolveAppNameForEnv(config, envName);
|
|
1595
1608
|
if (!resolved.ok) throw new Error(resolved.reason);
|
|
1596
1609
|
const flattened = flattenWranglerEnvConfig(config, envName);
|
|
1597
|
-
const configPath =
|
|
1610
|
+
const configPath = join6(
|
|
1598
1611
|
appDir,
|
|
1599
1612
|
`.wrangler.deepspace.${safeGeneratedConfigSegment(envName)}.${process.pid}.${++generatedConfigSeq}.toml`
|
|
1600
1613
|
);
|
|
1601
|
-
|
|
1614
|
+
writeFileSync4(
|
|
1602
1615
|
configPath,
|
|
1603
1616
|
[
|
|
1604
1617
|
"# Generated by DeepSpace for this CLI run.",
|
|
@@ -1660,7 +1673,7 @@ var WranglerConfigError = class extends Error {
|
|
|
1660
1673
|
}
|
|
1661
1674
|
};
|
|
1662
1675
|
function readWranglerConfig(appDir) {
|
|
1663
|
-
const path =
|
|
1676
|
+
const path = join6(appDir, "wrangler.toml");
|
|
1664
1677
|
const raw = readFileSync9(path, "utf-8");
|
|
1665
1678
|
try {
|
|
1666
1679
|
return parseToml3(raw);
|
|
@@ -1669,7 +1682,7 @@ function readWranglerConfig(appDir) {
|
|
|
1669
1682
|
}
|
|
1670
1683
|
}
|
|
1671
1684
|
function hasWranglerConfig(appDir) {
|
|
1672
|
-
return existsSync6(
|
|
1685
|
+
return existsSync6(join6(appDir, "wrangler.toml"));
|
|
1673
1686
|
}
|
|
1674
1687
|
|
|
1675
1688
|
// src/cli/lib/dev-vars.ts
|
|
@@ -1712,21 +1725,21 @@ async function writeDevVars(appDir, ownerId, callerJwt, wranglerEnv, opts = {})
|
|
|
1712
1725
|
|
|
1713
1726
|
// src/cli/lib/install-status.ts
|
|
1714
1727
|
import { existsSync as existsSync8, readFileSync as readFileSync11, realpathSync as realpathSync3 } from "fs";
|
|
1715
|
-
import { dirname as
|
|
1728
|
+
import { dirname as dirname6, join as join8, resolve as resolve6 } from "path";
|
|
1716
1729
|
|
|
1717
1730
|
// src/cli/lib/package-manager.ts
|
|
1718
1731
|
import { existsSync as existsSync7, readFileSync as readFileSync10 } from "fs";
|
|
1719
|
-
import { join as
|
|
1732
|
+
import { join as join7 } from "path";
|
|
1720
1733
|
function detectPackageManager(appDir) {
|
|
1721
1734
|
try {
|
|
1722
|
-
const pkg2 = JSON.parse(readFileSync10(
|
|
1735
|
+
const pkg2 = JSON.parse(readFileSync10(join7(appDir, "package.json"), "utf-8"));
|
|
1723
1736
|
const name = typeof pkg2.packageManager === "string" ? pkg2.packageManager.split("@")[0] : "";
|
|
1724
1737
|
if (name === "npm" || name === "pnpm" || name === "yarn" || name === "bun") return name;
|
|
1725
1738
|
} catch {
|
|
1726
1739
|
}
|
|
1727
|
-
if (existsSync7(
|
|
1728
|
-
if (existsSync7(
|
|
1729
|
-
if (existsSync7(
|
|
1740
|
+
if (existsSync7(join7(appDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
1741
|
+
if (existsSync7(join7(appDir, "yarn.lock"))) return "yarn";
|
|
1742
|
+
if (existsSync7(join7(appDir, "bun.lock")) || existsSync7(join7(appDir, "bun.lockb"))) return "bun";
|
|
1730
1743
|
return "npm";
|
|
1731
1744
|
}
|
|
1732
1745
|
function installCommand(appDir) {
|
|
@@ -1736,10 +1749,10 @@ function installCommand(appDir) {
|
|
|
1736
1749
|
// src/cli/lib/install-status.ts
|
|
1737
1750
|
function installState(appDir) {
|
|
1738
1751
|
if (resolvesDeepspace(appDir)) return "ready";
|
|
1739
|
-
const sentinelDir =
|
|
1740
|
-
if (existsSync8(
|
|
1741
|
-
if (existsSync8(
|
|
1742
|
-
if (!existsSync8(
|
|
1752
|
+
const sentinelDir = join8(appDir, ".deepspace");
|
|
1753
|
+
if (existsSync8(join8(sentinelDir, "install.err"))) return "failed";
|
|
1754
|
+
if (existsSync8(join8(sentinelDir, "install.started"))) {
|
|
1755
|
+
if (!existsSync8(join8(sentinelDir, "install.done")) && installWorkerAlive(sentinelDir)) {
|
|
1743
1756
|
return "installing";
|
|
1744
1757
|
}
|
|
1745
1758
|
return "failed";
|
|
@@ -1751,11 +1764,11 @@ function tailHint(logPath, platform = process.platform) {
|
|
|
1751
1764
|
}
|
|
1752
1765
|
function ensureInstallReady(appDir) {
|
|
1753
1766
|
if (resolvesDeepspace(appDir)) return;
|
|
1754
|
-
const sentinelDir =
|
|
1755
|
-
const errPath =
|
|
1756
|
-
const startedPath =
|
|
1757
|
-
const donePath =
|
|
1758
|
-
const logPath =
|
|
1767
|
+
const sentinelDir = join8(appDir, ".deepspace");
|
|
1768
|
+
const errPath = join8(sentinelDir, "install.err");
|
|
1769
|
+
const startedPath = join8(sentinelDir, "install.started");
|
|
1770
|
+
const donePath = join8(sentinelDir, "install.done");
|
|
1771
|
+
const logPath = join8(sentinelDir, "install.log");
|
|
1759
1772
|
if (existsSync8(errPath)) {
|
|
1760
1773
|
const detail = readFileSync11(errPath, "utf-8").trimEnd();
|
|
1761
1774
|
const log29 = existsSync8(logPath) ? ` Full log: ${logPath}.` : "";
|
|
@@ -1796,9 +1809,9 @@ function resolvesDeepspace(fromDir) {
|
|
|
1796
1809
|
} catch {
|
|
1797
1810
|
}
|
|
1798
1811
|
for (; ; ) {
|
|
1799
|
-
if (existsSync8(
|
|
1812
|
+
if (existsSync8(join8(dir, "node_modules", "deepspace", "package.json"))) return true;
|
|
1800
1813
|
if (dir === checkoutRoot) return false;
|
|
1801
|
-
const parent =
|
|
1814
|
+
const parent = dirname6(dir);
|
|
1802
1815
|
if (parent === dir) return false;
|
|
1803
1816
|
dir = parent;
|
|
1804
1817
|
}
|
|
@@ -1811,7 +1824,7 @@ function canonicalPath2(path) {
|
|
|
1811
1824
|
}
|
|
1812
1825
|
}
|
|
1813
1826
|
function installWorkerAlive(sentinelDir) {
|
|
1814
|
-
const pidPath =
|
|
1827
|
+
const pidPath = join8(sentinelDir, "install.pid");
|
|
1815
1828
|
if (!existsSync8(pidPath)) return false;
|
|
1816
1829
|
const pid = Number(readFileSync11(pidPath, "utf-8").trim());
|
|
1817
1830
|
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
@@ -1864,7 +1877,7 @@ function preflightWindowsWorkerd(appDir) {
|
|
|
1864
1877
|
|
|
1865
1878
|
// src/cli/lib/macos-junk.ts
|
|
1866
1879
|
import { readdirSync as readdirSync2, rmSync as rmSync3 } from "fs";
|
|
1867
|
-
import { join as
|
|
1880
|
+
import { join as join9 } from "path";
|
|
1868
1881
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", ".wrangler", ".vite"]);
|
|
1869
1882
|
function removeMacosJunk(dir) {
|
|
1870
1883
|
let removed = 0;
|
|
@@ -1875,7 +1888,7 @@ function removeMacosJunk(dir) {
|
|
|
1875
1888
|
return removed;
|
|
1876
1889
|
}
|
|
1877
1890
|
for (const entry of entries) {
|
|
1878
|
-
const path =
|
|
1891
|
+
const path = join9(dir, entry.name);
|
|
1879
1892
|
if (entry.isDirectory()) {
|
|
1880
1893
|
if (!SKIP_DIRS.has(entry.name)) removed += removeMacosJunk(path);
|
|
1881
1894
|
continue;
|
|
@@ -2373,7 +2386,7 @@ async function refreshSecretsCache(deployUrl, token, appId, wranglerEnv, selecte
|
|
|
2373
2386
|
|
|
2374
2387
|
// src/cli/lib/schema-lint.ts
|
|
2375
2388
|
import { existsSync as existsSync10 } from "fs";
|
|
2376
|
-
import { join as
|
|
2389
|
+
import { join as join10 } from "path";
|
|
2377
2390
|
import { pathToFileURL } from "url";
|
|
2378
2391
|
|
|
2379
2392
|
// src/server/schemas/registry.ts
|
|
@@ -2432,12 +2445,12 @@ function lintSchema(schema) {
|
|
|
2432
2445
|
|
|
2433
2446
|
// src/cli/lib/schema-lint.ts
|
|
2434
2447
|
async function lintProjectSchemas(appDir) {
|
|
2435
|
-
const schemasPath =
|
|
2448
|
+
const schemasPath = join10(appDir, "src", "schemas.ts");
|
|
2436
2449
|
if (!existsSync10(schemasPath)) return null;
|
|
2437
2450
|
let schemas;
|
|
2438
2451
|
try {
|
|
2439
2452
|
const esbuild = await import("esbuild");
|
|
2440
|
-
const outFile =
|
|
2453
|
+
const outFile = join10(appDir, ".wrangler", "deploy", "schemas.lint.bundle.mjs");
|
|
2441
2454
|
await esbuild.build({
|
|
2442
2455
|
entryPoints: [schemasPath],
|
|
2443
2456
|
bundle: true,
|
|
@@ -2498,9 +2511,9 @@ function isPortListening(port, host, timeoutMs = 500) {
|
|
|
2498
2511
|
socket.connect(port, target2);
|
|
2499
2512
|
});
|
|
2500
2513
|
}
|
|
2501
|
-
async function waitForPortListening(port, host, timeoutMs) {
|
|
2514
|
+
async function waitForPortListening(port, host, timeoutMs, signal) {
|
|
2502
2515
|
const deadline = Date.now() + timeoutMs;
|
|
2503
|
-
while (Date.now() < deadline) {
|
|
2516
|
+
while (Date.now() < deadline && !signal?.aborted) {
|
|
2504
2517
|
if (await isPortListening(port, host)) return true;
|
|
2505
2518
|
await new Promise((resolve21) => setTimeout(resolve21, 250));
|
|
2506
2519
|
}
|
|
@@ -2598,7 +2611,7 @@ var dev_default = defineDeepspaceCommand({
|
|
|
2598
2611
|
);
|
|
2599
2612
|
} else if (!args.json) {
|
|
2600
2613
|
console.warn(
|
|
2601
|
-
`Warning: could not update ${
|
|
2614
|
+
`Warning: could not update ${join11(worktree.mainRepoRoot, ".claude", "launch.json")} (malformed or unwritable) \u2014 the Claude preview tool may serve the main repo's code instead of this worktree.`
|
|
2602
2615
|
);
|
|
2603
2616
|
}
|
|
2604
2617
|
}
|
|
@@ -2664,13 +2677,15 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2664
2677
|
}
|
|
2665
2678
|
const url = `http://${host === DEFAULT_DEV_HOST ? "localhost" : host}:${port}`;
|
|
2666
2679
|
say("Starting dev server...\n");
|
|
2667
|
-
const vite =
|
|
2680
|
+
const vite = spawn2("npx", ["vite", "--port", String(port), "--strictPort", "--host", host], {
|
|
2668
2681
|
cwd: appDir,
|
|
2669
2682
|
stdio: "inherit",
|
|
2670
2683
|
env: wranglerViteEnv(process.env, wranglerConfig, { DEEPSPACE_PORT: String(port) })
|
|
2671
2684
|
});
|
|
2685
|
+
const readiness = new AbortController();
|
|
2672
2686
|
if (args.json) {
|
|
2673
|
-
void waitForPortListening(port, host, READINESS_TIMEOUT_MS).then((ready) => {
|
|
2687
|
+
void waitForPortListening(port, host, READINESS_TIMEOUT_MS, readiness.signal).then((ready) => {
|
|
2688
|
+
if (readiness.signal.aborted) return;
|
|
2674
2689
|
console.log(
|
|
2675
2690
|
JSON.stringify(
|
|
2676
2691
|
ready ? { ok: true, ready: true, url, port, host, appDir } : {
|
|
@@ -2702,6 +2717,7 @@ Free it with \`${killCmd}\`, or start on another port: \`deepspace dev start --p
|
|
|
2702
2717
|
});
|
|
2703
2718
|
process.off("SIGINT", stop);
|
|
2704
2719
|
process.off("SIGTERM", stop);
|
|
2720
|
+
readiness.abort();
|
|
2705
2721
|
if (!devExitSucceeded(code, stopping)) {
|
|
2706
2722
|
throw new Refusal(`Dev server exited with code ${code}.`, "dev_server_failed", {
|
|
2707
2723
|
extra: { port, appDir, exitCode: code }
|
|
@@ -2817,12 +2833,12 @@ var kill_default = defineDeepspaceCommand({
|
|
|
2817
2833
|
}
|
|
2818
2834
|
});
|
|
2819
2835
|
function noTargetsMessage(opts) {
|
|
2820
|
-
const { enumerated, swept, all, port } = opts;
|
|
2836
|
+
const { enumerated, swept, all, port, platform = process.platform } = opts;
|
|
2821
2837
|
const couldObserve = enumerated || all && swept;
|
|
2822
2838
|
if (!couldObserve) {
|
|
2823
2839
|
return {
|
|
2824
2840
|
ok: false,
|
|
2825
|
-
message: `Couldn't determine what's running on :${port}: no lsof/pgrep and /proc is unavailable, so nothing was inspected or killed. Install lsof (or procps for pgrep), or find and kill the process manually.`
|
|
2841
|
+
message: platform === "win32" ? `Couldn't determine what's running on :${port}: the PowerShell port query could not be run, so nothing was inspected or killed. Either powershell.exe (or pwsh) is not on PATH, or Get-NetTCPConnection is unavailable on this Windows edition. Find the process manually with \`netstat -ano | findstr :${port}\`.` : `Couldn't determine what's running on :${port}: no lsof/pgrep and /proc is unavailable, so nothing was inspected or killed. Install lsof (or procps for pgrep), or find and kill the process manually.`
|
|
2826
2842
|
};
|
|
2827
2843
|
}
|
|
2828
2844
|
return {
|
|
@@ -2917,7 +2933,7 @@ function sweepByName(names) {
|
|
|
2917
2933
|
const all = /* @__PURE__ */ new Set();
|
|
2918
2934
|
if (IS_WIN) {
|
|
2919
2935
|
const orClauses = names.map((n) => `($_.Name -like '*${n}*') -or ($_.CommandLine -like '*${n}*')`).join(" -or ");
|
|
2920
|
-
const script = `Get-CimInstance Win32_Process | Where-Object { ${orClauses} } | Select-Object -ExpandProperty ProcessId`;
|
|
2936
|
+
const script = `Get-CimInstance Win32_Process | Where-Object { $_.ProcessId -ne $PID -and (${orClauses}) } | Select-Object -ExpandProperty ProcessId`;
|
|
2921
2937
|
const r = runPowershellChecked(script);
|
|
2922
2938
|
for (const pid of r.pids) if (pid !== process.pid) all.add(pid);
|
|
2923
2939
|
return { pids: [...all], swept: r.ran };
|
|
@@ -2954,14 +2970,22 @@ function run(cmd) {
|
|
|
2954
2970
|
function runPowershell(script) {
|
|
2955
2971
|
return runPowershellChecked(script).pids;
|
|
2956
2972
|
}
|
|
2973
|
+
var PS_SENTINEL = "__deepspace_ps_ok__";
|
|
2974
|
+
function withSentinel(script) {
|
|
2975
|
+
return `$ErrorActionPreference='Stop'; try { ${script}; '${PS_SENTINEL}' } catch { }`;
|
|
2976
|
+
}
|
|
2977
|
+
function readPowershellPids(stdout) {
|
|
2978
|
+
if (!stdout.includes(PS_SENTINEL)) return { pids: [], ran: false };
|
|
2979
|
+
return { pids: parsePidLines(stdout.replace(PS_SENTINEL, "")), ran: true };
|
|
2980
|
+
}
|
|
2957
2981
|
function runPowershellChecked(script) {
|
|
2958
2982
|
const exe = pwshOrPowershell();
|
|
2959
2983
|
try {
|
|
2960
|
-
const r = spawnSync2(exe, ["-NoProfile", "-NonInteractive", "-Command", script], {
|
|
2984
|
+
const r = spawnSync2(exe, ["-NoProfile", "-NonInteractive", "-Command", withSentinel(script)], {
|
|
2961
2985
|
encoding: "utf-8"
|
|
2962
2986
|
});
|
|
2963
2987
|
if (r.error) return { pids: [], ran: false };
|
|
2964
|
-
return
|
|
2988
|
+
return readPowershellPids(r.stdout ?? "");
|
|
2965
2989
|
} catch {
|
|
2966
2990
|
return { pids: [], ran: false };
|
|
2967
2991
|
}
|
|
@@ -3026,10 +3050,10 @@ function ensurePlaywright(appDir) {
|
|
|
3026
3050
|
import { readFileSync as readFileSync14 } from "fs";
|
|
3027
3051
|
|
|
3028
3052
|
// src/testing/accounts.ts
|
|
3029
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as
|
|
3030
|
-
import { homedir as
|
|
3031
|
-
import { join as
|
|
3032
|
-
var TEST_ACCOUNTS_PATH =
|
|
3053
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync13, writeFileSync as writeFileSync5 } from "fs";
|
|
3054
|
+
import { homedir as homedir2 } from "os";
|
|
3055
|
+
import { join as join12 } from "path";
|
|
3056
|
+
var TEST_ACCOUNTS_PATH = join12(homedir2(), ".deepspace", "test-accounts.json");
|
|
3033
3057
|
var PRODUCTION_AUTH_ORIGIN = "https://auth.deep.space";
|
|
3034
3058
|
var STAGING_AUTH_ORIGIN = "https://auth.deepspacesites.com";
|
|
3035
3059
|
function currentTestAccountScope(env = process.env) {
|
|
@@ -3115,8 +3139,8 @@ function validTestAccounts(value) {
|
|
|
3115
3139
|
);
|
|
3116
3140
|
}
|
|
3117
3141
|
function saveTestAccountStore(store) {
|
|
3118
|
-
mkdirSync5(
|
|
3119
|
-
|
|
3142
|
+
mkdirSync5(join12(homedir2(), ".deepspace"), { recursive: true });
|
|
3143
|
+
writeFileSync5(TEST_ACCOUNTS_PATH, JSON.stringify(store, null, 2), { mode: 384 });
|
|
3120
3144
|
}
|
|
3121
3145
|
|
|
3122
3146
|
// src/cli/lib/test-account-service.ts
|
|
@@ -3616,7 +3640,7 @@ var clear = defineDeepspaceCommand({
|
|
|
3616
3640
|
return { data: { deleted: 0, requested: 0, failures: [] } };
|
|
3617
3641
|
}
|
|
3618
3642
|
if (!args.yes) {
|
|
3619
|
-
if (args.json) {
|
|
3643
|
+
if (!process.stdin.isTTY || args.json) {
|
|
3620
3644
|
throw new Refusal(
|
|
3621
3645
|
"Deleting test accounts needs confirmation. Pass --yes to confirm non-interactively.",
|
|
3622
3646
|
"confirmation_required"
|
|
@@ -3845,15 +3869,15 @@ function describeFilesFailure(status3, body) {
|
|
|
3845
3869
|
import * as p6 from "@clack/prompts";
|
|
3846
3870
|
import { execSync as execSync2 } from "child_process";
|
|
3847
3871
|
import { createHash as createHash2 } from "crypto";
|
|
3848
|
-
import {
|
|
3849
|
-
import { dirname as
|
|
3872
|
+
import { existsSync as existsSync14, lstatSync as lstatSync2, readFileSync as readFileSync17, readdirSync as readdirSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
3873
|
+
import { dirname as dirname7, join as join15, resolve as resolve11 } from "path";
|
|
3850
3874
|
|
|
3851
3875
|
// src/documentation/deploy.ts
|
|
3852
3876
|
import { existsSync as existsSync12, readFileSync as readFileSync15 } from "fs";
|
|
3853
|
-
import { join as
|
|
3877
|
+
import { join as join13 } from "path";
|
|
3854
3878
|
function readDocumentationDeployManifest(appDir, clientDir) {
|
|
3855
|
-
if (!existsSync12(
|
|
3856
|
-
const manifestPath =
|
|
3879
|
+
if (!existsSync12(join13(appDir, "documentation.json"))) return void 0;
|
|
3880
|
+
const manifestPath = join13(clientDir, "_documentation", "manifest.json");
|
|
3857
3881
|
if (!existsSync12(manifestPath)) {
|
|
3858
3882
|
throw new Error(
|
|
3859
3883
|
"documentation.json exists but the build produced no documentation manifest. Ensure vite.config.ts includes deepSpaceDocumentation() from deepspace/documentation."
|
|
@@ -3874,7 +3898,7 @@ import {
|
|
|
3874
3898
|
readFileSync as readFileSync16,
|
|
3875
3899
|
writeSync
|
|
3876
3900
|
} from "fs";
|
|
3877
|
-
import { join as
|
|
3901
|
+
import { join as join14 } from "path";
|
|
3878
3902
|
|
|
3879
3903
|
// src/shared/protocol/app-migrations.ts
|
|
3880
3904
|
var APP_MIGRATION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
@@ -3926,7 +3950,7 @@ var APP_MIGRATION_DEFINITIONS = SOURCE_MIGRATIONS.map(
|
|
|
3926
3950
|
({ id, description }) => ({ id, description })
|
|
3927
3951
|
);
|
|
3928
3952
|
function readAppliedAppMigrations(appDir) {
|
|
3929
|
-
const path =
|
|
3953
|
+
const path = join14(appDir, APP_MIGRATIONS_MANIFEST);
|
|
3930
3954
|
if (!existsSync13(path)) return [];
|
|
3931
3955
|
const source = readRegularFile(path);
|
|
3932
3956
|
let parsed;
|
|
@@ -3953,7 +3977,7 @@ function planAppMigrations(appDir) {
|
|
|
3953
3977
|
const edits = [];
|
|
3954
3978
|
for (const repoPath of tracked) {
|
|
3955
3979
|
if (!isSourcePath(repoPath, appPrefix)) continue;
|
|
3956
|
-
const absolutePath =
|
|
3980
|
+
const absolutePath = join14(repo, repoPath);
|
|
3957
3981
|
let stat;
|
|
3958
3982
|
try {
|
|
3959
3983
|
stat = lstatSync(absolutePath);
|
|
@@ -3961,7 +3985,8 @@ function planAppMigrations(appDir) {
|
|
|
3961
3985
|
continue;
|
|
3962
3986
|
}
|
|
3963
3987
|
if (!stat.isFile() || stat.isSymbolicLink()) continue;
|
|
3964
|
-
const
|
|
3988
|
+
const checkout = readRegularFile(absolutePath);
|
|
3989
|
+
const before = normalizeEol(checkout);
|
|
3965
3990
|
let after = before;
|
|
3966
3991
|
for (const migration of pendingMigrations) {
|
|
3967
3992
|
const result = migration.transform(after, repoPath);
|
|
@@ -3979,7 +4004,9 @@ function planAppMigrations(appDir) {
|
|
|
3979
4004
|
}
|
|
3980
4005
|
blockers.push(...migration.findBlockers(after, repoPath));
|
|
3981
4006
|
}
|
|
3982
|
-
if (after !== before)
|
|
4007
|
+
if (after !== before) {
|
|
4008
|
+
edits.push({ path: repoPath, before: checkout, after: restoreEol(after, checkout) });
|
|
4009
|
+
}
|
|
3983
4010
|
}
|
|
3984
4011
|
const pending = pendingMigrations.map((migration) => {
|
|
3985
4012
|
const planned = perMigration.get(migration.id);
|
|
@@ -3987,7 +4014,7 @@ function planAppMigrations(appDir) {
|
|
|
3987
4014
|
});
|
|
3988
4015
|
if (pending.length > 0 && blockers.length === 0) {
|
|
3989
4016
|
const manifestPath = `${appPrefix}${APP_MIGRATIONS_MANIFEST}`;
|
|
3990
|
-
const absoluteManifestPath =
|
|
4017
|
+
const absoluteManifestPath = join14(repo, manifestPath);
|
|
3991
4018
|
const before = existsSync13(absoluteManifestPath) ? readRegularFile(absoluteManifestPath) : null;
|
|
3992
4019
|
const after = `${JSON.stringify([...appliedIds, ...pending.map(({ id }) => id)], null, 2)}
|
|
3993
4020
|
`;
|
|
@@ -4003,13 +4030,19 @@ function planAppMigrations(appDir) {
|
|
|
4003
4030
|
function applyAppMigrationPlan(appDir, plan) {
|
|
4004
4031
|
const repo = repoToplevel(appDir);
|
|
4005
4032
|
for (const edit of plan.edits) {
|
|
4006
|
-
const absolutePath =
|
|
4033
|
+
const absolutePath = join14(repo, edit.path);
|
|
4007
4034
|
const current = existsSync13(absolutePath) ? readRegularFile(absolutePath) : null;
|
|
4008
4035
|
if (current !== edit.before) {
|
|
4009
4036
|
throw new Error(`Migration input changed after planning: ${edit.path}`);
|
|
4010
4037
|
}
|
|
4011
4038
|
}
|
|
4012
|
-
for (const edit of plan.edits) writeRegularFile(
|
|
4039
|
+
for (const edit of plan.edits) writeRegularFile(join14(repo, edit.path), edit.before, edit.after);
|
|
4040
|
+
}
|
|
4041
|
+
function normalizeEol(source) {
|
|
4042
|
+
return source.replaceAll("\r\n", "\n");
|
|
4043
|
+
}
|
|
4044
|
+
function restoreEol(source, checkout) {
|
|
4045
|
+
return checkout.includes("\r\n") ? source.replaceAll("\n", "\r\n") : source;
|
|
4013
4046
|
}
|
|
4014
4047
|
function readRegularFile(path) {
|
|
4015
4048
|
const before = lstatSync(path);
|
|
@@ -4161,6 +4194,7 @@ ${SECURE_JOB_ROOM_CONSTRUCTOR}`
|
|
|
4161
4194
|
]
|
|
4162
4195
|
];
|
|
4163
4196
|
var HTTP_ROLE_IMPORT = `import { resolveAppRole } from 'deepspace/worker'`;
|
|
4197
|
+
var HTTP_ROLE_IMPORT_PATTERN = /\bimport\s*\{[^}]*\bresolveAppRole\b[^}]*\}\s*from\s*(['"])deepspace\/worker\1/;
|
|
4164
4198
|
var HTTP_ROLE_IMPORT_SEAM = `import type { AppContext, Env } from '../../worker.js'`;
|
|
4165
4199
|
var DEBUG_ROUTE_SEAM = ` app.all('/api/debug/*', async (c) => {
|
|
4166
4200
|
if (c.env.ALLOW_DEBUG_ROUTES !== 'true') {
|
|
@@ -4199,8 +4233,11 @@ function secureDebugRouteOccurrences(source) {
|
|
|
4199
4233
|
0
|
|
4200
4234
|
);
|
|
4201
4235
|
}
|
|
4236
|
+
function httpRoleImportOccurrences(source) {
|
|
4237
|
+
return source.match(new RegExp(HTTP_ROLE_IMPORT_PATTERN.source, "g"))?.length ?? 0;
|
|
4238
|
+
}
|
|
4202
4239
|
function hasSecureDebugRoute(source) {
|
|
4203
|
-
return debugRouteOccurrences(source) === 1 && secureDebugRouteOccurrences(source) === 1 &&
|
|
4240
|
+
return debugRouteOccurrences(source) === 1 && secureDebugRouteOccurrences(source) === 1 && httpRoleImportOccurrences(source) === 1;
|
|
4204
4241
|
}
|
|
4205
4242
|
function migrateSecureRoomBoundaries(source, file) {
|
|
4206
4243
|
if (file.endsWith("src/server/realtime-routes.ts")) {
|
|
@@ -4243,7 +4280,7 @@ function migrateDebugRouteAuthorization(source) {
|
|
|
4243
4280
|
const matchingRoutes = DEBUG_ROUTE_REPLACEMENTS.filter(
|
|
4244
4281
|
([before2]) => occurrences(source, before2) === 1
|
|
4245
4282
|
);
|
|
4246
|
-
if (debugRouteOccurrences(source) !== 1 || matchingRoutes.length !== 1 ||
|
|
4283
|
+
if (debugRouteOccurrences(source) !== 1 || matchingRoutes.length !== 1 || httpRoleImportOccurrences(source) !== 0 || occurrences(source, HTTP_ROLE_IMPORT_SEAM) !== 1) {
|
|
4247
4284
|
return { source, replacements: 0 };
|
|
4248
4285
|
}
|
|
4249
4286
|
const [before, after] = matchingRoutes[0];
|
|
@@ -4357,7 +4394,9 @@ function findWorkerOwnedNotFoundBlockers(source, file) {
|
|
|
4357
4394
|
const blockers = [];
|
|
4358
4395
|
const lines = source.split("\n");
|
|
4359
4396
|
for (const [index, line] of lines.entries()) {
|
|
4360
|
-
if (!/['"`]\/index\.html/.test(line))
|
|
4397
|
+
if (!/(?:\burl\.pathname\s*=\s*|\bnew\s+URL\s*\(\s*)['"`]\/index\.html/.test(line)) {
|
|
4398
|
+
continue;
|
|
4399
|
+
}
|
|
4361
4400
|
blockers.push({
|
|
4362
4401
|
migrationId: WORKER_OWNED_NOT_FOUND_MIGRATION_ID,
|
|
4363
4402
|
file,
|
|
@@ -4370,14 +4409,14 @@ function findWorkerOwnedNotFoundBlockers(source, file) {
|
|
|
4370
4409
|
|
|
4371
4410
|
// src/cli/commands/deploy/build.ts
|
|
4372
4411
|
var RESERVED_RUN_WORKER_FIRST2 = new Set(RESERVED_RUN_WORKER_FIRST);
|
|
4373
|
-
function
|
|
4374
|
-
const path =
|
|
4412
|
+
function removeBuildDevVars(workerDir) {
|
|
4413
|
+
const path = join15(workerDir, ".dev.vars");
|
|
4375
4414
|
if (!existsSync14(path)) return false;
|
|
4376
4415
|
const stat = lstatSync2(path);
|
|
4377
4416
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
4378
4417
|
throw new Error(`Refusing unsafe build secret path: ${path}`);
|
|
4379
4418
|
}
|
|
4380
|
-
|
|
4419
|
+
unlinkSync2(path);
|
|
4381
4420
|
return true;
|
|
4382
4421
|
}
|
|
4383
4422
|
function declaredCompatibilityDate(config) {
|
|
@@ -4415,7 +4454,7 @@ async function buildDeployBundle(options) {
|
|
|
4415
4454
|
preparedWranglerConfig?.cleanup();
|
|
4416
4455
|
}
|
|
4417
4456
|
spinner2.stop("Built");
|
|
4418
|
-
const deployConfigPath =
|
|
4457
|
+
const deployConfigPath = join15(appDir, ".wrangler", "deploy", "config.json");
|
|
4419
4458
|
if (!existsSync14(deployConfigPath)) {
|
|
4420
4459
|
output.die(
|
|
4421
4460
|
"Build output config not found at .wrangler/deploy/config.json",
|
|
@@ -4423,7 +4462,7 @@ async function buildDeployBundle(options) {
|
|
|
4423
4462
|
);
|
|
4424
4463
|
}
|
|
4425
4464
|
const deployConfig = JSON.parse(readFileSync17(deployConfigPath, "utf-8"));
|
|
4426
|
-
const outputWranglerPath = resolve11(
|
|
4465
|
+
const outputWranglerPath = resolve11(dirname7(deployConfigPath), deployConfig.configPath);
|
|
4427
4466
|
if (!existsSync14(outputWranglerPath)) {
|
|
4428
4467
|
output.die(`Output wrangler.json not found at ${outputWranglerPath}`, "build_output_missing");
|
|
4429
4468
|
}
|
|
@@ -4435,13 +4474,13 @@ async function buildDeployBundle(options) {
|
|
|
4435
4474
|
"build_output_mismatch"
|
|
4436
4475
|
);
|
|
4437
4476
|
}
|
|
4438
|
-
const workerDir =
|
|
4477
|
+
const workerDir = dirname7(outputWranglerPath);
|
|
4439
4478
|
try {
|
|
4440
|
-
|
|
4479
|
+
removeBuildDevVars(workerDir);
|
|
4441
4480
|
} catch (error) {
|
|
4442
4481
|
output.die(errorMessage(error), "build_output_unsafe");
|
|
4443
4482
|
}
|
|
4444
|
-
const workerBundlePath =
|
|
4483
|
+
const workerBundlePath = join15(workerDir, outputConfig.main);
|
|
4445
4484
|
const clientDir = outputConfig.assets?.directory ? resolve11(workerDir, outputConfig.assets.directory) : null;
|
|
4446
4485
|
if (!existsSync14(workerBundlePath)) {
|
|
4447
4486
|
output.die(`Worker bundle not found at ${workerBundlePath}`, "build_output_missing");
|
|
@@ -4533,7 +4572,7 @@ function collectAssets(dir) {
|
|
|
4533
4572
|
const walk = (currentDir, prefix) => {
|
|
4534
4573
|
for (const entry of readdirSync4(currentDir, { withFileTypes: true })) {
|
|
4535
4574
|
if (isDeployAssetControlFile(entry.name)) continue;
|
|
4536
|
-
const fullPath =
|
|
4575
|
+
const fullPath = join15(currentDir, entry.name);
|
|
4537
4576
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
4538
4577
|
if (entry.isDirectory()) {
|
|
4539
4578
|
walk(fullPath, relativePath);
|
|
@@ -4557,7 +4596,7 @@ function readDeployAssetConfig(clientDir) {
|
|
|
4557
4596
|
["_headers", "_headers"],
|
|
4558
4597
|
["_redirects", "_redirects"]
|
|
4559
4598
|
]) {
|
|
4560
|
-
const filePath =
|
|
4599
|
+
const filePath = join15(clientDir, file);
|
|
4561
4600
|
if (!existsSync14(filePath)) continue;
|
|
4562
4601
|
const content = readFileSync17(filePath, "utf8");
|
|
4563
4602
|
if (content.trim()) config[key] = content;
|
|
@@ -4574,17 +4613,17 @@ function errorMessage(error) {
|
|
|
4574
4613
|
// src/cli/commands/deploy/commerce.ts
|
|
4575
4614
|
import * as p7 from "@clack/prompts";
|
|
4576
4615
|
import { existsSync as existsSync15 } from "fs";
|
|
4577
|
-
import { join as
|
|
4616
|
+
import { join as join16 } from "path";
|
|
4578
4617
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4579
4618
|
var API_URL2 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
4580
4619
|
function errorMessage2(error) {
|
|
4581
4620
|
return error instanceof Error ? error.message : String(error);
|
|
4582
4621
|
}
|
|
4583
4622
|
async function loadDeclaration(appDir, sourceFile, outputFile, exportName) {
|
|
4584
|
-
const sourcePath =
|
|
4623
|
+
const sourcePath = join16(appDir, "src", sourceFile);
|
|
4585
4624
|
if (!existsSync15(sourcePath)) return void 0;
|
|
4586
4625
|
const esbuild = await import("esbuild");
|
|
4587
|
-
const outputPath =
|
|
4626
|
+
const outputPath = join16(appDir, ".wrangler", "deploy", outputFile);
|
|
4588
4627
|
await esbuild.build({
|
|
4589
4628
|
entryPoints: [sourcePath],
|
|
4590
4629
|
bundle: true,
|
|
@@ -4677,7 +4716,7 @@ Stripe will keep charging them until you cancel. Cancel at the end of their curr
|
|
|
4677
4716
|
}
|
|
4678
4717
|
}
|
|
4679
4718
|
async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
4680
|
-
if (!existsSync15(
|
|
4719
|
+
if (!existsSync15(join16(appDir, "src", "subscriptions.ts"))) return;
|
|
4681
4720
|
let plans;
|
|
4682
4721
|
try {
|
|
4683
4722
|
plans = await loadDeclaration(
|
|
@@ -4732,7 +4771,7 @@ async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
|
|
|
4732
4771
|
}
|
|
4733
4772
|
}
|
|
4734
4773
|
async function syncOneTimeProducts(appDir, appName, token) {
|
|
4735
|
-
if (!existsSync15(
|
|
4774
|
+
if (!existsSync15(join16(appDir, "src", "products.ts"))) return;
|
|
4736
4775
|
let products;
|
|
4737
4776
|
try {
|
|
4738
4777
|
products = await loadDeclaration(
|
|
@@ -4827,7 +4866,7 @@ function createDeployOutput(json) {
|
|
|
4827
4866
|
else console.error(withSlug(message, code));
|
|
4828
4867
|
if (action) printAction(action);
|
|
4829
4868
|
}
|
|
4830
|
-
|
|
4869
|
+
throw new CliExit(opts.actionRequired ? 2 : 1);
|
|
4831
4870
|
}
|
|
4832
4871
|
};
|
|
4833
4872
|
}
|
|
@@ -5556,6 +5595,7 @@ async function syncDeployRepository(options) {
|
|
|
5556
5595
|
sourceRevision = claimed.revision;
|
|
5557
5596
|
}
|
|
5558
5597
|
} catch (error) {
|
|
5598
|
+
if (error instanceof CliExit) throw error;
|
|
5559
5599
|
const failure = deployRepositoryFailure(error, appDir);
|
|
5560
5600
|
output.die(failure.error, failure.code);
|
|
5561
5601
|
}
|
|
@@ -5672,7 +5712,7 @@ async function deployBuiltBundle(options) {
|
|
|
5672
5712
|
...action ? { action } : {}
|
|
5673
5713
|
});
|
|
5674
5714
|
}
|
|
5675
|
-
|
|
5715
|
+
throw new CliExit(actionRequired ? 2 : 1);
|
|
5676
5716
|
};
|
|
5677
5717
|
const makeForm = () => {
|
|
5678
5718
|
const form = new FormData();
|
|
@@ -6583,6 +6623,7 @@ var apps_default = defineDeepspaceCommand({
|
|
|
6583
6623
|
|
|
6584
6624
|
// src/cli/commands/logs.ts
|
|
6585
6625
|
import { defineCommand as defineCommand4 } from "citty";
|
|
6626
|
+
import { setTimeout as delay } from "timers/promises";
|
|
6586
6627
|
|
|
6587
6628
|
// src/shared/log-events.ts
|
|
6588
6629
|
var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
|
|
@@ -6693,7 +6734,7 @@ function formatEvent(e, color, now = Date.now()) {
|
|
|
6693
6734
|
const client = e.source === "client" ? paint("35", "CLIENT", color) + " " : "";
|
|
6694
6735
|
return `${time} ${client}${tag} ${body}`;
|
|
6695
6736
|
}
|
|
6696
|
-
var sleep3 = (ms) =>
|
|
6737
|
+
var sleep3 = (ms, signal) => delay(ms, void 0, { signal });
|
|
6697
6738
|
var logs_default = defineCommand4({
|
|
6698
6739
|
meta: {
|
|
6699
6740
|
name: "logs",
|
|
@@ -6769,12 +6810,17 @@ var logs_default = defineCommand4({
|
|
|
6769
6810
|
const windowLabel = args.since?.trim() || "15m";
|
|
6770
6811
|
const MAX_LIMIT = 500;
|
|
6771
6812
|
const followLimit = followInitialLimit(limit, MAX_LIMIT);
|
|
6772
|
-
const fetchPage = async (since, pageLimit, token2) => {
|
|
6813
|
+
const fetchPage = async (since, pageLimit, token2, signal) => {
|
|
6773
6814
|
const params = new URLSearchParams({ since: String(since) });
|
|
6774
6815
|
if (pageLimit !== void 0) params.set("limit", String(pageLimit));
|
|
6775
6816
|
if (args.level) params.set("level", args.level);
|
|
6776
6817
|
if (args.search) params.set("search", args.search);
|
|
6777
|
-
return apiFetch(
|
|
6818
|
+
return apiFetch(
|
|
6819
|
+
DEPLOY_URL6,
|
|
6820
|
+
token2,
|
|
6821
|
+
`/api/apps/${appId}/logs?${params}`,
|
|
6822
|
+
signal ? { signal } : void 0
|
|
6823
|
+
);
|
|
6778
6824
|
};
|
|
6779
6825
|
const print = (events) => {
|
|
6780
6826
|
for (const e of events) {
|
|
@@ -6810,7 +6856,8 @@ var logs_default = defineCommand4({
|
|
|
6810
6856
|
}
|
|
6811
6857
|
return;
|
|
6812
6858
|
}
|
|
6813
|
-
|
|
6859
|
+
const tail = new AbortController();
|
|
6860
|
+
process.once("SIGINT", () => tail.abort());
|
|
6814
6861
|
if (!args.json) {
|
|
6815
6862
|
console.error(`Tailing logs for ${appId} \u2014 Ctrl+C to stop.`);
|
|
6816
6863
|
}
|
|
@@ -6835,12 +6882,23 @@ var logs_default = defineCommand4({
|
|
|
6835
6882
|
}
|
|
6836
6883
|
}
|
|
6837
6884
|
for (; ; ) {
|
|
6838
|
-
|
|
6885
|
+
try {
|
|
6886
|
+
await sleep3(backoff || interval, tail.signal);
|
|
6887
|
+
} catch {
|
|
6888
|
+
return;
|
|
6889
|
+
}
|
|
6839
6890
|
const freshToken = await ensureToken();
|
|
6891
|
+
if (tail.signal.aborted) return;
|
|
6840
6892
|
let page;
|
|
6841
6893
|
try {
|
|
6842
|
-
page = await fetchPage(
|
|
6894
|
+
page = await fetchPage(
|
|
6895
|
+
nextPollSince(cursor, initialSince),
|
|
6896
|
+
followLimit,
|
|
6897
|
+
freshToken,
|
|
6898
|
+
tail.signal
|
|
6899
|
+
);
|
|
6843
6900
|
} catch (err) {
|
|
6901
|
+
if (tail.signal.aborted) return;
|
|
6844
6902
|
if (err instanceof ApiError && [401, 403, 404].includes(err.status)) throw err;
|
|
6845
6903
|
backoff = Math.min(backoff ? backoff * 2 : MIN_POLL_MS, 3e4);
|
|
6846
6904
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -6946,7 +7004,7 @@ var usage_default = defineDeepspaceCommand({
|
|
|
6946
7004
|
|
|
6947
7005
|
// src/cli/commands/add.ts
|
|
6948
7006
|
import { existsSync as existsSync18, readFileSync as readFileSync20, realpathSync as realpathSync4 } from "fs";
|
|
6949
|
-
import { dirname as
|
|
7007
|
+
import { dirname as dirname9, join as join18, resolve as resolve15 } from "path";
|
|
6950
7008
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
6951
7009
|
|
|
6952
7010
|
// src/cli/commands/feature-installer.ts
|
|
@@ -6962,17 +7020,17 @@ import {
|
|
|
6962
7020
|
readSync,
|
|
6963
7021
|
readdirSync as readdirSync5,
|
|
6964
7022
|
rmSync as rmSync4,
|
|
6965
|
-
writeFileSync as
|
|
7023
|
+
writeFileSync as writeFileSync6
|
|
6966
7024
|
} from "fs";
|
|
6967
7025
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
6968
7026
|
import { tmpdir as tmpdir2 } from "os";
|
|
6969
|
-
import { dirname as
|
|
7027
|
+
import { dirname as dirname8, isAbsolute as isAbsolute4, join as join17, resolve as resolve14 } from "path";
|
|
6970
7028
|
import { fileURLToPath } from "url";
|
|
6971
7029
|
var NAV_MARKER = "// \u2500\u2500 Features add nav items below this line \u2500\u2500";
|
|
6972
7030
|
function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
6973
|
-
let dir =
|
|
7031
|
+
let dir = dirname8(fileURLToPath(moduleUrl));
|
|
6974
7032
|
for (; ; ) {
|
|
6975
|
-
const packagePath =
|
|
7033
|
+
const packagePath = join17(dir, "package.json");
|
|
6976
7034
|
if (existsSync17(packagePath)) {
|
|
6977
7035
|
try {
|
|
6978
7036
|
const pkg2 = JSON.parse(readFileSync19(packagePath, "utf-8"));
|
|
@@ -6980,16 +7038,16 @@ function featurePackageRoot(moduleUrl = import.meta.url) {
|
|
|
6980
7038
|
} catch {
|
|
6981
7039
|
}
|
|
6982
7040
|
}
|
|
6983
|
-
const parent =
|
|
7041
|
+
const parent = dirname8(dir);
|
|
6984
7042
|
if (parent === dir) throw new Error("Could not locate the deepspace package root");
|
|
6985
7043
|
dir = parent;
|
|
6986
7044
|
}
|
|
6987
7045
|
}
|
|
6988
7046
|
function hasFeatureCatalog(packageRoot = featurePackageRoot()) {
|
|
6989
|
-
return existsSync17(
|
|
7047
|
+
return existsSync17(join17(packageRoot, "features"));
|
|
6990
7048
|
}
|
|
6991
7049
|
function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
6992
|
-
const configPath =
|
|
7050
|
+
const configPath = join17(packageRoot, "features", id, "feature.json");
|
|
6993
7051
|
if (!existsSync17(configPath)) return null;
|
|
6994
7052
|
try {
|
|
6995
7053
|
const config = JSON.parse(readFileSync19(configPath, "utf-8"));
|
|
@@ -7002,7 +7060,7 @@ function readFeatureConfig(id, packageRoot = featurePackageRoot()) {
|
|
|
7002
7060
|
}
|
|
7003
7061
|
}
|
|
7004
7062
|
function listFeatureConfigs(packageRoot = featurePackageRoot()) {
|
|
7005
|
-
const featuresDir =
|
|
7063
|
+
const featuresDir = join17(packageRoot, "features");
|
|
7006
7064
|
if (!existsSync17(featuresDir)) return [];
|
|
7007
7065
|
return readdirSync5(featuresDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => readFeatureConfig(entry.name, packageRoot)).filter((config) => config !== null && !config.internal).sort((a, b) => a.id.localeCompare(b.id));
|
|
7008
7066
|
}
|
|
@@ -7051,17 +7109,17 @@ function resolveFeatureDestPath(fileDest, route) {
|
|
|
7051
7109
|
return route?.protected === false ? `${appPages}${rest}` : `${appPages}(protected)/${rest}`;
|
|
7052
7110
|
}
|
|
7053
7111
|
function copyFile(src, dest) {
|
|
7054
|
-
mkdirSync6(
|
|
7112
|
+
mkdirSync6(dirname8(dest), { recursive: true });
|
|
7055
7113
|
copyFileSync(src, dest);
|
|
7056
7114
|
}
|
|
7057
7115
|
function copyFileWithImportShift(src, dest, levels) {
|
|
7058
|
-
mkdirSync6(
|
|
7116
|
+
mkdirSync6(dirname8(dest), { recursive: true });
|
|
7059
7117
|
const prefix = "../".repeat(levels);
|
|
7060
7118
|
const shifted = readFileSync19(src, "utf-8").replace(
|
|
7061
7119
|
/(from\s+|import\s+|import\()(['"])(\.\.\/)/g,
|
|
7062
7120
|
`$1$2${prefix}$3`
|
|
7063
7121
|
);
|
|
7064
|
-
|
|
7122
|
+
writeFileSync6(dest, shifted);
|
|
7065
7123
|
}
|
|
7066
7124
|
function installFiles(packageRoot, config, targetDir, emit) {
|
|
7067
7125
|
let copied = 0;
|
|
@@ -7070,9 +7128,9 @@ function installFiles(packageRoot, config, targetDir, emit) {
|
|
|
7070
7128
|
const preexisting = [];
|
|
7071
7129
|
const missing = [];
|
|
7072
7130
|
for (const file of config.files) {
|
|
7073
|
-
const srcPath =
|
|
7131
|
+
const srcPath = join17(packageRoot, "features", config.id, file.src);
|
|
7074
7132
|
const resolvedDest = resolveFeatureDestPath(file.dest, config.route);
|
|
7075
|
-
const destPath =
|
|
7133
|
+
const destPath = join17(targetDir, resolvedDest);
|
|
7076
7134
|
const existed = existsSync17(destPath);
|
|
7077
7135
|
if (existed) preexisting.push(resolvedDest);
|
|
7078
7136
|
if (!existsSync17(srcPath)) {
|
|
@@ -7112,7 +7170,7 @@ function unresolvedSchema(schema, reason, emit) {
|
|
|
7112
7170
|
}
|
|
7113
7171
|
function integrateSchema(config, targetDir, emit) {
|
|
7114
7172
|
if (!config.schema) return [];
|
|
7115
|
-
const schemasPath =
|
|
7173
|
+
const schemasPath = join17(targetDir, "src", "schemas.ts");
|
|
7116
7174
|
if (!existsSync17(schemasPath)) {
|
|
7117
7175
|
return [unresolvedSchema(config.schema, "src/schemas.ts was not found.", emit)];
|
|
7118
7176
|
}
|
|
@@ -7147,7 +7205,7 @@ export const schemas`
|
|
|
7147
7205
|
return [unresolvedSchema(config.schema, reason, emit)];
|
|
7148
7206
|
}
|
|
7149
7207
|
content = withEntry;
|
|
7150
|
-
|
|
7208
|
+
writeFileSync6(schemasPath, content);
|
|
7151
7209
|
emit(` Schema integrated: ${exportName} -> schemas.ts`);
|
|
7152
7210
|
return [];
|
|
7153
7211
|
}
|
|
@@ -7169,7 +7227,7 @@ function unresolvedActions(actions, reason, emit) {
|
|
|
7169
7227
|
}
|
|
7170
7228
|
function integrateActions(config, targetDir, emit) {
|
|
7171
7229
|
if (!config.actions?.length) return [];
|
|
7172
|
-
const actionsPath =
|
|
7230
|
+
const actionsPath = join17(targetDir, "src", "actions", "index.ts");
|
|
7173
7231
|
if (!existsSync17(actionsPath)) {
|
|
7174
7232
|
return [unresolvedActions(config.actions, "src/actions/index.ts was not found.", emit)];
|
|
7175
7233
|
}
|
|
@@ -7213,13 +7271,13 @@ ${registryEntry}`);
|
|
|
7213
7271
|
integrated++;
|
|
7214
7272
|
emit(` Action integrated: ${action.registerAs} (${action.exportName})`);
|
|
7215
7273
|
}
|
|
7216
|
-
if (integrated > 0)
|
|
7274
|
+
if (integrated > 0) writeFileSync6(actionsPath, content);
|
|
7217
7275
|
return unresolved;
|
|
7218
7276
|
}
|
|
7219
7277
|
function integrateCode(config, targetDir, emit) {
|
|
7220
7278
|
const unresolved = [];
|
|
7221
7279
|
for (const insertion of config.code ?? []) {
|
|
7222
|
-
const targetPath =
|
|
7280
|
+
const targetPath = join17(targetDir, insertion.file);
|
|
7223
7281
|
if (!existsSync17(targetPath)) {
|
|
7224
7282
|
unresolved.push({
|
|
7225
7283
|
area: "code",
|
|
@@ -7249,34 +7307,36 @@ function integrateCode(config, targetDir, emit) {
|
|
|
7249
7307
|
if (insertion.import && !content.includes(insertion.import)) {
|
|
7250
7308
|
const importIndex = content.search(/^import\s/m);
|
|
7251
7309
|
content = `${content.slice(0, importIndex < 0 ? 0 : importIndex)}${insertion.import}
|
|
7252
|
-
${content.slice(
|
|
7310
|
+
${content.slice(
|
|
7311
|
+
importIndex < 0 ? 0 : importIndex
|
|
7312
|
+
)}`;
|
|
7253
7313
|
}
|
|
7254
7314
|
const currentMarkerIndex = content.indexOf(insertion.marker);
|
|
7255
7315
|
const insertAt = insertion.placement === "before" ? currentMarkerIndex : currentMarkerIndex + insertion.marker.length;
|
|
7256
7316
|
const prefix = insertion.placement === "before" ? "" : "\n";
|
|
7257
7317
|
const suffix = insertion.placement === "before" ? "\n" : "";
|
|
7258
7318
|
content = `${content.slice(0, insertAt)}${prefix}${insertion.insert}${suffix}${content.slice(insertAt)}`;
|
|
7259
|
-
|
|
7319
|
+
writeFileSync6(targetPath, content);
|
|
7260
7320
|
emit(` Integrated: ${insertion.file}`);
|
|
7261
7321
|
}
|
|
7262
7322
|
return unresolved;
|
|
7263
7323
|
}
|
|
7264
7324
|
function integrateIgnore(config, targetDir) {
|
|
7265
7325
|
if (!config.ignore?.length) return;
|
|
7266
|
-
const targetPath =
|
|
7326
|
+
const targetPath = join17(targetDir, ".gitignore");
|
|
7267
7327
|
const current = existsSync17(targetPath) ? readFileSync19(targetPath, "utf-8") : "";
|
|
7268
7328
|
const present = new Set(current.split(/\r?\n/).map((line) => line.trim()));
|
|
7269
7329
|
const missing = config.ignore.filter((pattern) => !present.has(pattern));
|
|
7270
7330
|
if (missing.length === 0) return;
|
|
7271
7331
|
const separator = current === "" || current.endsWith("\n") ? "" : "\n";
|
|
7272
|
-
|
|
7332
|
+
writeFileSync6(targetPath, `${current}${separator}${missing.join("\n")}
|
|
7273
7333
|
`);
|
|
7274
7334
|
}
|
|
7275
7335
|
function integrateWrangler(config, targetDir, emit) {
|
|
7276
7336
|
const runWorkerFirst = config.wrangler?.runWorkerFirst === true;
|
|
7277
7337
|
const rateLimits = config.wrangler?.rateLimits ?? [];
|
|
7278
7338
|
if (!runWorkerFirst && rateLimits.length === 0) return [];
|
|
7279
|
-
const targetPath =
|
|
7339
|
+
const targetPath = join17(targetDir, "wrangler.toml");
|
|
7280
7340
|
const steps = [
|
|
7281
7341
|
...runWorkerFirst ? ["Set assets.run_worker_first = true in wrangler.toml."] : [],
|
|
7282
7342
|
...rateLimits.map((binding) => `Add the ${binding.name} rate-limit binding to wrangler.toml.`)
|
|
@@ -7306,7 +7366,7 @@ ${rateLimitBindingBlock(scope, binding)}
|
|
|
7306
7366
|
}
|
|
7307
7367
|
}
|
|
7308
7368
|
if (changed) {
|
|
7309
|
-
|
|
7369
|
+
writeFileSync6(targetPath, source);
|
|
7310
7370
|
emit(" Integrated: wrangler.toml");
|
|
7311
7371
|
} else emit(" Integration already present: wrangler.toml");
|
|
7312
7372
|
return [];
|
|
@@ -7360,7 +7420,7 @@ function rateLimitBindingBlock(scope, binding) {
|
|
|
7360
7420
|
}
|
|
7361
7421
|
function integrateCss(packageRoot, config, targetDir, emit) {
|
|
7362
7422
|
if (!config.css?.length) return [];
|
|
7363
|
-
const stylesPath =
|
|
7423
|
+
const stylesPath = join17(targetDir, "src", "styles.css");
|
|
7364
7424
|
if (!existsSync17(stylesPath)) {
|
|
7365
7425
|
emit(" Warning: Cannot integrate CSS \u2014 src/styles.css not found");
|
|
7366
7426
|
return [
|
|
@@ -7377,7 +7437,7 @@ function integrateCss(packageRoot, config, targetDir, emit) {
|
|
|
7377
7437
|
let integrated = 0;
|
|
7378
7438
|
const unresolved = [];
|
|
7379
7439
|
for (const cssFile of config.css) {
|
|
7380
|
-
const srcPath =
|
|
7440
|
+
const srcPath = join17(packageRoot, "features", config.id, cssFile);
|
|
7381
7441
|
if (!existsSync17(srcPath)) {
|
|
7382
7442
|
emit(` Warning: CSS source not found: ${cssFile}`, "stderr");
|
|
7383
7443
|
unresolved.push({
|
|
@@ -7399,22 +7459,29 @@ ${css}`;
|
|
|
7399
7459
|
integrated++;
|
|
7400
7460
|
emit(` CSS integrated: ${cssFile} -> styles.css`);
|
|
7401
7461
|
}
|
|
7402
|
-
if (integrated > 0)
|
|
7462
|
+
if (integrated > 0) writeFileSync6(stylesPath, styles);
|
|
7403
7463
|
return unresolved;
|
|
7404
7464
|
}
|
|
7405
7465
|
function unresolvedRoute(route, config, reason, emit) {
|
|
7466
|
+
const roles = routeRolesSuffix(route);
|
|
7406
7467
|
emit("");
|
|
7407
7468
|
emit(" Add manually to src/nav.ts:");
|
|
7408
|
-
emit(` { path: '${route.path}', label: '${config.name}' },`);
|
|
7469
|
+
emit(` { path: '${route.path}', label: '${config.name}'${roles} },`);
|
|
7409
7470
|
return {
|
|
7410
7471
|
area: "nav",
|
|
7411
7472
|
reason,
|
|
7412
|
-
steps: [
|
|
7473
|
+
steps: [
|
|
7474
|
+
`Add { path: '${route.path}', label: '${config.name}'${roles} } to the exported nav array.`
|
|
7475
|
+
]
|
|
7413
7476
|
};
|
|
7414
7477
|
}
|
|
7478
|
+
function routeRolesSuffix(route) {
|
|
7479
|
+
const roles = route.roles?.length ? route.roles : route.protected === false ? [] : ["member"];
|
|
7480
|
+
return roles.length ? `, roles: [${roles.map((role) => `'${role}' as Role`).join(", ")}]` : "";
|
|
7481
|
+
}
|
|
7415
7482
|
function integrateRoute(config, targetDir, emit) {
|
|
7416
7483
|
if (!config.route) return [];
|
|
7417
|
-
const navPath =
|
|
7484
|
+
const navPath = join17(targetDir, "src", "nav.ts");
|
|
7418
7485
|
if (!existsSync17(navPath)) {
|
|
7419
7486
|
return [unresolvedRoute(config.route, config, "src/nav.ts was not found.", emit)];
|
|
7420
7487
|
}
|
|
@@ -7435,11 +7502,11 @@ function integrateRoute(config, targetDir, emit) {
|
|
|
7435
7502
|
)
|
|
7436
7503
|
];
|
|
7437
7504
|
}
|
|
7438
|
-
const roles = config.route
|
|
7505
|
+
const roles = routeRolesSuffix(config.route);
|
|
7439
7506
|
const entry = ` { path: '${routePath}', label: '${config.name}'${roles} },`;
|
|
7440
7507
|
content = content.replace(NAV_MARKER, `${NAV_MARKER}
|
|
7441
7508
|
${entry}`);
|
|
7442
|
-
|
|
7509
|
+
writeFileSync6(navPath, content);
|
|
7443
7510
|
emit(` Nav wired: ${routePath} (${config.name})`);
|
|
7444
7511
|
emit(" Route: automatic (file-based routing via src/pages/)");
|
|
7445
7512
|
return [];
|
|
@@ -7465,10 +7532,10 @@ function runPackageInstall(packageManager, targetDir, outputVisible) {
|
|
|
7465
7532
|
const child = spawnSync6(packageManager, ["install"], { ...options, stdio: "inherit" });
|
|
7466
7533
|
return { error: child.error, status: child.status };
|
|
7467
7534
|
}
|
|
7468
|
-
const captureDir = mkdtempSync(
|
|
7535
|
+
const captureDir = mkdtempSync(join17(tmpdir2(), "deepspace-add-install-"));
|
|
7469
7536
|
let outputFd;
|
|
7470
7537
|
try {
|
|
7471
|
-
outputFd = openSync2(
|
|
7538
|
+
outputFd = openSync2(join17(captureDir, "output.log"), "w+");
|
|
7472
7539
|
const child = spawnSync6(packageManager, ["install"], {
|
|
7473
7540
|
...options,
|
|
7474
7541
|
stdio: ["ignore", outputFd, outputFd]
|
|
@@ -7492,7 +7559,7 @@ function integrateDependencies(config, targetDir, runInstall, outputVisible, emi
|
|
|
7492
7559
|
if (declarations.every(({ values }) => !values || Object.keys(values).length === 0)) {
|
|
7493
7560
|
return { added: [], installRan: false, packageManager };
|
|
7494
7561
|
}
|
|
7495
|
-
const packagePath =
|
|
7562
|
+
const packagePath = join17(targetDir, "package.json");
|
|
7496
7563
|
if (!existsSync17(packagePath)) {
|
|
7497
7564
|
emit(" Could not patch package.json (file not found)");
|
|
7498
7565
|
return { added: [], installRan: false, packageManager };
|
|
@@ -7523,7 +7590,7 @@ function integrateDependencies(config, targetDir, runInstall, outputVisible, emi
|
|
|
7523
7590
|
if (added.length === 0) {
|
|
7524
7591
|
emit(" Dependencies already present");
|
|
7525
7592
|
} else {
|
|
7526
|
-
|
|
7593
|
+
writeFileSync6(packagePath, `${JSON.stringify(pkg2, null, 2)}
|
|
7527
7594
|
`, "utf-8");
|
|
7528
7595
|
emit(` Added to package.json: ${added.map(({ name }) => name).join(", ")}`);
|
|
7529
7596
|
if (skipped.length) emit(` Already present (kept your version): ${skipped.join(", ")}`);
|
|
@@ -7559,7 +7626,7 @@ ${child.diagnosticTail}` : "";
|
|
|
7559
7626
|
}
|
|
7560
7627
|
function dependencySnapshot(targetDir) {
|
|
7561
7628
|
try {
|
|
7562
|
-
const pkg2 = JSON.parse(readFileSync19(
|
|
7629
|
+
const pkg2 = JSON.parse(readFileSync19(join17(targetDir, "package.json"), "utf-8"));
|
|
7563
7630
|
return {
|
|
7564
7631
|
dependencies: pkg2.dependencies ?? {},
|
|
7565
7632
|
devDependencies: pkg2.devDependencies ?? {}
|
|
@@ -7571,7 +7638,7 @@ function dependencySnapshot(targetDir) {
|
|
|
7571
7638
|
function installedNavFeatures(packageRoot, targetDir) {
|
|
7572
7639
|
return listFeatureConfigs(packageRoot).filter((feature) => feature.category === "nav" && feature.files.length > 0).filter((feature) => {
|
|
7573
7640
|
const signature = resolveFeatureDestPath(feature.files[0].dest, feature.route);
|
|
7574
|
-
return existsSync17(
|
|
7641
|
+
return existsSync17(join17(targetDir, signature));
|
|
7575
7642
|
}).map((feature) => feature.id);
|
|
7576
7643
|
}
|
|
7577
7644
|
function warnNavConflicts(packageRoot, config, targetDir, emit) {
|
|
@@ -7631,7 +7698,7 @@ function installFeature(options) {
|
|
|
7631
7698
|
);
|
|
7632
7699
|
if (config.instructions?.length) {
|
|
7633
7700
|
emit("");
|
|
7634
|
-
emit("---
|
|
7701
|
+
emit("--- Next steps ---");
|
|
7635
7702
|
emit("");
|
|
7636
7703
|
config.instructions.forEach((instruction, index) => {
|
|
7637
7704
|
emit(`${index + 1}. ${instruction}`);
|
|
@@ -7804,8 +7871,8 @@ function renderFeatureInfo(config) {
|
|
|
7804
7871
|
return lines.join("\n");
|
|
7805
7872
|
}
|
|
7806
7873
|
function isDeepSpaceApp(dir) {
|
|
7807
|
-
if (existsSync18(
|
|
7808
|
-
const packagePath =
|
|
7874
|
+
if (existsSync18(join18(dir, "wrangler.toml"))) return true;
|
|
7875
|
+
const packagePath = join18(dir, "package.json");
|
|
7809
7876
|
if (!existsSync18(packagePath)) return false;
|
|
7810
7877
|
try {
|
|
7811
7878
|
const pkg2 = JSON.parse(readFileSync20(packagePath, "utf-8"));
|
|
@@ -7817,9 +7884,9 @@ function isDeepSpaceApp(dir) {
|
|
|
7817
7884
|
function installedPackageRoot(fromDir) {
|
|
7818
7885
|
let dir = fromDir;
|
|
7819
7886
|
for (; ; ) {
|
|
7820
|
-
const candidate =
|
|
7821
|
-
if (existsSync18(
|
|
7822
|
-
const parent =
|
|
7887
|
+
const candidate = join18(dir, "node_modules", "deepspace");
|
|
7888
|
+
if (existsSync18(join18(candidate, "package.json"))) return candidate;
|
|
7889
|
+
const parent = dirname9(dir);
|
|
7823
7890
|
if (parent === dir) return null;
|
|
7824
7891
|
dir = parent;
|
|
7825
7892
|
}
|
|
@@ -7835,8 +7902,8 @@ async function targetInstaller(appDir) {
|
|
|
7835
7902
|
if (realpathSync4(installedRoot) === realpathSync4(featurePackageRoot())) {
|
|
7836
7903
|
return { installFeature };
|
|
7837
7904
|
}
|
|
7838
|
-
const entry =
|
|
7839
|
-
const catalog =
|
|
7905
|
+
const entry = join18(installedRoot, "dist", "feature-installer.js");
|
|
7906
|
+
const catalog = join18(installedRoot, "features");
|
|
7840
7907
|
if (!existsSync18(entry) || !existsSync18(catalog)) {
|
|
7841
7908
|
throw new Refusal(
|
|
7842
7909
|
`The app's installed deepspace package does not contain the typed feature installer.
|
|
@@ -7974,6 +8041,7 @@ Create one with: deepspace app create <name>`,
|
|
|
7974
8041
|
}
|
|
7975
8042
|
if (!outcome.ok) {
|
|
7976
8043
|
throw new Refusal(outcome.error, outcome.code, {
|
|
8044
|
+
actionRequired: outcome.code === "manual_integration_required",
|
|
7977
8045
|
..."data" in outcome ? { extra: outcome.data } : {}
|
|
7978
8046
|
});
|
|
7979
8047
|
}
|
|
@@ -8011,13 +8079,12 @@ function fmtDate(iso) {
|
|
|
8011
8079
|
}
|
|
8012
8080
|
async function confirm4(message) {
|
|
8013
8081
|
process.stdout.write(`${message} [y/N] `);
|
|
8014
|
-
|
|
8082
|
+
const answer = await new Promise((resolve21) => {
|
|
8015
8083
|
process.stdin.setEncoding("utf-8");
|
|
8016
|
-
process.stdin.once("data", (data) =>
|
|
8017
|
-
const answer = data.toString().trim().toLowerCase();
|
|
8018
|
-
resolve21(answer === "y" || answer === "yes");
|
|
8019
|
-
});
|
|
8084
|
+
process.stdin.once("data", (data) => resolve21(data.toString().trim().toLowerCase()));
|
|
8020
8085
|
});
|
|
8086
|
+
process.stdin.pause();
|
|
8087
|
+
return answer === "y" || answer === "yes";
|
|
8021
8088
|
}
|
|
8022
8089
|
var cannotPrompt = (json) => json || !process.stdin.isTTY;
|
|
8023
8090
|
var search = defineDeepspaceCommand({
|
|
@@ -9368,7 +9435,7 @@ var integrations_default = defineCommand9({
|
|
|
9368
9435
|
// src/cli/commands/feedback.ts
|
|
9369
9436
|
import * as p16 from "@clack/prompts";
|
|
9370
9437
|
import { existsSync as existsSync20, readFileSync as readFileSync22 } from "fs";
|
|
9371
|
-
import { dirname as
|
|
9438
|
+
import { dirname as dirname10, join as join19 } from "path";
|
|
9372
9439
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9373
9440
|
import { release } from "os";
|
|
9374
9441
|
var API_URL8 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
|
|
@@ -9389,10 +9456,10 @@ function normalizeType(raw) {
|
|
|
9389
9456
|
}
|
|
9390
9457
|
function readCliVersion() {
|
|
9391
9458
|
try {
|
|
9392
|
-
const here =
|
|
9459
|
+
const here = dirname10(fileURLToPath2(import.meta.url));
|
|
9393
9460
|
const candidates = [
|
|
9394
|
-
|
|
9395
|
-
|
|
9461
|
+
join19(here, "..", "package.json"),
|
|
9462
|
+
join19(here, "..", "..", "..", "package.json")
|
|
9396
9463
|
];
|
|
9397
9464
|
for (const path of candidates) {
|
|
9398
9465
|
if (!existsSync20(path)) continue;
|
|
@@ -9793,7 +9860,7 @@ var get2 = defineCommand10({
|
|
|
9793
9860
|
const { secrets } = await listSecrets(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
9794
9861
|
const item = secrets.find((s) => s.key === key);
|
|
9795
9862
|
if (!item)
|
|
9796
|
-
|
|
9863
|
+
throw new InputError(`Secret "${key}" not found in ${t.configName}`, "secret_not_found");
|
|
9797
9864
|
ok(
|
|
9798
9865
|
args.json === true,
|
|
9799
9866
|
{
|
|
@@ -9865,7 +9932,7 @@ var upload = defineCommand10({
|
|
|
9865
9932
|
const content = args.file === "-" ? readFileSync23(0, "utf-8") : readFileSync23(args.file, "utf-8");
|
|
9866
9933
|
const secrets = parseSecretsUpload(content);
|
|
9867
9934
|
if (Object.keys(secrets).length === 0)
|
|
9868
|
-
|
|
9935
|
+
throw new InputError("No secrets found in the input.", "empty_input");
|
|
9869
9936
|
await uploadSecrets(DEPLOY_URL11, t.token, t.appId, t.configName, secrets, args.replace);
|
|
9870
9937
|
const uploaded = Object.keys(secrets);
|
|
9871
9938
|
ok(
|
|
@@ -9896,11 +9963,9 @@ var download = defineCommand10({
|
|
|
9896
9963
|
const t = await resolveTarget(args);
|
|
9897
9964
|
const format = args.format;
|
|
9898
9965
|
if (!["dotenv", "json", "shell"].includes(format)) {
|
|
9899
|
-
|
|
9900
|
-
|
|
9901
|
-
|
|
9902
|
-
"invalid_format"
|
|
9903
|
-
)
|
|
9966
|
+
throw new InputError(
|
|
9967
|
+
`Unknown format "${args.format}" \u2014 use dotenv, json, or shell.`,
|
|
9968
|
+
"invalid_format"
|
|
9904
9969
|
);
|
|
9905
9970
|
}
|
|
9906
9971
|
const { secrets } = await fetchSecretsValues(DEPLOY_URL11, t.token, t.appId, t.configName);
|
|
@@ -9918,11 +9983,9 @@ var pull = defineCommand10({
|
|
|
9918
9983
|
const wranglerEnv = args.env?.trim() || void 0;
|
|
9919
9984
|
const appDir = findAppDir();
|
|
9920
9985
|
if (!appDir)
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
"not_in_app_repo"
|
|
9925
|
-
)
|
|
9986
|
+
throw new InputError(
|
|
9987
|
+
"Run from a DeepSpace app directory (one containing wrangler.toml).",
|
|
9988
|
+
"not_in_app_repo"
|
|
9926
9989
|
);
|
|
9927
9990
|
const t = await resolveTarget(args);
|
|
9928
9991
|
const ownerId = decodeJwtPayload(t.token).sub;
|
|
@@ -9986,11 +10049,9 @@ var configsCreate = defineCommand10({
|
|
|
9986
10049
|
const { configs: configs2 } = await listConfigs(DEPLOY_URL11, t.token, t.appId);
|
|
9987
10050
|
if (configs2.some((c) => c.name === name)) {
|
|
9988
10051
|
if (copyFrom) {
|
|
9989
|
-
|
|
9990
|
-
new
|
|
9991
|
-
|
|
9992
|
-
"config_exists"
|
|
9993
|
-
)
|
|
10052
|
+
throw new InputError(
|
|
10053
|
+
`Config "${name}" already exists \u2014 refusing to copy "${copyFrom}" over it. Delete it first, or pick a new name.`,
|
|
10054
|
+
"config_exists"
|
|
9994
10055
|
);
|
|
9995
10056
|
}
|
|
9996
10057
|
ok(
|
|
@@ -10890,7 +10951,7 @@ var pull_default = defineDeepspaceCommand({
|
|
|
10890
10951
|
// src/cli/commands/clone.ts
|
|
10891
10952
|
import * as p20 from "@clack/prompts";
|
|
10892
10953
|
import { existsSync as existsSync22, readdirSync as readdirSync6, rmSync as rmSync5 } from "fs";
|
|
10893
|
-
import { resolve as resolve17, basename as basename5, join as
|
|
10954
|
+
import { resolve as resolve17, basename as basename5, join as join20 } from "path";
|
|
10894
10955
|
function cleanFailedCloneDir(dir) {
|
|
10895
10956
|
let entries;
|
|
10896
10957
|
try {
|
|
@@ -10900,7 +10961,7 @@ function cleanFailedCloneDir(dir) {
|
|
|
10900
10961
|
}
|
|
10901
10962
|
if (entries.length === 1 && entries[0] === ".git") {
|
|
10902
10963
|
try {
|
|
10903
|
-
rmSync5(
|
|
10964
|
+
rmSync5(join20(dir, ".git"), { recursive: true, force: true });
|
|
10904
10965
|
return [];
|
|
10905
10966
|
} catch {
|
|
10906
10967
|
return entries;
|
|
@@ -11385,8 +11446,16 @@ function printOverlaps(overlaps, json) {
|
|
|
11385
11446
|
|
|
11386
11447
|
// src/cli/commands/workspace/local.ts
|
|
11387
11448
|
import * as p24 from "@clack/prompts";
|
|
11388
|
-
import {
|
|
11389
|
-
|
|
11449
|
+
import {
|
|
11450
|
+
existsSync as existsSync23,
|
|
11451
|
+
mkdirSync as mkdirSync7,
|
|
11452
|
+
readFileSync as readFileSync25,
|
|
11453
|
+
realpathSync as realpathSync6,
|
|
11454
|
+
renameSync as renameSync2,
|
|
11455
|
+
statSync as statSync3,
|
|
11456
|
+
writeFileSync as writeFileSync7
|
|
11457
|
+
} from "fs";
|
|
11458
|
+
import { dirname as dirname11, isAbsolute as isAbsolute5, join as join21, relative as relative2, sep as sep2 } from "path";
|
|
11390
11459
|
var WORKSPACE_MARKER = "deepspace-workspace.json";
|
|
11391
11460
|
function excludeWorktreeDir(appDir, dir) {
|
|
11392
11461
|
try {
|
|
@@ -11407,7 +11476,7 @@ function worktreeMarkerPath(worktreeRoot) {
|
|
|
11407
11476
|
const result = runGit(worktreeRoot, ["rev-parse", "--absolute-git-dir"], { allowFail: true });
|
|
11408
11477
|
if (result.status !== 0) return null;
|
|
11409
11478
|
const gitDir = result.stdout.toString("utf-8").trim();
|
|
11410
|
-
return isAbsolute5(gitDir) ?
|
|
11479
|
+
return isAbsolute5(gitDir) ? join21(gitDir, WORKSPACE_MARKER) : null;
|
|
11411
11480
|
} catch {
|
|
11412
11481
|
return null;
|
|
11413
11482
|
}
|
|
@@ -11418,8 +11487,8 @@ function markManagedWorkspace(worktreeRoot, workspaceId) {
|
|
|
11418
11487
|
const marker = { version: 1, workspaceId, mode: "managed-linked" };
|
|
11419
11488
|
const tempPath = `${markerPath}.${process.pid}.tmp`;
|
|
11420
11489
|
try {
|
|
11421
|
-
mkdirSync7(
|
|
11422
|
-
|
|
11490
|
+
mkdirSync7(dirname11(markerPath), { recursive: true });
|
|
11491
|
+
writeFileSync7(tempPath, JSON.stringify(marker) + "\n");
|
|
11423
11492
|
renameSync2(tempPath, markerPath);
|
|
11424
11493
|
return true;
|
|
11425
11494
|
} catch {
|
|
@@ -11452,11 +11521,11 @@ function isManagedWorkspaceWorktree(worktreeRoot, workspaceId) {
|
|
|
11452
11521
|
function defaultWorkspaceRoot(appDir, workspaceId) {
|
|
11453
11522
|
const primary = listWorktrees(appDir)[0];
|
|
11454
11523
|
if (!primary) throw new Error("Git did not report a primary worktree");
|
|
11455
|
-
return
|
|
11524
|
+
return join21(primary.path, ".deepspace", "ws", workspaceId.slice(3).toLowerCase());
|
|
11456
11525
|
}
|
|
11457
11526
|
function appDirInWorktree(appDir, worktreeRoot) {
|
|
11458
11527
|
const appRelative = relative2(realpathSync6(repoToplevel(appDir)), realpathSync6(appDir));
|
|
11459
|
-
return appRelative ?
|
|
11528
|
+
return appRelative ? join21(worktreeRoot, appRelative) : worktreeRoot;
|
|
11460
11529
|
}
|
|
11461
11530
|
function primaryAppDir(appDir) {
|
|
11462
11531
|
const primary = listWorktrees(appDir)[0];
|
|
@@ -11491,7 +11560,7 @@ function rematerializeWorkspaceWorktree(appDir, worktreeRoot, branch, workspaceI
|
|
|
11491
11560
|
function inOwnLinkedWorktree(appDir, id) {
|
|
11492
11561
|
if (workspaceIdFromBranch(currentBranch(appDir)) !== id) return false;
|
|
11493
11562
|
try {
|
|
11494
|
-
return statSync3(
|
|
11563
|
+
return statSync3(join21(repoToplevel(appDir), ".git")).isFile();
|
|
11495
11564
|
} catch {
|
|
11496
11565
|
return false;
|
|
11497
11566
|
}
|
|
@@ -11532,6 +11601,7 @@ function cleanupJson(outcome) {
|
|
|
11532
11601
|
worktreeRetained: outcome.worktreeRetained,
|
|
11533
11602
|
branchDeleted: outcome.branchDeleted,
|
|
11534
11603
|
...outcome.mainDir ? { mainDir: outcome.mainDir } : {},
|
|
11604
|
+
...outcome.leftoverDir ? { leftoverDir: outcome.leftoverDir } : {},
|
|
11535
11605
|
...outcome.error ? { error: outcome.error } : {}
|
|
11536
11606
|
};
|
|
11537
11607
|
}
|
|
@@ -11606,7 +11676,23 @@ function cleanupWorkspaceLocal(appDir, id, trunkBranch, options = {}) {
|
|
|
11606
11676
|
}
|
|
11607
11677
|
const remove2 = runGit(mainDir, ["worktree", "remove", linked.path], { allowFail: true });
|
|
11608
11678
|
if (remove2.status !== 0) {
|
|
11609
|
-
|
|
11679
|
+
const reason = remove2.stderr.toString("utf-8").trim() || "unknown git error";
|
|
11680
|
+
const registered = listWorktrees(mainDir);
|
|
11681
|
+
const stillRegistered = registered.length === 0 || registered.some((worktree, index) => index > 0 && worktree.path === linked.path);
|
|
11682
|
+
if (stillRegistered) {
|
|
11683
|
+
out.error = `git worktree remove ${linked.path} failed: ${reason}`;
|
|
11684
|
+
return out;
|
|
11685
|
+
}
|
|
11686
|
+
runGit(mainDir, ["worktree", "prune"], { allowFail: true });
|
|
11687
|
+
out.worktreeDir = null;
|
|
11688
|
+
const leftover = existsSync23(linked.path);
|
|
11689
|
+
if (leftover) out.leftoverDir = linked.path;
|
|
11690
|
+
else out.worktreeRemoved = linked.path;
|
|
11691
|
+
deleteWsBranch(mainDir, branch, expectedBranchOid, out);
|
|
11692
|
+
if (leftover) {
|
|
11693
|
+
const branchProblem = out.error;
|
|
11694
|
+
out.error = `git removed the worktree but could not delete its files (${reason})` + (branchProblem ? `. Also: ${branchProblem}` : "");
|
|
11695
|
+
}
|
|
11610
11696
|
return out;
|
|
11611
11697
|
}
|
|
11612
11698
|
out.worktreeRemoved = linked.path;
|
|
@@ -11628,12 +11714,20 @@ function cleanupWorkspaceLocal(appDir, id, trunkBranch, options = {}) {
|
|
|
11628
11714
|
function cleanupRefusalMessage(outcome) {
|
|
11629
11715
|
if (outcome.worktreeDir) {
|
|
11630
11716
|
const dir = shQuote(outcome.worktreeDir);
|
|
11631
|
-
|
|
11717
|
+
if (outcome.error.includes("contains modified or untracked files")) {
|
|
11718
|
+
return `Cleanup incomplete: ${outcome.error}. The worktree at ${dir} still holds uncommitted or untracked work \u2014 that's why the plain removal refused. Inspect it (\`git -C ${dir} status\`) and commit anything worth keeping to the workspace branch. Once it's clean, remove it from the main checkout: \`git worktree remove ${dir}\`.`;
|
|
11719
|
+
}
|
|
11720
|
+
return `Cleanup incomplete: ${outcome.error}. The worktree at ${dir} is still registered; git refused the plain removal for the reason above. Inspect it (\`git -C ${dir} status\`), resolve that, then remove it from the main checkout: \`git worktree remove ${dir}\`.`;
|
|
11721
|
+
}
|
|
11722
|
+
if (outcome.leftoverDir) {
|
|
11723
|
+
return `Cleanup incomplete: ${outcome.error}. Close anything using that folder \u2014 a dev server, an editor, or a shell inside it \u2014 then delete: ${shQuote(outcome.leftoverDir)}`;
|
|
11632
11724
|
}
|
|
11633
11725
|
return `Cleanup incomplete: ${outcome.error}. Finish it from the main checkout once ${shQuote(outcome.branch)} is safe to delete.`;
|
|
11634
11726
|
}
|
|
11635
11727
|
function cleanupAction(outcome) {
|
|
11636
|
-
|
|
11728
|
+
if (outcome.worktreeDir) return { cwd: outcome.worktreeDir, argv: ["git", "status"] };
|
|
11729
|
+
if (outcome.leftoverDir) return { cwd: process.cwd(), argv: ["git", "worktree", "list"] };
|
|
11730
|
+
return { cwd: process.cwd(), argv: ["git", "branch", "--list", outcome.branch] };
|
|
11637
11731
|
}
|
|
11638
11732
|
function reportCleanupHuman(outcome) {
|
|
11639
11733
|
if (outcome.error) {
|
|
@@ -11641,6 +11735,7 @@ function reportCleanupHuman(outcome) {
|
|
|
11641
11735
|
cleanupRefusalMessage({
|
|
11642
11736
|
error: outcome.error,
|
|
11643
11737
|
worktreeDir: outcome.worktreeDir,
|
|
11738
|
+
leftoverDir: outcome.leftoverDir,
|
|
11644
11739
|
branch: outcome.branch
|
|
11645
11740
|
})
|
|
11646
11741
|
);
|
|
@@ -11888,7 +11983,7 @@ var newWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11888
11983
|
|
|
11889
11984
|
// src/cli/commands/workspace/attach.ts
|
|
11890
11985
|
import * as p26 from "@clack/prompts";
|
|
11891
|
-
import { existsSync as
|
|
11986
|
+
import { existsSync as existsSync24, readdirSync as readdirSync7, realpathSync as realpathSync7, rmSync as rmSync6 } from "fs";
|
|
11892
11987
|
import { isAbsolute as isAbsolute7, resolve as resolve19 } from "path";
|
|
11893
11988
|
function samePath(a, b) {
|
|
11894
11989
|
const real = (p35) => {
|
|
@@ -11908,7 +12003,7 @@ function finishedWorkspaceMessage(id, view) {
|
|
|
11908
12003
|
return `Workspace ${id} is ${workspace.status} \u2014 its ref is retained briefly (fetch ${workspace.ref} to inspect), but attach only works on active workspaces.`;
|
|
11909
12004
|
}
|
|
11910
12005
|
function cleanFailedFreshAttachDir(dir) {
|
|
11911
|
-
if (!
|
|
12006
|
+
if (!existsSync24(dir)) return [];
|
|
11912
12007
|
let entries;
|
|
11913
12008
|
try {
|
|
11914
12009
|
entries = readdirSync7(dir);
|
|
@@ -11990,7 +12085,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
11990
12085
|
const localTip = resolveCommit(appDir, `refs/heads/${branch}`);
|
|
11991
12086
|
if (localTip) {
|
|
11992
12087
|
let existing = resolveWorkspaceWorktree(listWorktrees(appDir), id);
|
|
11993
|
-
if (existing && !
|
|
12088
|
+
if (existing && !existsSync24(existing)) {
|
|
11994
12089
|
runGit(appDir, ["worktree", "prune"], { allowFail: true });
|
|
11995
12090
|
existing = null;
|
|
11996
12091
|
}
|
|
@@ -12108,7 +12203,7 @@ var attachWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12108
12203
|
process.cwd(),
|
|
12109
12204
|
(typeof args.dir === "string" ? args.dir.trim() : "") || `ws-${id.slice(3).toLowerCase()}`
|
|
12110
12205
|
);
|
|
12111
|
-
if (
|
|
12206
|
+
if (existsSync24(dir)) {
|
|
12112
12207
|
spinner2?.stop("Target exists.");
|
|
12113
12208
|
throw new Refusal(`${dir} already exists \u2014 pass a different directory.`, "dir_exists");
|
|
12114
12209
|
}
|
|
@@ -12446,12 +12541,12 @@ import * as p30 from "@clack/prompts";
|
|
|
12446
12541
|
// src/cli/lib/validation.ts
|
|
12447
12542
|
import { sync as spawnSync7 } from "cross-spawn";
|
|
12448
12543
|
import { readFileSync as readFileSync26 } from "fs";
|
|
12449
|
-
import { join as
|
|
12544
|
+
import { join as join22 } from "path";
|
|
12450
12545
|
var MAX_SUMMARY_CHARS = 4e3;
|
|
12451
12546
|
var MAX_OUTPUT_BUFFER = 64 * 1024 * 1024;
|
|
12452
12547
|
function configuredCommand(appDir) {
|
|
12453
12548
|
try {
|
|
12454
|
-
const pkg2 = JSON.parse(readFileSync26(
|
|
12549
|
+
const pkg2 = JSON.parse(readFileSync26(join22(appDir, "package.json"), "utf-8"));
|
|
12455
12550
|
if (pkg2.scripts?.validate) return `${detectPackageManager(appDir)} run --silent validate`;
|
|
12456
12551
|
} catch {
|
|
12457
12552
|
}
|
|
@@ -12792,12 +12887,14 @@ var landWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12792
12887
|
if (cleanup?.error) {
|
|
12793
12888
|
const action2 = cleanupAction({
|
|
12794
12889
|
worktreeDir: cleanup.worktreeDir,
|
|
12890
|
+
leftoverDir: cleanup.leftoverDir,
|
|
12795
12891
|
branch: cleanup.branch
|
|
12796
12892
|
});
|
|
12797
12893
|
throw new Refusal(
|
|
12798
12894
|
cleanupRefusalMessage({
|
|
12799
12895
|
error: cleanup.error,
|
|
12800
12896
|
worktreeDir: cleanup.worktreeDir,
|
|
12897
|
+
leftoverDir: cleanup.leftoverDir,
|
|
12801
12898
|
branch: cleanup.branch
|
|
12802
12899
|
}),
|
|
12803
12900
|
"cleanup_incomplete",
|
|
@@ -12963,12 +13060,14 @@ var dropWorkspaceCommand = defineDeepspaceCommand({
|
|
|
12963
13060
|
if (cleanup?.error) {
|
|
12964
13061
|
const action = cleanupAction({
|
|
12965
13062
|
worktreeDir: cleanup.worktreeDir,
|
|
13063
|
+
leftoverDir: cleanup.leftoverDir,
|
|
12966
13064
|
branch: cleanup.branch
|
|
12967
13065
|
});
|
|
12968
13066
|
throw new Refusal(
|
|
12969
13067
|
cleanupRefusalMessage({
|
|
12970
13068
|
error: cleanup.error,
|
|
12971
13069
|
worktreeDir: cleanup.worktreeDir,
|
|
13070
|
+
leftoverDir: cleanup.leftoverDir,
|
|
12972
13071
|
branch: cleanup.branch
|
|
12973
13072
|
}),
|
|
12974
13073
|
"cleanup_incomplete",
|
|
@@ -13523,10 +13622,167 @@ function sameRefs(left, right) {
|
|
|
13523
13622
|
|
|
13524
13623
|
// src/cli/commands/update.ts
|
|
13525
13624
|
import * as p34 from "@clack/prompts";
|
|
13526
|
-
import { existsSync as
|
|
13527
|
-
import { join as
|
|
13625
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27, writeFileSync as writeFileSync8 } from "fs";
|
|
13626
|
+
import { join as join23, resolve as resolve20 } from "path";
|
|
13627
|
+
|
|
13628
|
+
// package.json
|
|
13629
|
+
var package_default = {
|
|
13630
|
+
name: "deepspace",
|
|
13631
|
+
version: "0.19.2",
|
|
13632
|
+
engines: {
|
|
13633
|
+
node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
|
|
13634
|
+
},
|
|
13635
|
+
description: "DeepSpace SDK \u2014 build real-time collaborative apps on Cloudflare Workers",
|
|
13636
|
+
type: "module",
|
|
13637
|
+
sideEffects: false,
|
|
13638
|
+
main: "./dist/index.js",
|
|
13639
|
+
types: "./dist/index.d.ts",
|
|
13640
|
+
bin: {
|
|
13641
|
+
deepspace: "dist/cli.js"
|
|
13642
|
+
},
|
|
13643
|
+
exports: {
|
|
13644
|
+
".": {
|
|
13645
|
+
types: "./dist/index.d.ts",
|
|
13646
|
+
import: "./dist/index.js"
|
|
13647
|
+
},
|
|
13648
|
+
"./schema": {
|
|
13649
|
+
types: "./dist/schema.d.ts",
|
|
13650
|
+
import: "./dist/schema.js"
|
|
13651
|
+
},
|
|
13652
|
+
"./worker": {
|
|
13653
|
+
types: "./dist/worker.d.ts",
|
|
13654
|
+
import: "./dist/worker.js"
|
|
13655
|
+
},
|
|
13656
|
+
"./server": {
|
|
13657
|
+
types: "./dist/server.d.ts",
|
|
13658
|
+
import: "./dist/server.js"
|
|
13659
|
+
},
|
|
13660
|
+
"./testing": {
|
|
13661
|
+
types: "./dist/testing.d.ts",
|
|
13662
|
+
import: "./dist/testing.js"
|
|
13663
|
+
},
|
|
13664
|
+
"./documentation": {
|
|
13665
|
+
types: "./dist/documentation.d.ts",
|
|
13666
|
+
import: "./dist/documentation.js"
|
|
13667
|
+
},
|
|
13668
|
+
"./documentation/react": {
|
|
13669
|
+
types: "./dist/documentation-react.d.ts",
|
|
13670
|
+
import: "./dist/documentation-react.js"
|
|
13671
|
+
}
|
|
13672
|
+
},
|
|
13673
|
+
files: [
|
|
13674
|
+
"dist",
|
|
13675
|
+
"features",
|
|
13676
|
+
"CHANGELOG.md"
|
|
13677
|
+
],
|
|
13678
|
+
scripts: {
|
|
13679
|
+
build: "node ../../scripts/clean-artifacts.mjs dist --tsbuildinfo && tsup",
|
|
13680
|
+
"type-check": "tsc --noEmit",
|
|
13681
|
+
test: "vitest run",
|
|
13682
|
+
"test:documentation-browser": "playwright test --config src/documentation/runtime/__browser__/playwright.config.ts",
|
|
13683
|
+
clean: "node ../../scripts/clean-artifacts.mjs dist --tsbuildinfo",
|
|
13684
|
+
prepublishOnly: "pnpm build"
|
|
13685
|
+
},
|
|
13686
|
+
dependencies: {
|
|
13687
|
+
"@ai-sdk/anthropic": "2.0.91",
|
|
13688
|
+
"@ai-sdk/openai": "2.0.116",
|
|
13689
|
+
"@ai-sdk/openai-compatible": "1.0.46",
|
|
13690
|
+
"@clack/prompts": "^1.2.0",
|
|
13691
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
13692
|
+
acorn: "^8.16.0",
|
|
13693
|
+
ai: "5.0.222",
|
|
13694
|
+
"better-auth": "1.6.23",
|
|
13695
|
+
citty: "^0.2.0",
|
|
13696
|
+
"cross-spawn": "^7.0.6",
|
|
13697
|
+
esbuild: "^0.27.0",
|
|
13698
|
+
"highlight.js": "^11.11.1",
|
|
13699
|
+
hono: "^4.6.0",
|
|
13700
|
+
jose: "^6.1.0",
|
|
13701
|
+
marked: "^18.0.7",
|
|
13702
|
+
"mdast-util-gfm": "^3.1.0",
|
|
13703
|
+
"mdast-util-to-markdown": "^2.1.2",
|
|
13704
|
+
"rehype-highlight": "^7.0.2",
|
|
13705
|
+
"remark-frontmatter": "^5.0.0",
|
|
13706
|
+
"remark-gfm": "^4.0.1",
|
|
13707
|
+
"sanitize-html": "^2.17.6",
|
|
13708
|
+
"smol-toml": "^1.6.1",
|
|
13709
|
+
yaml: "^2.9.0",
|
|
13710
|
+
yjs: "^13.6.0",
|
|
13711
|
+
zod: "^4.3.6"
|
|
13712
|
+
},
|
|
13713
|
+
peerDependencies: {
|
|
13714
|
+
"@playwright/test": ">=1.40.0",
|
|
13715
|
+
clsx: ">=2.0.0",
|
|
13716
|
+
"lucide-react": ">=0.400.0",
|
|
13717
|
+
react: "^18.0.0 || ^19.0.0",
|
|
13718
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
13719
|
+
"tailwind-merge": ">=2.0.0"
|
|
13720
|
+
},
|
|
13721
|
+
peerDependenciesMeta: {
|
|
13722
|
+
"@playwright/test": {
|
|
13723
|
+
optional: true
|
|
13724
|
+
},
|
|
13725
|
+
react: {
|
|
13726
|
+
optional: true
|
|
13727
|
+
},
|
|
13728
|
+
"react-dom": {
|
|
13729
|
+
optional: true
|
|
13730
|
+
},
|
|
13731
|
+
clsx: {
|
|
13732
|
+
optional: true
|
|
13733
|
+
},
|
|
13734
|
+
"tailwind-merge": {
|
|
13735
|
+
optional: true
|
|
13736
|
+
},
|
|
13737
|
+
"lucide-react": {
|
|
13738
|
+
optional: true
|
|
13739
|
+
}
|
|
13740
|
+
},
|
|
13741
|
+
devDependencies: {
|
|
13742
|
+
"@cloudflare/workers-types": "^4.20241205.0",
|
|
13743
|
+
"@playwright/test": "^1.59.1",
|
|
13744
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
13745
|
+
"@types/cross-spawn": "^6.0.6",
|
|
13746
|
+
"@types/react": "^19.0.0",
|
|
13747
|
+
"@types/react-dom": "^19.0.0",
|
|
13748
|
+
"@types/sanitize-html": "^2.16.1",
|
|
13749
|
+
"better-sqlite3": "^12.0.0",
|
|
13750
|
+
clsx: "^2.1.1",
|
|
13751
|
+
"framer-motion": "^12.38.0",
|
|
13752
|
+
jsdom: "^29.1.1",
|
|
13753
|
+
"lucide-react": "^1.7.0",
|
|
13754
|
+
"react-router-dom": "^7.1.0",
|
|
13755
|
+
"tailwind-merge": "^3.5.0",
|
|
13756
|
+
tsup: "^8.3.0",
|
|
13757
|
+
typescript: "^5.7.0",
|
|
13758
|
+
vitest: "^4.1.0"
|
|
13759
|
+
},
|
|
13760
|
+
keywords: [
|
|
13761
|
+
"deepspace",
|
|
13762
|
+
"cloudflare-workers",
|
|
13763
|
+
"durable-objects",
|
|
13764
|
+
"real-time",
|
|
13765
|
+
"collaborative",
|
|
13766
|
+
"sdk"
|
|
13767
|
+
],
|
|
13768
|
+
license: "Apache-2.0",
|
|
13769
|
+
homepage: "https://deep.space",
|
|
13770
|
+
repository: {
|
|
13771
|
+
type: "git",
|
|
13772
|
+
url: "git+https://github.com/deepdotspace/deepspace.git",
|
|
13773
|
+
directory: "packages/deepspace"
|
|
13774
|
+
},
|
|
13775
|
+
bugs: {
|
|
13776
|
+
url: "https://github.com/deepdotspace/deepspace/issues"
|
|
13777
|
+
}
|
|
13778
|
+
};
|
|
13779
|
+
|
|
13780
|
+
// src/cli/commands/update.ts
|
|
13528
13781
|
var REGISTRY = "https://registry.npmjs.org/deepspace/latest";
|
|
13529
13782
|
var DOCS_URL = "https://documentation.deep.space/cli-reference/commands";
|
|
13783
|
+
var BUILD_PREVIEW_SECRETS_GUIDE = "https://github.com/deepdotspace/deepspace-sdk/blob/main/docs/migrations/build-preview-secrets.md";
|
|
13784
|
+
var USERS_SCHEMA_VISIBILITY_GUIDE = "https://github.com/deepdotspace/deepspace-sdk/blob/main/docs/migrations/users-schema-member-visibility.md";
|
|
13785
|
+
var COMPATIBLE_AI_VERSION = package_default.dependencies.ai;
|
|
13530
13786
|
var OLDEST_SUPPORTED_MINOR = 12;
|
|
13531
13787
|
function parseVersion(raw) {
|
|
13532
13788
|
const match = /^(\d+)\.(\d+)\.(\d+)/.exec(raw.trim().replace(/^[\^~]/, ""));
|
|
@@ -13538,27 +13794,58 @@ function gapIsTooWide(from, to) {
|
|
|
13538
13794
|
return from.major === 0 && from.minor < OLDEST_SUPPORTED_MINOR;
|
|
13539
13795
|
}
|
|
13540
13796
|
function readAppSdkVersion(appDir) {
|
|
13541
|
-
const installed =
|
|
13542
|
-
if (
|
|
13797
|
+
const installed = join23(appDir, "node_modules", "deepspace", "package.json");
|
|
13798
|
+
if (existsSync25(installed)) {
|
|
13543
13799
|
const parsed2 = JSON.parse(readFileSync27(installed, "utf8"));
|
|
13544
13800
|
if (typeof parsed2.version === "string") return parsed2.version;
|
|
13545
13801
|
}
|
|
13546
|
-
const manifest =
|
|
13547
|
-
if (!
|
|
13802
|
+
const manifest = join23(appDir, "package.json");
|
|
13803
|
+
if (!existsSync25(manifest)) return null;
|
|
13548
13804
|
const parsed = JSON.parse(readFileSync27(manifest, "utf8"));
|
|
13549
13805
|
return parsed.dependencies?.deepspace ?? null;
|
|
13550
13806
|
}
|
|
13551
13807
|
function pinSdkVersion(appDir, version) {
|
|
13552
|
-
const path =
|
|
13808
|
+
const path = join23(appDir, "package.json");
|
|
13553
13809
|
const source = readFileSync27(path, "utf8");
|
|
13554
|
-
const
|
|
13555
|
-
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
if (
|
|
13559
|
-
|
|
13810
|
+
const manifest = JSON.parse(source);
|
|
13811
|
+
const dependencies = manifest.dependencies;
|
|
13812
|
+
if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) return false;
|
|
13813
|
+
let changed = false;
|
|
13814
|
+
if (Object.prototype.hasOwnProperty.call(dependencies, "deepspace") && typeof dependencies.deepspace === "string" && dependencies.deepspace !== `^${version}`) {
|
|
13815
|
+
dependencies.deepspace = `^${version}`;
|
|
13816
|
+
changed = true;
|
|
13817
|
+
}
|
|
13818
|
+
if (Object.prototype.hasOwnProperty.call(dependencies, "ai") && typeof dependencies.ai === "string" && dependencies.ai !== COMPATIBLE_AI_VERSION) {
|
|
13819
|
+
dependencies.ai = COMPATIBLE_AI_VERSION;
|
|
13820
|
+
changed = true;
|
|
13821
|
+
}
|
|
13822
|
+
if (!changed) return false;
|
|
13823
|
+
const eol = source.includes("\r\n") ? "\r\n" : "\n";
|
|
13824
|
+
const indent = source.match(/\r?\n([\t ]+)"/)?.[1] ?? " ";
|
|
13825
|
+
const finalEol = source.endsWith("\n") ? eol : "";
|
|
13826
|
+
writeFileSync8(path, JSON.stringify(manifest, null, indent).replaceAll("\n", eol) + finalEol);
|
|
13560
13827
|
return true;
|
|
13561
13828
|
}
|
|
13829
|
+
function buildPreviewSecretsUpgradeInstruction(appDir) {
|
|
13830
|
+
const configName = [
|
|
13831
|
+
"vite.config.ts",
|
|
13832
|
+
"vite.config.mts",
|
|
13833
|
+
"vite.config.js",
|
|
13834
|
+
"vite.config.mjs"
|
|
13835
|
+
].find((candidate) => existsSync25(join23(appDir, candidate)));
|
|
13836
|
+
if (!configName) return null;
|
|
13837
|
+
const source = readFileSync27(join23(appDir, configName), "utf8");
|
|
13838
|
+
if (source.includes("deepspace-remove-build-preview-secrets")) return null;
|
|
13839
|
+
return `${configName}: add the build-preview secret cleanup from ${BUILD_PREVIEW_SECRETS_GUIDE}; app update left this app-owned file unchanged.`;
|
|
13840
|
+
}
|
|
13841
|
+
function usersSchemaVisibilityUpgradeInstruction(appDir) {
|
|
13842
|
+
const schemaName = "src/schemas/users-schema.ts";
|
|
13843
|
+
const path = join23(appDir, schemaName);
|
|
13844
|
+
if (!existsSync25(path)) return null;
|
|
13845
|
+
const source = readFileSync27(path, "utf8");
|
|
13846
|
+
if (!/\bmember\s*:\s*\{[^}]*\bread\s*:\s*true\b/s.test(source)) return null;
|
|
13847
|
+
return `${schemaName}: review the member user-row visibility change at ${USERS_SCHEMA_VISIBILITY_GUIDE}; app update left this app-owned schema unchanged.`;
|
|
13848
|
+
}
|
|
13562
13849
|
async function latestPublishedVersion() {
|
|
13563
13850
|
const response = await fetch(REGISTRY, { signal: AbortSignal.timeout(15e3) }).catch(
|
|
13564
13851
|
(error) => {
|
|
@@ -13648,27 +13935,36 @@ var update_default = defineDeepspaceCommand({
|
|
|
13648
13935
|
}
|
|
13649
13936
|
const dryRun = args["dry-run"] === true;
|
|
13650
13937
|
const plan = planAppMigrations(appDir);
|
|
13938
|
+
const previewSecretsInstruction = buildPreviewSecretsUpgradeInstruction(appDir);
|
|
13939
|
+
const usersSchemaInstruction = usersSchemaVisibilityUpgradeInstruction(appDir);
|
|
13940
|
+
const manualInstructions = [previewSecretsInstruction, usersSchemaInstruction].filter(
|
|
13941
|
+
(instruction) => instruction !== null
|
|
13942
|
+
);
|
|
13651
13943
|
const pinned = dryRun ? false : pinSdkVersion(appDir, targetRaw);
|
|
13652
13944
|
if (!dryRun && plan.edits.length) applyAppMigrationPlan(appDir, plan);
|
|
13653
13945
|
if (!args.json) {
|
|
13654
13946
|
p34.log.info(`deepspace ${currentRaw} \u2192 ${targetRaw}`);
|
|
13655
13947
|
if (pinned) p34.log.success("package.json now asks for the current SDK");
|
|
13948
|
+
for (const instruction of manualInstructions) p34.log.warn(instruction);
|
|
13656
13949
|
if (!plan.pending.length && !plan.blockers.length) {
|
|
13657
|
-
p34.log.success("No source changes required.");
|
|
13950
|
+
p34.log.success("No automatic source changes required.");
|
|
13658
13951
|
}
|
|
13659
13952
|
reportPlan(plan, !dryRun);
|
|
13660
13953
|
}
|
|
13661
|
-
if (plan.blockers.length) {
|
|
13954
|
+
if (plan.blockers.length || manualInstructions.length) {
|
|
13955
|
+
const remaining = plan.blockers.length + manualInstructions.length;
|
|
13662
13956
|
throw new Refusal(
|
|
13663
|
-
`${
|
|
13957
|
+
`${remaining} change(s) need a human or agent edit; follow the returned manual instructions and blockers.`,
|
|
13664
13958
|
"manual_changes_required",
|
|
13665
13959
|
{
|
|
13960
|
+
...pinned ? { action: cliAction("npm", "install") } : {},
|
|
13666
13961
|
actionRequired: true,
|
|
13667
13962
|
extra: {
|
|
13668
13963
|
currentVersion: currentRaw,
|
|
13669
13964
|
targetVersion: targetRaw,
|
|
13670
13965
|
applied: plan.pending.map((migration) => migration.id),
|
|
13671
|
-
blockers: plan.blockers
|
|
13966
|
+
blockers: plan.blockers,
|
|
13967
|
+
manualInstructions
|
|
13672
13968
|
}
|
|
13673
13969
|
}
|
|
13674
13970
|
);
|
|
@@ -13679,6 +13975,7 @@ var update_default = defineDeepspaceCommand({
|
|
|
13679
13975
|
targetVersion: targetRaw,
|
|
13680
13976
|
pinned,
|
|
13681
13977
|
dryRun,
|
|
13978
|
+
manualInstructions,
|
|
13682
13979
|
applied: plan.pending.map((migration) => ({
|
|
13683
13980
|
id: migration.id,
|
|
13684
13981
|
description: migration.description,
|
|
@@ -13695,9 +13992,9 @@ var update_default = defineDeepspaceCommand({
|
|
|
13695
13992
|
});
|
|
13696
13993
|
|
|
13697
13994
|
// src/cli/cli.ts
|
|
13698
|
-
var __dirname =
|
|
13699
|
-
var pkg = JSON.parse(readFileSync28(
|
|
13700
|
-
if (process.platform === "linux" && !process.env.SSL_CERT_FILE &&
|
|
13995
|
+
var __dirname = dirname12(fileURLToPath3(import.meta.url));
|
|
13996
|
+
var pkg = JSON.parse(readFileSync28(join24(__dirname, "..", "package.json"), "utf-8"));
|
|
13997
|
+
if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync26("/etc/ssl/certs/ca-certificates.crt")) {
|
|
13701
13998
|
process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
|
|
13702
13999
|
}
|
|
13703
14000
|
var create2 = defineCommand14({
|