deepspace 0.4.4 → 0.4.5

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/dist/cli.js CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/cli.ts
4
- import { defineCommand as defineCommand21, runMain } from "citty";
4
+ import { defineCommand as defineCommand18, runMain } from "citty";
5
5
  import { execSync as execSync5 } from "child_process";
6
- import { readFileSync as readFileSync13, existsSync as existsSync14 } from "fs";
7
- import { dirname as dirname4, join as join16 } from "path";
6
+ import { readFileSync as readFileSync12, existsSync as existsSync13 } from "fs";
7
+ import { dirname as dirname4, join as join14 } from "path";
8
8
  import { fileURLToPath as fileURLToPath2 } from "url";
9
9
 
10
10
  // src/cli/commands/login.ts
@@ -122,6 +122,9 @@ function resolveAppNameForEnv(config, envName) {
122
122
  }
123
123
  return resolveAppName(envBlock.name);
124
124
  }
125
+ function devVarsPathFor(appDir, envName) {
126
+ return envName ? join(appDir, `.dev.vars.${envName}`) : join(appDir, ".dev.vars");
127
+ }
125
128
  var WranglerConfigError = class extends Error {
126
129
  constructor(path, cause) {
127
130
  const detail = cause instanceof Error ? cause.message : String(cause);
@@ -232,22 +235,8 @@ var SDK_MANAGED_KEYS = /* @__PURE__ */ new Set([
232
235
  "OWNER_USER_ID",
233
236
  "APP_OWNER_JWT",
234
237
  "APP_IDENTITY_TOKEN",
235
- "APP_SECRETS_KEY",
236
- "APP_SECRETS_LOCAL_FALLBACK",
237
238
  "ALLOW_DEBUG_ROUTES"
238
239
  ]);
239
- var MANAGED_ENV_HEADER = "# Managed by `deepspace secrets` and regenerated by `deepspace dev`/`deepspace test`.";
240
- var MANAGED_ENV_SYNCED_HEADER = "# DeepSpace synced secrets - mirrored with the deployed app secrets store.";
241
- var MANAGED_ENV_DEV_ONLY_HEADER = "# DeepSpace dev-only secrets - used by `deepspace dev`; never synced unless pushed.";
242
- function localEnvPath(appDir) {
243
- return join2(appDir, ".env");
244
- }
245
- function legacyDevVarsPath(appDir, wranglerEnv) {
246
- return join2(appDir, wranglerEnv ? `.dev.vars.${wranglerEnv}` : ".dev.vars");
247
- }
248
- function hasLegacyDevVars(appDir, wranglerEnv) {
249
- return existsSync2(legacyDevVarsPath(appDir, wranglerEnv));
250
- }
251
240
  var DEV_VARS_DIVIDER = "# --- not managed by the SDK; preserved across dev/test runs ---";
252
241
  function extractCustomDevVars(content) {
253
242
  const lines = content.split("\n");
@@ -354,189 +343,6 @@ function parseDevVars(content) {
354
343
  }
355
344
  return result;
356
345
  }
357
- function parseDevVarsStrict(content, file = ".env") {
358
- const result = {};
359
- const lines = content.split("\n");
360
- let i = 0;
361
- while (i < lines.length) {
362
- const line = lines[i];
363
- const trimmed = line.trim();
364
- if (!trimmed || trimmed.startsWith("#")) {
365
- i++;
366
- continue;
367
- }
368
- const eq = line.indexOf("=");
369
- if (eq < 0) {
370
- throw new Error(`${file}: invalid dotenv syntax on line ${i + 1}. Expected KEY=value.`);
371
- }
372
- const keyMatch = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
373
- if (!keyMatch) {
374
- throw new Error(`${file}: invalid variable name on line ${i + 1}.`);
375
- }
376
- const key = keyMatch[1];
377
- let value = line.slice(eq + 1);
378
- let closed = !value.startsWith('"') || hasUnescapedQuote(value.slice(1));
379
- if (!closed) {
380
- i++;
381
- while (i < lines.length) {
382
- value += "\n" + lines[i];
383
- if (hasUnescapedQuote(lines[i])) {
384
- closed = true;
385
- i++;
386
- break;
387
- }
388
- i++;
389
- }
390
- } else {
391
- i++;
392
- }
393
- if (value.startsWith('"') && !closed) {
394
- throw new Error(`${file}: unterminated quoted value for key "${key}".`);
395
- }
396
- if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
397
- value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
398
- }
399
- result[key] = value;
400
- }
401
- return result;
402
- }
403
- function quoteEnvValue(value) {
404
- return /^[A-Za-z0-9_./:@-]*$/.test(value) && !value.includes("\n") ? value : `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
405
- }
406
- function stripSdkManaged(vars) {
407
- const out = {};
408
- for (const [name, value] of Object.entries(vars)) {
409
- if (!SDK_MANAGED_KEYS.has(name)) out[name] = value;
410
- }
411
- return out;
412
- }
413
- function sortRecord(input) {
414
- const out = {};
415
- for (const key of Object.keys(input).sort()) out[key] = input[key];
416
- return out;
417
- }
418
- function readManagedEnvSections(appDir) {
419
- const path = localEnvPath(appDir);
420
- if (!existsSync2(path)) return { sdk: {}, synced: {}, devOnly: {} };
421
- return parseManagedEnvSections(readFileSync2(path, "utf-8"));
422
- }
423
- function parseManagedEnvSections(content) {
424
- const sections = { sdk: {}, synced: {}, devOnly: {} };
425
- const legacyAppLines = [];
426
- let target = "sdk";
427
- const lines = content.split("\n");
428
- for (let i = 0; i < lines.length; i++) {
429
- const line = lines[i];
430
- if (line.trim() === MANAGED_ENV_SYNCED_HEADER.trim()) {
431
- target = "synced";
432
- continue;
433
- }
434
- if (line.trim() === MANAGED_ENV_DEV_ONLY_HEADER.trim()) {
435
- target = "devOnly";
436
- continue;
437
- }
438
- if (line.trim().startsWith("#")) continue;
439
- const name = assignmentName(line);
440
- if (!name) {
441
- if (line.trim()) legacyAppLines.push(line);
442
- continue;
443
- }
444
- const block = [line];
445
- const eq = line.indexOf("=");
446
- const valStart = eq >= 0 ? line.slice(eq + 1) : "";
447
- if (valStart.startsWith('"') && !hasUnescapedQuote(valStart.slice(1))) {
448
- i++;
449
- while (i < lines.length) {
450
- block.push(lines[i]);
451
- const closed = hasUnescapedQuote(lines[i]);
452
- if (closed) break;
453
- i++;
454
- }
455
- }
456
- if (target === "sdk" && !SDK_MANAGED_KEYS.has(name)) {
457
- legacyAppLines.push(...block);
458
- continue;
459
- }
460
- const parsed = parseDevVarsStrict(block.join("\n"), ".env");
461
- Object.assign(sections[target], parsed);
462
- }
463
- if (legacyAppLines.length) {
464
- Object.assign(sections.synced, stripSdkManaged(parseDevVarsStrict(legacyAppLines.join("\n"), ".env")));
465
- }
466
- return sections;
467
- }
468
- function assignmentName(line) {
469
- const eq = line.indexOf("=");
470
- if (eq < 0) return null;
471
- const match = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
472
- return match?.[1] ?? null;
473
- }
474
- function readManagedAppEnv(appDir) {
475
- const sections = readManagedEnvSections(appDir);
476
- return { ...sections.synced, ...sections.devOnly };
477
- }
478
- function readManagedSyncedEnv(appDir) {
479
- return { ...readManagedEnvSections(appDir).synced };
480
- }
481
- function readManagedDevOnlyEnv(appDir) {
482
- return { ...readManagedEnvSections(appDir).devOnly };
483
- }
484
- function writeManagedEnvSections(appDir, sections) {
485
- ensureLocalEnvIgnored(appDir);
486
- const lines = [
487
- MANAGED_ENV_HEADER,
488
- "# Do not commit this file. Edit secrets with `deepspace secrets`, not by hand."
489
- ];
490
- for (const [name, value] of Object.entries(sortRecord(sections.sdk))) {
491
- lines.push(`${name}=${quoteEnvValue(value)}`);
492
- }
493
- lines.push("", MANAGED_ENV_SYNCED_HEADER);
494
- for (const [name, value] of Object.entries(sortRecord(sections.synced))) {
495
- lines.push(`${name}=${quoteEnvValue(value)}`);
496
- }
497
- lines.push("", MANAGED_ENV_DEV_ONLY_HEADER);
498
- for (const [name, value] of Object.entries(sortRecord(sections.devOnly))) {
499
- lines.push(`${name}=${quoteEnvValue(value)}`);
500
- }
501
- writeFileSync(localEnvPath(appDir), lines.join("\n") + "\n", { mode: 384 });
502
- }
503
- function ensureLocalEnvIgnored(appDir) {
504
- const path = join2(appDir, ".gitignore");
505
- const existing = existsSync2(path) ? readFileSync2(path, "utf-8") : "";
506
- const lines = new Set(existing.split("\n").map((line) => line.trim()));
507
- const additions = [".env", ".dev.vars"].filter((entry) => !lines.has(entry));
508
- if (!additions.length) return;
509
- const prefix = existing && !existing.endsWith("\n") ? existing + "\n" : existing;
510
- writeFileSync(path, `${prefix}${additions.join("\n")}
511
- `);
512
- }
513
- function patchManagedSyncedEnv(appDir, set2 = {}, removeNames = []) {
514
- const sections = readManagedEnvSections(appDir);
515
- for (const [name, value] of Object.entries(set2)) sections.synced[name] = value;
516
- for (const name of removeNames) delete sections.synced[name];
517
- writeManagedEnvSections(appDir, sections);
518
- }
519
- function patchManagedDevOnlyEnv(appDir, set2 = {}, removeNames = []) {
520
- const sections = readManagedEnvSections(appDir);
521
- for (const [name, value] of Object.entries(set2)) sections.devOnly[name] = value;
522
- for (const name of removeNames) delete sections.devOnly[name];
523
- writeManagedEnvSections(appDir, sections);
524
- }
525
- function replaceManagedSyncedEnv(appDir, syncedVars) {
526
- const sections = readManagedEnvSections(appDir);
527
- sections.synced = stripSdkManaged(syncedVars);
528
- writeManagedEnvSections(appDir, sections);
529
- }
530
- function moveManagedDevOnlyToSynced(appDir, names) {
531
- const sections = readManagedEnvSections(appDir);
532
- for (const name of names) {
533
- if (name in sections.devOnly) {
534
- sections.synced[name] = sections.devOnly[name];
535
- delete sections.devOnly[name];
536
- }
537
- }
538
- writeManagedEnvSections(appDir, sections);
539
- }
540
346
  async function writeDevVars(appDir, env, ownerId, callerJwt, wranglerEnv) {
541
347
  const urls = ENVS[env];
542
348
  const publicKey = await fetchPublicKey(urls.auth);
@@ -552,18 +358,11 @@ async function writeDevVars(appDir, env, ownerId, callerJwt, wranglerEnv) {
552
358
  `OWNER_USER_ID=${ownerId}`,
553
359
  `APP_OWNER_JWT=${appOwnerJwt}`,
554
360
  ...appIdentityToken ? [`APP_IDENTITY_TOKEN=${appIdentityToken}`] : [],
555
- `APP_SECRETS_LOCAL_FALLBACK=true`,
556
361
  // Open /api/debug/* (proxied to RecordRoom) for dev + tests only.
557
362
  // Production secrets never set this, so deployed apps 404 the route.
558
363
  `ALLOW_DEBUG_ROUTES=true`
559
364
  ].join("\n");
560
- const sdkEnv = parseDevVarsStrict(sdkVars, "SDK env");
561
- if (!hasLegacyDevVars(appDir, wranglerEnv)) {
562
- const sections = readManagedEnvSections(appDir);
563
- writeManagedEnvSections(appDir, { ...sections, sdk: sdkEnv });
564
- return;
565
- }
566
- const devVarsPath = legacyDevVarsPath(appDir, wranglerEnv);
365
+ const devVarsPath = join2(appDir, wranglerEnv ? `.dev.vars.${wranglerEnv}` : ".dev.vars");
567
366
  const existing = existsSync2(devVarsPath) ? readFileSync2(devVarsPath, "utf-8") : "";
568
367
  const custom = extractCustomDevVars(existing);
569
368
  const body = custom ? `${sdkVars}
@@ -772,7 +571,7 @@ var logout_default = defineCommand2({
772
571
  });
773
572
 
774
573
  // src/cli/commands/dev.ts
775
- import { defineCommand as defineCommand4 } from "citty";
574
+ import { defineCommand as defineCommand3 } from "citty";
776
575
  import { resolve as resolve3, basename } from "path";
777
576
  import spawn from "cross-spawn";
778
577
 
@@ -782,8 +581,8 @@ import { join as join5 } from "path";
782
581
  import { homedir as homedir3 } from "os";
783
582
 
784
583
  // src/cli/jwt.ts
785
- function decodeJwtPayload(token2) {
786
- const payloadSegment = token2.split(".")[1];
584
+ function decodeJwtPayload(token) {
585
+ const payloadSegment = token.split(".")[1];
787
586
  if (!payloadSegment) {
788
587
  throw new Error("JWT payload is missing");
789
588
  }
@@ -806,13 +605,13 @@ async function ensureToken() {
806
605
  throw new Error("Not logged in. Run `deepspace login` first.");
807
606
  }
808
607
  const sessionToken = readFileSync4(SESSION_PATH2, "utf-8").trim();
809
- const token2 = await exchangeSession(AUTH_URL3, sessionToken);
810
- if (!token2) {
608
+ const token = await exchangeSession(AUTH_URL3, sessionToken);
609
+ if (!token) {
811
610
  throw new Error("Session expired. Run `deepspace login` to re-authenticate.");
812
611
  }
813
612
  mkdirSync2(DIR2, { recursive: true, mode: 448 });
814
- writeFileSync3(TOKEN_PATH2, token2, { mode: 384 });
815
- return token2;
613
+ writeFileSync3(TOKEN_PATH2, token, { mode: 384 });
614
+ return token;
816
615
  }
817
616
  function isTokenValid(jwt) {
818
617
  try {
@@ -947,525 +746,9 @@ function preflightWindowsWorkerd(appDir) {
947
746
  }
948
747
  }
949
748
 
950
- // src/cli/commands/secrets.ts
951
- import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
952
- import { join as join8 } from "path";
953
- import { defineCommand as defineCommand3 } from "citty";
954
- var SECRET_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
955
- var ERROR_SNIPPET_CHARS = 500;
956
- var COLLABORATOR_ROUTES_404 = "Platform API does not expose app-collaborator routes; deploy/update api-worker before using collaborator commands.";
957
- var COLLABORATOR_SCHEMA_NOT_MIGRATED = "Platform API is missing app-collaborator database tables. Run api-worker /_migrate with x-migration-secret, then retry collaborator commands.";
958
- function parseAssignment(value) {
959
- const eq = value.indexOf("=");
960
- if (eq <= 0) throw new Error("Use KEY=value.");
961
- const name = value.slice(0, eq);
962
- if (!SECRET_NAME_RE.test(name)) throw new Error(`Invalid secret name "${name}".`);
963
- if (SDK_MANAGED_KEYS.has(name)) throw new Error(`${name} is managed by DeepSpace and cannot be set as an app secret.`);
964
- return [name, value.slice(eq + 1)];
965
- }
966
- function devTargetPath() {
967
- return join8(process.cwd(), ".dev.vars");
968
- }
969
- function readDevTarget() {
970
- if (!hasLegacyDevVars(process.cwd())) {
971
- return readManagedAppEnv(process.cwd());
972
- }
973
- const path = devTargetPath();
974
- if (!existsSync8(path)) return {};
975
- return stripSdkManaged(parseDevVars(splitDevTarget(readFileSync7(path, "utf-8")).custom));
976
- }
977
- function readSyncedTarget() {
978
- if (hasLegacyDevVars(process.cwd())) return readDevTarget();
979
- return readManagedSyncedEnv(process.cwd());
980
- }
981
- function readDevOnlyTarget() {
982
- if (hasLegacyDevVars(process.cwd())) return readDevTarget();
983
- return readManagedDevOnlyEnv(process.cwd());
984
- }
985
- function writeLocalPatch(set2 = {}, removeNames = []) {
986
- for (const name of [...Object.keys(set2), ...removeNames]) {
987
- if (SDK_MANAGED_KEYS.has(name)) {
988
- throw new Error(`${name} is managed by DeepSpace and cannot be set as an app secret.`);
989
- }
990
- }
991
- if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch(set2, removeNames);
992
- else {
993
- patchManagedDevOnlyEnv(process.cwd(), set2, removeNames);
994
- }
995
- }
996
- function quote(value) {
997
- return quoteEnvValue(value);
998
- }
999
- function splitLocal(raw) {
1000
- const idx = raw.indexOf(DEV_VARS_DIVIDER);
1001
- if (idx < 0) return { top: "", custom: raw };
1002
- const after = raw.slice(idx + DEV_VARS_DIVIDER.length);
1003
- return {
1004
- top: raw.slice(0, idx).trimEnd(),
1005
- custom: after.startsWith("\n") ? after.slice(1) : after
1006
- };
1007
- }
1008
- function splitDevTarget(raw) {
1009
- const idx = raw.indexOf(DEV_VARS_DIVIDER);
1010
- if (idx >= 0) return splitLocal(raw);
1011
- const lines = raw.split("\n");
1012
- const top = [];
1013
- const custom = [];
1014
- let target = top;
1015
- let i = 0;
1016
- while (i < lines.length) {
1017
- const line = lines[i];
1018
- const name = assignmentName2(line);
1019
- const eq = line.indexOf("=");
1020
- const valStart = eq >= 0 ? line.slice(eq + 1) : "";
1021
- const block = [line];
1022
- i++;
1023
- if (name && valStart.startsWith('"') && !hasUnescapedQuote2(valStart.slice(1))) {
1024
- while (i < lines.length) {
1025
- block.push(lines[i]);
1026
- const closed = hasUnescapedQuote2(lines[i]);
1027
- i++;
1028
- if (closed) break;
1029
- }
1030
- }
1031
- if (name && !SDK_MANAGED_KEYS.has(name)) target = custom;
1032
- target.push(...block);
1033
- }
1034
- while (top.length && top[top.length - 1] === "") top.pop();
1035
- while (custom.length && custom[custom.length - 1] === "") custom.pop();
1036
- return { top: top.join("\n"), custom: custom.join("\n") };
1037
- }
1038
- function assignmentName2(line) {
1039
- const eq = line.indexOf("=");
1040
- if (eq < 0) return null;
1041
- const match = line.slice(0, eq).match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*$/);
1042
- return match?.[1] ?? null;
1043
- }
1044
- function hasUnescapedQuote2(s) {
1045
- let escaped = false;
1046
- for (const ch of s) {
1047
- if (escaped) {
1048
- escaped = false;
1049
- continue;
1050
- }
1051
- if (ch === "\\") {
1052
- escaped = true;
1053
- continue;
1054
- }
1055
- if (ch === '"') return true;
1056
- }
1057
- return false;
1058
- }
1059
- function rewriteCustomSection(custom, set2, remove2) {
1060
- const lines = custom.split("\n");
1061
- const out = [];
1062
- const pending = new Set(Object.keys(set2));
1063
- let i = 0;
1064
- while (i < lines.length) {
1065
- const line = lines[i];
1066
- const name = assignmentName2(line);
1067
- const eq = line.indexOf("=");
1068
- const valStart = eq >= 0 ? line.slice(eq + 1) : "";
1069
- const block = [line];
1070
- i++;
1071
- if (name && valStart.startsWith('"') && !hasUnescapedQuote2(valStart.slice(1))) {
1072
- while (i < lines.length) {
1073
- block.push(lines[i]);
1074
- const closed = hasUnescapedQuote2(lines[i]);
1075
- i++;
1076
- if (closed) break;
1077
- }
1078
- }
1079
- if (name && (remove2.has(name) || pending.has(name))) {
1080
- if (pending.has(name)) {
1081
- out.push(`${name}=${quote(set2[name])}`);
1082
- pending.delete(name);
1083
- }
1084
- continue;
1085
- }
1086
- out.push(...block);
1087
- }
1088
- while (out.length && out[out.length - 1] === "") out.pop();
1089
- for (const name of Array.from(pending).sort()) {
1090
- out.push(`${name}=${quote(set2[name])}`);
1091
- }
1092
- return out.join("\n");
1093
- }
1094
- function writeDevTargetPatch(set2 = {}, removeNames = []) {
1095
- const path = devTargetPath();
1096
- const existing = existsSync8(path) ? readFileSync7(path, "utf-8") : "";
1097
- const { top, custom: existingCustom } = splitDevTarget(existing);
1098
- const custom = rewriteCustomSection(existingCustom, set2, new Set(removeNames));
1099
- const body = top ? `${top}
1100
-
1101
- ${DEV_VARS_DIVIDER}
1102
- ${custom}${custom ? "\n" : ""}` : `${DEV_VARS_DIVIDER}
1103
- ${custom}${custom ? "\n" : ""}`;
1104
- writeFileSync5(path, body);
1105
- }
1106
- async function remoteDeployState(appName, token2) {
1107
- const res = await fetch(`${process.env.DEEPSPACE_DEPLOY_URL ?? "https://deploy-worker.deep.space"}/api/deploy/${encodeURIComponent(appName)}`, {
1108
- headers: { Authorization: `Bearer ${token2}` }
1109
- });
1110
- const text2 = await res.text().catch(() => "");
1111
- let body = {};
1112
- if (text2) {
1113
- try {
1114
- body = JSON.parse(text2);
1115
- } catch (err) {
1116
- const message = err instanceof Error ? err.message : String(err);
1117
- throw new Error(`Could not determine deploy status for ${appName}: invalid JSON response (${message}).`);
1118
- }
1119
- }
1120
- if (!res.ok) {
1121
- const detail = body.error ?? (text2 || "unknown error");
1122
- throw new Error(`Could not determine deploy status for ${appName} (${res.status}): ${detail}`);
1123
- }
1124
- if (body.deployed === true) return "deployed";
1125
- if (body.deployed === false) return "not-deployed";
1126
- throw new Error(`Could not determine deploy status for ${appName}: response missing "deployed".`);
1127
- }
1128
- async function remoteAvailable(appName, token2) {
1129
- return await remoteDeployState(appName, token2) === "deployed";
1130
- }
1131
- async function mintScopedSecretsToken(appName, token2) {
1132
- const body = await collaboratorFetch(appName, token2, "/secrets-token", { method: "POST" });
1133
- if (!body.token) throw new Error("Platform API did not return an app-secret access token.");
1134
- return body.token;
1135
- }
1136
- async function remoteFetch(appName, token2, path = "", init = {}) {
1137
- const scopedToken = await mintScopedSecretsToken(appName, token2);
1138
- const res = await fetch(`https://${appName}.app.space/_deepspace/secrets${path}`, {
1139
- ...init,
1140
- headers: {
1141
- "Content-Type": "application/json",
1142
- Authorization: `Bearer ${scopedToken}`,
1143
- ...init.headers ?? {}
1144
- }
1145
- });
1146
- const contentType = res.headers.get("content-type") ?? "unknown";
1147
- const text2 = await res.text().catch(() => "");
1148
- let body = null;
1149
- let parseError = null;
1150
- if (text2 && contentType.toLowerCase().includes("json")) {
1151
- try {
1152
- body = JSON.parse(text2);
1153
- } catch (err) {
1154
- parseError = err instanceof Error ? err.message : String(err);
1155
- }
1156
- }
1157
- if (!res.ok) {
1158
- if (body?.error) throw new Error(body.error);
1159
- const snippet = text2 ? ` Body: ${text2.slice(0, ERROR_SNIPPET_CHARS)}` : " Body: <empty>";
1160
- const parseDetail2 = parseError ? ` JSON parse failed: ${parseError}.` : "";
1161
- throw new Error(`Remote secrets request failed (${res.status}; content-type: ${contentType}).${parseDetail2}${snippet}`);
1162
- }
1163
- if (body) return body;
1164
- if (!text2) return {};
1165
- const parseDetail = parseError ? ` JSON parse failed: ${parseError}.` : "";
1166
- throw new Error(`Remote secrets response was not JSON (${res.status}; content-type: ${contentType}).${parseDetail} Body: ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
1167
- }
1168
- function apiUrl() {
1169
- return process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
1170
- }
1171
- async function collaboratorFetch(appName, token2, path, init = {}) {
1172
- const url = `${apiUrl()}/api/app-collaborators/${encodeURIComponent(appName)}${path}`;
1173
- const res = await fetch(url, {
1174
- ...init,
1175
- headers: {
1176
- "Content-Type": "application/json",
1177
- Authorization: `Bearer ${token2}`,
1178
- ...init.headers ?? {}
1179
- }
1180
- });
1181
- const text2 = await res.text().catch(() => "");
1182
- let body = {};
1183
- if (text2) {
1184
- try {
1185
- body = JSON.parse(text2);
1186
- } catch {
1187
- if (res.status === 404) throw new Error(COLLABORATOR_ROUTES_404);
1188
- if (!res.ok) throw new Error(`Collaborator request failed (${res.status}): ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
1189
- throw new Error(`Collaborator response was not JSON (${res.status}): ${text2.slice(0, ERROR_SNIPPET_CHARS)}`);
1190
- }
1191
- }
1192
- if (!res.ok) {
1193
- if (res.status === 404 && (!body.error || body.error === "Not found" || body.error === "not_found")) {
1194
- throw new Error(COLLABORATOR_ROUTES_404);
1195
- }
1196
- if (body.error === "platform_schema_not_migrated") {
1197
- const diagnostic = body;
1198
- const action = typeof diagnostic.action === "string" ? ` ${diagnostic.action}` : "";
1199
- throw new Error(`${COLLABORATOR_SCHEMA_NOT_MIGRATED}${action}`);
1200
- }
1201
- throw new Error(body.error ?? `Collaborator request failed (${res.status})`);
1202
- }
1203
- return body;
1204
- }
1205
- async function requireRemoteSecretsAvailable(appName, token2) {
1206
- const state = await remoteDeployState(appName, token2);
1207
- if (state === "deployed") return;
1208
- throw new Error(
1209
- "Remote secrets are available after the first deploy. Deploy this app first, then run `deepspace secrets push`; `deepspace secrets set --dev` writes dev-only secrets for `deepspace dev` without touching remote."
1210
- );
1211
- }
1212
- function diffMaps(local, remote) {
1213
- const localOnly = [];
1214
- const remoteOnly = [];
1215
- const changed = [];
1216
- const matching = [];
1217
- for (const [name, value] of Object.entries(local)) {
1218
- if (!(name in remote)) localOnly.push(name);
1219
- else if (remote[name] !== value) changed.push(name);
1220
- else matching.push(name);
1221
- }
1222
- for (const name of Object.keys(remote)) {
1223
- if (!(name in local)) remoteOnly.push(name);
1224
- }
1225
- return { localOnly, remoteOnly, changed, matching };
1226
- }
1227
- function diffNames(local, remote) {
1228
- const localSet = new Set(local);
1229
- const remoteSet = new Set(remote);
1230
- return {
1231
- localOnly: local.filter((name) => !remoteSet.has(name)).sort(),
1232
- remoteOnly: remote.filter((name) => !localSet.has(name)).sort()
1233
- };
1234
- }
1235
- function statusLine(d, remote) {
1236
- if (!remote) return "Secrets: remote unavailable until first deploy; dev-only .env section updated.";
1237
- if (!d || !d.localOnly.length && !d.remoteOnly.length && !d.changed.length) {
1238
- return "Secrets: synced .env section matches remote.";
1239
- }
1240
- return `Secrets: ${d.localOnly.length} local-only, ${d.remoteOnly.length} remote-only, ${d.changed.length} changed. Run \`deepspace secrets diff\`.`;
1241
- }
1242
- function nameStatusLine(d) {
1243
- if (!d.localOnly.length && !d.remoteOnly.length) {
1244
- return "Secrets: synced .env section has the same names as remote.";
1245
- }
1246
- return `Secrets: ${d.localOnly.length} local-only, ${d.remoteOnly.length} remote-only. Run \`deepspace secrets diff\` to compare values.`;
1247
- }
1248
- async function compare(appName, token2) {
1249
- if (!await remoteAvailable(appName, token2)) return null;
1250
- const local = readSyncedTarget();
1251
- const remote = await remoteFetch(appName, token2, "/pull");
1252
- return diffMaps(local, remote.secrets ?? {});
1253
- }
1254
- var set = defineCommand3({
1255
- meta: { name: "set", description: "Set an app secret" },
1256
- args: {
1257
- assignment: { type: "positional", required: true, description: "KEY=value" },
1258
- dev: {
1259
- type: "boolean",
1260
- default: false,
1261
- description: "Write only to the dev-only .env section used by `deepspace dev`; never sync to the deployed app"
1262
- }
1263
- },
1264
- async run({ args }) {
1265
- const [name, value] = parseAssignment(String(args.assignment));
1266
- const token2 = await ensureToken();
1267
- const appName = requireAppName(void 0);
1268
- if (args.dev) {
1269
- writeLocalPatch({ [name]: value });
1270
- console.log("Secrets: updated dev-only .env section for `deepspace dev`; remote was not changed.");
1271
- return;
1272
- }
1273
- const state = await remoteDeployState(appName, token2);
1274
- if (state === "not-deployed") {
1275
- writeLocalPatch({ [name]: value });
1276
- console.log("Secrets: app is not deployed; wrote to dev-only .env section. Run `deepspace secrets push` after deploy.");
1277
- return;
1278
- }
1279
- await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ set: { [name]: value } }) });
1280
- if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch({ [name]: value });
1281
- else patchManagedSyncedEnv(process.cwd(), { [name]: value });
1282
- console.log("Secrets: updated remote and synced .env section.");
1283
- }
1284
- });
1285
- var unset = defineCommand3({
1286
- meta: { name: "unset", description: "Remove an app secret" },
1287
- args: {
1288
- name: { type: "positional", required: true, description: "Secret name" },
1289
- dev: {
1290
- type: "boolean",
1291
- default: false,
1292
- description: "Remove only from the dev-only .env section used by `deepspace dev`; never sync to the deployed app"
1293
- }
1294
- },
1295
- async run({ args }) {
1296
- const name = String(args.name);
1297
- if (!SECRET_NAME_RE.test(name)) throw new Error(`Invalid secret name "${name}".`);
1298
- const token2 = await ensureToken();
1299
- const appName = requireAppName(void 0);
1300
- if (args.dev) {
1301
- writeLocalPatch({}, [name]);
1302
- console.log("Secrets: removed from dev-only .env section; remote was not changed.");
1303
- return;
1304
- }
1305
- const state = await remoteDeployState(appName, token2);
1306
- if (state === "not-deployed") {
1307
- writeLocalPatch({}, [name]);
1308
- console.log("Secrets: app is not deployed; removed from dev-only .env section if present.");
1309
- return;
1310
- }
1311
- await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ delete: [name] }) });
1312
- if (hasLegacyDevVars(process.cwd())) writeDevTargetPatch({}, [name]);
1313
- else patchManagedSyncedEnv(process.cwd(), {}, [name]);
1314
- console.log("Secrets: removed from remote and synced .env section.");
1315
- }
1316
- });
1317
- var list = defineCommand3({
1318
- meta: { name: "list", description: "List app secret names and metadata" },
1319
- async run() {
1320
- const token2 = await ensureToken();
1321
- const appName = requireAppName(void 0);
1322
- await requireRemoteSecretsAvailable(appName, token2);
1323
- const body = await remoteFetch(appName, token2);
1324
- for (const item of body.secrets ?? []) console.log(`${item.name} version=${item.version} updated=${item.updatedAt}`);
1325
- const d = diffNames(Object.keys(readSyncedTarget()), (body.secrets ?? []).map((item) => item.name));
1326
- console.log(nameStatusLine(d));
1327
- }
1328
- });
1329
- var pull = defineCommand3({
1330
- meta: { name: "pull", description: "Pull remote app secrets into the synced .env section" },
1331
- async run() {
1332
- const token2 = await ensureToken();
1333
- const appName = requireAppName(void 0);
1334
- await requireRemoteSecretsAvailable(appName, token2);
1335
- const body = await remoteFetch(appName, token2, "/pull");
1336
- const remoteSecrets = body.secrets ?? {};
1337
- if (hasLegacyDevVars(process.cwd())) {
1338
- writeDevTargetPatch(remoteSecrets);
1339
- } else {
1340
- replaceManagedSyncedEnv(process.cwd(), remoteSecrets);
1341
- }
1342
- const count = Object.keys(remoteSecrets).length;
1343
- console.log(`Secrets: pulled ${count} remote secret${count === 1 ? "" : "s"} into synced .env section.`);
1344
- }
1345
- });
1346
- var push = defineCommand3({
1347
- meta: { name: "push", description: "Push dev-only .env secrets to remote and move them to synced" },
1348
- async run() {
1349
- const token2 = await ensureToken();
1350
- const appName = requireAppName(void 0);
1351
- const local = readDevOnlyTarget();
1352
- await requireRemoteSecretsAvailable(appName, token2);
1353
- const names = Object.keys(local);
1354
- if (!names.length) {
1355
- console.log("Secrets: no dev-only .env secrets to push.");
1356
- return;
1357
- }
1358
- await remoteFetch(appName, token2, "", { method: "PATCH", body: JSON.stringify({ set: local }) });
1359
- if (hasLegacyDevVars(process.cwd())) {
1360
- console.log(`Secrets: pushed ${names.length} dev-only secret${names.length === 1 ? "" : "s"} to remote.`);
1361
- } else {
1362
- moveManagedDevOnlyToSynced(process.cwd(), names);
1363
- console.log(`Secrets: pushed ${names.length} dev-only secret${names.length === 1 ? "" : "s"} to remote and moved ${names.length === 1 ? "it" : "them"} to synced .env section.`);
1364
- }
1365
- }
1366
- });
1367
- var diff = defineCommand3({
1368
- meta: { name: "diff", description: "Compare synced .env section with remote app secrets" },
1369
- async run() {
1370
- const token2 = await ensureToken();
1371
- const appName = requireAppName(void 0);
1372
- await requireRemoteSecretsAvailable(appName, token2);
1373
- const d = await compare(appName, token2);
1374
- for (const name of d?.localOnly ?? []) console.log(`local-only ${name}`);
1375
- for (const name of d?.remoteOnly ?? []) console.log(`remote-only ${name}`);
1376
- for (const name of d?.changed ?? []) console.log(`changed ${name}`);
1377
- console.log(statusLine(d, true));
1378
- }
1379
- });
1380
- var collaboratorsList = defineCommand3({
1381
- meta: { name: "list", description: "List app secret collaborators" },
1382
- async run() {
1383
- const token2 = await ensureToken();
1384
- const appName = requireAppName(void 0);
1385
- const body = await collaboratorFetch(appName, token2, "/collaborators");
1386
- for (const item of body.collaborators ?? []) {
1387
- console.log(`${item.emailDisplay} ${item.userId} created=${new Date(item.createdAt).toISOString()}`);
1388
- }
1389
- if (!body.collaborators?.length) console.log("No secrets collaborators.");
1390
- }
1391
- });
1392
- var collaboratorsAdd = defineCommand3({
1393
- meta: { name: "add", description: "Add an existing DeepSpace user as a secrets collaborator" },
1394
- args: {
1395
- email: { type: "positional", required: true, description: "Collaborator email" }
1396
- },
1397
- async run({ args }) {
1398
- const token2 = await ensureToken();
1399
- const appName = requireAppName(void 0);
1400
- const body = await collaboratorFetch(appName, token2, "/collaborators", {
1401
- method: "POST",
1402
- body: JSON.stringify({ email: String(args.email) })
1403
- });
1404
- console.log(`Added ${body.collaborator.emailDisplay} (${body.collaborator.userId}) as a secrets collaborator.`);
1405
- }
1406
- });
1407
- var collaboratorsRemove = defineCommand3({
1408
- meta: { name: "remove", description: "Remove a secrets collaborator" },
1409
- args: {
1410
- target: { type: "positional", required: true, description: "Collaborator email or user id" }
1411
- },
1412
- async run({ args }) {
1413
- const token2 = await ensureToken();
1414
- const appName = requireAppName(void 0);
1415
- const target = String(args.target);
1416
- let userId = target;
1417
- if (target.includes("@")) {
1418
- const body = await collaboratorFetch(appName, token2, "/collaborators");
1419
- const normalized = target.trim().toLowerCase();
1420
- const match = body.collaborators.find((item) => item.emailNormalized === normalized);
1421
- if (!match) throw new Error(`No collaborator found for ${target}.`);
1422
- userId = match.userId;
1423
- }
1424
- await collaboratorFetch(appName, token2, `/collaborators/${encodeURIComponent(userId)}`, { method: "DELETE" });
1425
- console.log(`Removed secrets collaborator ${target}.`);
1426
- }
1427
- });
1428
- var invitesList = defineCommand3({
1429
- meta: { name: "list", description: "List app secret collaborator invites" },
1430
- async run() {
1431
- const token2 = await ensureToken();
1432
- const appName = requireAppName(void 0);
1433
- const body = await collaboratorFetch(appName, token2, "/invites");
1434
- for (const invite of body.invites ?? []) {
1435
- const status2 = invite.revokedAt ? "revoked" : invite.acceptedAt ? "accepted" : new Date(invite.expiresAt).getTime() <= Date.now() ? "expired" : "pending";
1436
- console.log(`${invite.id} ${invite.emailDisplay} status=${status2} expires=${new Date(invite.expiresAt).toISOString()}`);
1437
- }
1438
- if (!body.invites?.length) console.log("No secrets collaborator invites.");
1439
- }
1440
- });
1441
- var invitesRevoke = defineCommand3({
1442
- meta: { name: "revoke", description: "Revoke a pending app secret collaborator invite" },
1443
- args: {
1444
- inviteId: { type: "positional", required: true, description: "Invite id" }
1445
- },
1446
- async run({ args }) {
1447
- const token2 = await ensureToken();
1448
- const appName = requireAppName(void 0);
1449
- await collaboratorFetch(appName, token2, `/invites/${encodeURIComponent(String(args.inviteId))}`, { method: "DELETE" });
1450
- console.log(`Revoked secrets collaborator invite ${String(args.inviteId)}.`);
1451
- }
1452
- });
1453
- var invites = defineCommand3({
1454
- meta: { name: "invites", description: "Manage app secret collaborator invites" },
1455
- subCommands: { list: invitesList, revoke: invitesRevoke }
1456
- });
1457
- var collaborators = defineCommand3({
1458
- meta: { name: "collaborators", description: "Manage app secret collaborators" },
1459
- subCommands: { list: collaboratorsList, add: collaboratorsAdd, remove: collaboratorsRemove, invites }
1460
- });
1461
- var secrets_default = defineCommand3({
1462
- meta: { name: "secrets", description: "Manage app-owned DeepSpace secrets" },
1463
- subCommands: { set, unset, list, pull, push, diff, collaborators }
1464
- });
1465
-
1466
749
  // src/cli/commands/dev.ts
1467
750
  var DEFAULT_PORT = 5173;
1468
- var dev_default = defineCommand4({
751
+ var dev_default = defineCommand3({
1469
752
  meta: {
1470
753
  name: "dev",
1471
754
  description: "Start local development server"
@@ -1483,18 +766,13 @@ var dev_default = defineCommand4({
1483
766
  },
1484
767
  env: {
1485
768
  type: "string",
1486
- description: "wrangler.toml [env.<name>] block to run (e.g. --env staging). Legacy apps read .dev.vars.<name>; new apps use managed .env.",
769
+ description: "wrangler.toml [env.<name>] block to run (e.g. --env staging). Reads .dev.vars.<name> and applies the env's overrides at build time.",
1487
770
  required: false
1488
771
  },
1489
772
  port: {
1490
773
  type: "string",
1491
774
  description: `Port to bind (default ${DEFAULT_PORT}, or $DEEPSPACE_PORT)`,
1492
775
  required: false
1493
- },
1494
- "no-pull-env": {
1495
- type: "boolean",
1496
- description: "Skip pulling remote app secrets into the synced .env section on startup",
1497
- default: false
1498
776
  }
1499
777
  },
1500
778
  async run({ args }) {
@@ -1516,40 +794,25 @@ var dev_default = defineCommand4({
1516
794
  }
1517
795
  writeLaunchConfigIfMissing(appDir, detectAppName(appDir) ?? basename(appDir), port);
1518
796
  ensureInstallReady(appDir);
1519
- let token2;
797
+ let token;
1520
798
  try {
1521
- token2 = await ensureToken();
799
+ token = await ensureToken();
1522
800
  } catch (err) {
1523
801
  console.error(err.message);
1524
802
  process.exit(1);
1525
803
  }
1526
804
  let payload;
1527
805
  try {
1528
- payload = decodeJwtPayload(token2);
806
+ payload = decodeJwtPayload(token);
1529
807
  } catch {
1530
808
  console.error("Malformed session token. Run `npx deepspace login`.");
1531
809
  process.exit(1);
1532
810
  }
1533
- console.log(`Logged in as ${payload.name ?? payload.email}`);
1534
- console.log(`Platform: ${env}`);
1535
- if (wranglerEnv) console.log(`Wrangler env: ${wranglerEnv}`);
1536
- console.log(`Port: ${port}`);
1537
- await writeDevVars(appDir, env, payload.sub, token2, wranglerEnv);
1538
- if (env === "dev" && !args["no-pull-env"] && !hasLegacyDevVars(appDir, wranglerEnv)) {
1539
- const appName = resolveCurrentAppName(appDir, wranglerEnv);
1540
- if (appName) {
1541
- try {
1542
- if (await remoteAvailable(appName, token2)) {
1543
- const body = await remoteFetch(appName, token2, "/pull");
1544
- replaceManagedSyncedEnv(appDir, body.secrets ?? {});
1545
- console.log("Secrets: pulled remote app secrets into synced .env section.");
1546
- }
1547
- } catch (err) {
1548
- const message = err instanceof Error ? err.message : String(err);
1549
- console.warn(`Secrets: remote app secrets pull skipped (${message}).`);
1550
- }
1551
- }
1552
- }
811
+ console.log(`Logged in as ${payload.name ?? payload.email}`);
812
+ console.log(`Platform: ${env}`);
813
+ if (wranglerEnv) console.log(`Wrangler env: ${wranglerEnv}`);
814
+ console.log(`Port: ${port}`);
815
+ await writeDevVars(appDir, env, payload.sub, token, wranglerEnv);
1553
816
  preflightWindowsWorkerd(appDir);
1554
817
  console.log("Starting dev server...\n");
1555
818
  const vite = spawn(
@@ -1559,10 +822,9 @@ var dev_default = defineCommand4({
1559
822
  cwd: appDir,
1560
823
  stdio: "inherit",
1561
824
  // CLOUDFLARE_ENV is what the Cloudflare Vite plugin keys off — it
1562
- // applies `[env.<name>]` overrides. Legacy .dev.vars apps use
1563
- // `.dev.vars.<name>` instead of `.dev.vars`; new apps use managed .env.
1564
- // Set only when --env was passed so the default invocation behaves
1565
- // exactly as before.
825
+ // applies `[env.<name>]` overrides and loads `.dev.vars.<name>`
826
+ // instead of `.dev.vars`. Set only when --env was passed so the
827
+ // default invocation behaves exactly as before.
1566
828
  env: {
1567
829
  ...process.env,
1568
830
  DEEPSPACE_PORT: String(port),
@@ -1585,23 +847,15 @@ function resolvePort(arg) {
1585
847
  }
1586
848
  return n;
1587
849
  }
1588
- function resolveCurrentAppName(appDir, wranglerEnv) {
1589
- try {
1590
- const resolved = resolveAppNameForEnv(readWranglerConfig(appDir), wranglerEnv);
1591
- return resolved.ok ? resolved.name : null;
1592
- } catch {
1593
- return null;
1594
- }
1595
- }
1596
850
 
1597
851
  // src/cli/commands/kill.ts
1598
- import { defineCommand as defineCommand5 } from "citty";
852
+ import { defineCommand as defineCommand4 } from "citty";
1599
853
  import { spawnSync } from "child_process";
1600
854
  import { setTimeout as wait } from "timers/promises";
1601
855
  var DEFAULT_PORT2 = 5173;
1602
856
  var SIGTERM_GRACE_MS = 1500;
1603
857
  var IS_WIN = process.platform === "win32";
1604
- var kill_default = defineCommand5({
858
+ var kill_default = defineCommand4({
1605
859
  meta: {
1606
860
  name: "kill",
1607
861
  description: "Kill the local dev server and any orphaned workerd processes"
@@ -1756,7 +1010,7 @@ function isAlive(pid) {
1756
1010
  }
1757
1011
 
1758
1012
  // src/cli/commands/test.ts
1759
- import { defineCommand as defineCommand6 } from "citty";
1013
+ import { defineCommand as defineCommand5 } from "citty";
1760
1014
  import { resolve as resolve4 } from "path";
1761
1015
  import { sync as spawnSync3 } from "cross-spawn";
1762
1016
 
@@ -1786,7 +1040,7 @@ function ensurePlaywright(appDir) {
1786
1040
 
1787
1041
  // src/cli/commands/test.ts
1788
1042
  var DEFAULT_PORT3 = 5173;
1789
- var test_default = defineCommand6({
1043
+ var test_default = defineCommand5({
1790
1044
  meta: {
1791
1045
  name: "test",
1792
1046
  description: "Run tests for your DeepSpace app"
@@ -1820,17 +1074,17 @@ var test_default = defineCommand6({
1820
1074
  process.exit(1);
1821
1075
  }
1822
1076
  ensureInstallReady(appDir);
1823
- let token2;
1077
+ let token;
1824
1078
  let ownerId;
1825
1079
  try {
1826
- token2 = await ensureToken();
1827
- const payload = decodeJwtPayload(token2);
1080
+ token = await ensureToken();
1081
+ const payload = decodeJwtPayload(token);
1828
1082
  ownerId = payload.sub;
1829
1083
  } catch (err) {
1830
1084
  console.error("`deepspace test` requires you to be logged in. Run `deepspace login` first.");
1831
1085
  process.exit(1);
1832
1086
  }
1833
- await writeDevVars(appDir, "dev", ownerId, token2);
1087
+ await writeDevVars(appDir, "dev", ownerId, token);
1834
1088
  if (suite !== "unit") {
1835
1089
  preflightWindowsWorkerd(appDir);
1836
1090
  ensurePlaywright(appDir);
@@ -1901,10 +1155,10 @@ function resolvePort3(arg) {
1901
1155
  }
1902
1156
 
1903
1157
  // src/cli/commands/screenshot.ts
1904
- import { defineCommand as defineCommand7 } from "citty";
1158
+ import { defineCommand as defineCommand6 } from "citty";
1905
1159
  import { sync as spawnSync4 } from "cross-spawn";
1906
1160
  import { resolve as resolve5 } from "path";
1907
- var screenshot_default = defineCommand7({
1161
+ var screenshot_default = defineCommand6({
1908
1162
  meta: {
1909
1163
  name: "screenshot",
1910
1164
  description: "Take a Playwright screenshot, installing Chromium on demand"
@@ -1948,30 +1202,30 @@ var screenshot_default = defineCommand7({
1948
1202
  });
1949
1203
 
1950
1204
  // src/cli/commands/test-accounts.ts
1951
- import { defineCommand as defineCommand8 } from "citty";
1205
+ import { defineCommand as defineCommand7 } from "citty";
1952
1206
  import * as p3 from "@clack/prompts";
1953
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
1954
- import { join as join9 } from "path";
1207
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
1208
+ import { join as join8 } from "path";
1955
1209
  import { homedir as homedir4 } from "os";
1956
1210
  var SESSION_COOKIE2 = "__Secure-better-auth.session_token";
1957
1211
  var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
1958
- var DIR3 = join9(homedir4(), ".deepspace");
1959
- var ACCOUNTS_PATH = join9(DIR3, "test-accounts.json");
1212
+ var DIR3 = join8(homedir4(), ".deepspace");
1213
+ var ACCOUNTS_PATH = join8(DIR3, "test-accounts.json");
1960
1214
  function loadAccounts() {
1961
- if (!existsSync9(ACCOUNTS_PATH)) return [];
1215
+ if (!existsSync8(ACCOUNTS_PATH)) return [];
1962
1216
  try {
1963
- return JSON.parse(readFileSync8(ACCOUNTS_PATH, "utf-8"));
1217
+ return JSON.parse(readFileSync7(ACCOUNTS_PATH, "utf-8"));
1964
1218
  } catch {
1965
1219
  return [];
1966
1220
  }
1967
1221
  }
1968
1222
  function saveAccounts(accounts) {
1969
1223
  mkdirSync4(DIR3, { recursive: true });
1970
- writeFileSync6(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
1224
+ writeFileSync5(ACCOUNTS_PATH, JSON.stringify(accounts, null, 2), { mode: 384 });
1971
1225
  }
1972
1226
  function sessionCookie() {
1973
- const token2 = readFileSync8(SESSION_PATH2, "utf-8").trim();
1974
- return `${SESSION_COOKIE2}=${encodeURIComponent(token2)}`;
1227
+ const token = readFileSync7(SESSION_PATH2, "utf-8").trim();
1228
+ return `${SESSION_COOKIE2}=${encodeURIComponent(token)}`;
1975
1229
  }
1976
1230
  async function fetchRemoteAccounts() {
1977
1231
  const res = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
@@ -1993,7 +1247,7 @@ async function deleteRemote(id) {
1993
1247
  throw new Error(data.error ?? `DELETE returned ${res.status}`);
1994
1248
  }
1995
1249
  }
1996
- var create = defineCommand8({
1250
+ var create = defineCommand7({
1997
1251
  meta: {
1998
1252
  name: "create",
1999
1253
  description: "Create a test account"
@@ -2063,7 +1317,7 @@ var create = defineCommand8({
2063
1317
  Saved to ${ACCOUNTS_PATH}`);
2064
1318
  }
2065
1319
  });
2066
- var list2 = defineCommand8({
1320
+ var list = defineCommand7({
2067
1321
  meta: {
2068
1322
  name: "list",
2069
1323
  description: "List your test accounts"
@@ -2098,7 +1352,7 @@ var list2 = defineCommand8({
2098
1352
  }
2099
1353
  }
2100
1354
  });
2101
- var del = defineCommand8({
1355
+ var del = defineCommand7({
2102
1356
  meta: {
2103
1357
  name: "delete",
2104
1358
  description: "Delete a test account by --email or --id"
@@ -2155,7 +1409,7 @@ var del = defineCommand8({
2155
1409
  console.log(`Test account deleted${targetEmail ? `: ${targetEmail}` : `: ${targetId}`}`);
2156
1410
  }
2157
1411
  });
2158
- var clear = defineCommand8({
1412
+ var clear = defineCommand7({
2159
1413
  meta: {
2160
1414
  name: "clear",
2161
1415
  description: "Delete all your test accounts (or those matching --label)"
@@ -2221,25 +1475,25 @@ Failed:`);
2221
1475
  }
2222
1476
  }
2223
1477
  });
2224
- var test_accounts_default = defineCommand8({
1478
+ var test_accounts_default = defineCommand7({
2225
1479
  meta: {
2226
1480
  name: "test-accounts",
2227
1481
  description: "Manage test accounts for development"
2228
1482
  },
2229
1483
  subCommands: {
2230
1484
  create,
2231
- list: list2,
1485
+ list,
2232
1486
  delete: del,
2233
1487
  clear
2234
1488
  }
2235
1489
  });
2236
1490
 
2237
1491
  // src/cli/commands/deploy.ts
2238
- import { defineCommand as defineCommand9 } from "citty";
1492
+ import { defineCommand as defineCommand8 } from "citty";
2239
1493
  import { execSync as execSync2 } from "child_process";
2240
1494
  import { randomUUID } from "crypto";
2241
- import { readFileSync as readFileSync9, readdirSync as readdirSync2, existsSync as existsSync10 } from "fs";
2242
- import { join as join10, resolve as resolve6, dirname as dirname2 } from "path";
1495
+ import { readFileSync as readFileSync8, readdirSync as readdirSync2, existsSync as existsSync9 } from "fs";
1496
+ import { join as join9, resolve as resolve6, dirname as dirname2 } from "path";
2243
1497
  import { pathToFileURL } from "url";
2244
1498
  import * as p4 from "@clack/prompts";
2245
1499
 
@@ -2268,7 +1522,6 @@ var RESERVED_BINDING_NAMES = /* @__PURE__ */ new Set([
2268
1522
  "AUTH_WORKER_URL",
2269
1523
  "APP_IDENTITY_TOKEN",
2270
1524
  "APP_OWNER_JWT",
2271
- "APP_SECRETS_KEY",
2272
1525
  "USAGE_EVENTS"
2273
1526
  ]);
2274
1527
  function validateBindingManifest(manifest) {
@@ -2449,7 +1702,6 @@ function asObjectArray(v) {
2449
1702
  // src/cli/commands/deploy.ts
2450
1703
  var DEPLOY_URL = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
2451
1704
  var API_URL = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
2452
- var SECRET_NAME_RE2 = /^[A-Za-z_][A-Za-z0-9_]*$/;
2453
1705
  var CLOUDFLARE_DEPLOY_ERROR_HINT = "Deployment reached the DeepSpace deploy worker, but Cloudflare's deployment control-plane API failed. This is often caused by a Cloudflare Dashboard/API incident or Workers for Platforms entitlement outage. Already deployed apps should keep serving; wait for Cloudflare to recover and retry.";
2454
1706
  var RESERVED_RUN_WORKER_FIRST = /* @__PURE__ */ new Set([
2455
1707
  "/api/*",
@@ -2492,14 +1744,6 @@ function formatDeployWorkerError(status2, error) {
2492
1744
 
2493
1745
  Underlying error: ${detail}`;
2494
1746
  }
2495
- function legacyDevVarsAppSecretsRoomWarning(userSecrets, doManifest) {
2496
- if (!Object.keys(userSecrets).length) return null;
2497
- const hasAppSecretsRoom = (doManifest ?? []).some(
2498
- (binding) => binding.binding === "SECRETS_ROOMS" || binding.className === "AppSecretsRoom"
2499
- );
2500
- if (!hasAppSecretsRoom) return null;
2501
- return "Legacy .dev.vars secrets are still being deployed as direct Worker bindings even though AppSecretsRoom is configured. Move these values with `deepspace secrets set` to manage them through the app secrets store.";
2502
- }
2503
1747
  var MAX_GROUP_BYTES = 40 * 1024 * 1024;
2504
1748
  var GROUP_BYTES = (() => {
2505
1749
  const raw = Number(process.env.DEEPSPACE_DEPLOY_GROUP_BYTES);
@@ -2544,16 +1788,16 @@ async function postWithRetry(url, makeInit, { attempts = 4, retryServerErrors =
2544
1788
  if (lastRes) return lastRes;
2545
1789
  throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
2546
1790
  }
2547
- async function abortStagedUpload(appName, uploadId, totalGroups, token2) {
1791
+ async function abortStagedUpload(appName, uploadId, totalGroups, token) {
2548
1792
  try {
2549
1793
  await fetch(
2550
1794
  `${DEPLOY_URL}/api/deploy/${appName}/assets?uploadId=${uploadId}&totalGroups=${totalGroups}`,
2551
- { method: "DELETE", headers: { Authorization: `Bearer ${token2}` } }
1795
+ { method: "DELETE", headers: { Authorization: `Bearer ${token}` } }
2552
1796
  );
2553
1797
  } catch {
2554
1798
  }
2555
1799
  }
2556
- var deploy_default = defineCommand9({
1800
+ var deploy_default = defineCommand8({
2557
1801
  meta: {
2558
1802
  name: "deploy",
2559
1803
  description: "Build and deploy your DeepSpace app"
@@ -2595,9 +1839,9 @@ var deploy_default = defineCommand9({
2595
1839
  }
2596
1840
  const appName = nameRes.name;
2597
1841
  p4.log.info(envName ? `App: ${appName} (env: ${envName})` : `App: ${appName}`);
2598
- let token2;
1842
+ let token;
2599
1843
  try {
2600
- token2 = await ensureToken();
1844
+ token = await ensureToken();
2601
1845
  } catch (err) {
2602
1846
  p4.cancel(err.message);
2603
1847
  process.exit(1);
@@ -2617,18 +1861,18 @@ var deploy_default = defineCommand9({
2617
1861
  process.exit(1);
2618
1862
  }
2619
1863
  s.stop("Built");
2620
- const deployConfigPath = join10(appDir, ".wrangler", "deploy", "config.json");
2621
- if (!existsSync10(deployConfigPath)) {
1864
+ const deployConfigPath = join9(appDir, ".wrangler", "deploy", "config.json");
1865
+ if (!existsSync9(deployConfigPath)) {
2622
1866
  p4.cancel("Build output config not found at .wrangler/deploy/config.json");
2623
1867
  process.exit(1);
2624
1868
  }
2625
- const deployConfig = JSON.parse(readFileSync9(deployConfigPath, "utf-8"));
1869
+ const deployConfig = JSON.parse(readFileSync8(deployConfigPath, "utf-8"));
2626
1870
  const outputWranglerPath = resolve6(dirname2(deployConfigPath), deployConfig.configPath);
2627
- if (!existsSync10(outputWranglerPath)) {
1871
+ if (!existsSync9(outputWranglerPath)) {
2628
1872
  p4.cancel(`Output wrangler.json not found at ${outputWranglerPath}`);
2629
1873
  process.exit(1);
2630
1874
  }
2631
- const outputConfig = JSON.parse(readFileSync9(outputWranglerPath, "utf-8"));
1875
+ const outputConfig = JSON.parse(readFileSync8(outputWranglerPath, "utf-8"));
2632
1876
  if (outputConfig.name && outputConfig.name !== appName) {
2633
1877
  const envHint = envName ? ` (--env ${envName})` : "";
2634
1878
  p4.cancel(
@@ -2637,20 +1881,20 @@ var deploy_default = defineCommand9({
2637
1881
  process.exit(1);
2638
1882
  }
2639
1883
  const workerDir = dirname2(outputWranglerPath);
2640
- const workerBundlePath = join10(workerDir, outputConfig.main);
1884
+ const workerBundlePath = join9(workerDir, outputConfig.main);
2641
1885
  const clientDir = outputConfig.assets?.directory ? resolve6(workerDir, outputConfig.assets.directory) : null;
2642
- if (!existsSync10(workerBundlePath)) {
1886
+ if (!existsSync9(workerBundlePath)) {
2643
1887
  p4.cancel(`Worker bundle not found at ${workerBundlePath}`);
2644
1888
  process.exit(1);
2645
1889
  }
2646
- if (!clientDir || !existsSync10(clientDir)) {
1890
+ if (!clientDir || !existsSync9(clientDir)) {
2647
1891
  p4.cancel(`Client assets not found at ${clientDir}`);
2648
1892
  process.exit(1);
2649
1893
  }
2650
1894
  s.start("Collecting assets...");
2651
1895
  const assets = collectAssets(clientDir);
2652
1896
  s.stop(`Collected ${assets.length} assets`);
2653
- const workerJs = readFileSync9(workerBundlePath, "utf-8");
1897
+ const workerJs = readFileSync8(workerBundlePath, "utf-8");
2654
1898
  const doBindings = outputConfig.durable_objects?.bindings;
2655
1899
  const sqliteClasses = new Set(
2656
1900
  outputConfig.migrations?.flatMap((m) => m.new_sqlite_classes ?? []) ?? []
@@ -2677,20 +1921,40 @@ var deploy_default = defineCommand9({
2677
1921
  `Custom bindings: ${customBindings.map((b) => `${b.name} (${b.type})`).join(", ")}`
2678
1922
  );
2679
1923
  }
1924
+ const devVarsPath = devVarsPathFor(appDir, envName);
2680
1925
  let userSecrets = {};
2681
- if (hasLegacyDevVars(appDir, envName)) {
2682
- try {
2683
- userSecrets = readLegacyUserSecrets(appDir, envName, customBindings, doManifest);
2684
- } catch (err) {
2685
- const message = err instanceof Error ? err.message : String(err);
2686
- p4.cancel(message);
1926
+ if (existsSync9(devVarsPath)) {
1927
+ const customSection = extractCustomDevVars(readFileSync8(devVarsPath, "utf-8"));
1928
+ if (customSection) {
1929
+ try {
1930
+ userSecrets = parseDevVars(customSection);
1931
+ } catch (err) {
1932
+ p4.cancel(`.dev.vars: ${err.message}`);
1933
+ process.exit(1);
1934
+ }
1935
+ }
1936
+ }
1937
+ const userSecretNames = Object.keys(userSecrets);
1938
+ const declaredBindingNames = /* @__PURE__ */ new Set([
1939
+ ...customBindings.map((b) => b.name),
1940
+ ...(doManifest ?? []).map((d) => d.binding)
1941
+ ]);
1942
+ for (const name of userSecretNames) {
1943
+ if (RESERVED_BINDING_NAMES.has(name)) {
1944
+ p4.cancel(
1945
+ `.dev.vars: "${name}" is a reserved binding name and cannot be used as an app secret.`
1946
+ );
1947
+ process.exit(1);
1948
+ }
1949
+ if (declaredBindingNames.has(name)) {
1950
+ p4.cancel(
1951
+ `.dev.vars: "${name}" collides with a binding declared in wrangler.toml \u2014 rename one or the other.`
1952
+ );
2687
1953
  process.exit(1);
2688
1954
  }
2689
1955
  }
2690
- if (Object.keys(userSecrets).length) {
2691
- p4.log.info(`Legacy .dev.vars secrets: ${Object.keys(userSecrets).sort().join(", ")}`);
2692
- const warning = legacyDevVarsAppSecretsRoomWarning(userSecrets, doManifest);
2693
- if (warning) p4.log.warn(warning);
1956
+ if (userSecretNames.length) {
1957
+ p4.log.info(`App secrets (from .dev.vars): ${userSecretNames.join(", ")}`);
2694
1958
  }
2695
1959
  s.start(`Deploying to ${appName}.app.space...`);
2696
1960
  const extraRoutes = extractRunWorkerFirst(wranglerConfig);
@@ -2715,7 +1979,7 @@ var deploy_default = defineCommand9({
2715
1979
  () => ({
2716
1980
  method: "POST",
2717
1981
  headers: {
2718
- Authorization: `Bearer ${token2}`,
1982
+ Authorization: `Bearer ${token}`,
2719
1983
  "Content-Type": "application/json"
2720
1984
  },
2721
1985
  body: groupJson
@@ -2723,7 +1987,7 @@ var deploy_default = defineCommand9({
2723
1987
  );
2724
1988
  if (!groupRes.ok) {
2725
1989
  const errBody = await groupRes.json().catch(() => ({}));
2726
- await abortStagedUpload(appName, uploadId, totalGroups, token2);
1990
+ await abortStagedUpload(appName, uploadId, totalGroups, token);
2727
1991
  s.stop("Deploy failed");
2728
1992
  p4.cancel(
2729
1993
  `Asset upload failed on group ${i + 1}/${totalGroups}: ${errBody.error ?? `HTTP ${groupRes.status}`}`
@@ -2732,7 +1996,7 @@ var deploy_default = defineCommand9({
2732
1996
  }
2733
1997
  }
2734
1998
  } catch (err) {
2735
- await abortStagedUpload(appName, uploadId, totalGroups, token2);
1999
+ await abortStagedUpload(appName, uploadId, totalGroups, token);
2736
2000
  s.stop("Deploy failed");
2737
2001
  p4.cancel(`Asset upload failed (network): ${err?.message ?? err}`);
2738
2002
  process.exit(1);
@@ -2754,12 +2018,12 @@ var deploy_default = defineCommand9({
2754
2018
  if (customBindings.length) {
2755
2019
  form.append("bindingManifest", JSON.stringify(customBindings));
2756
2020
  }
2021
+ if (userSecretNames.length) {
2022
+ form.append("userSecrets", JSON.stringify(userSecrets));
2023
+ }
2757
2024
  if (extraRoutes.length) {
2758
2025
  form.append("extraRunWorkerFirst", JSON.stringify(extraRoutes));
2759
2026
  }
2760
- if (Object.keys(userSecrets).length) {
2761
- form.append("userSecrets", JSON.stringify(userSecrets));
2762
- }
2763
2027
  return form;
2764
2028
  };
2765
2029
  let res;
@@ -2768,7 +2032,7 @@ var deploy_default = defineCommand9({
2768
2032
  `${DEPLOY_URL}/api/deploy/${appName}`,
2769
2033
  () => ({
2770
2034
  method: "POST",
2771
- headers: { Authorization: `Bearer ${token2}` },
2035
+ headers: { Authorization: `Bearer ${token}` },
2772
2036
  body: makeForm()
2773
2037
  }),
2774
2038
  // Commit runs a real deploy — don't retry its 5xx (could double-deploy);
@@ -2777,14 +2041,14 @@ var deploy_default = defineCommand9({
2777
2041
  { retryServerErrors: false }
2778
2042
  );
2779
2043
  } catch (err) {
2780
- if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token2);
2044
+ if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token);
2781
2045
  s.stop("Deploy failed");
2782
2046
  p4.cancel(`Deploy request failed: ${err?.message ?? err}`);
2783
2047
  process.exit(1);
2784
2048
  }
2785
2049
  const body = await res.json().catch(() => ({}));
2786
2050
  if (!res.ok || !body.success) {
2787
- if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token2);
2051
+ if (uploadId) await abortStagedUpload(appName, uploadId, totalGroups, token);
2788
2052
  s.stop("Deploy failed");
2789
2053
  p4.cancel(formatDeployWorkerError(res.status, body.error));
2790
2054
  process.exit(1);
@@ -2796,52 +2060,29 @@ var deploy_default = defineCommand9({
2796
2060
  s.stop("Deployed (edge propagation still in progress after 90s)");
2797
2061
  p4.log.warn("First requests may briefly hit the assets transitional page; retry in a minute.");
2798
2062
  p4.log.success(`Live at: ${body.url}`);
2799
- p4.log.info("Secrets: local dev-only values are not pushed automatically. Run `deepspace secrets push` when you want to sync them.");
2800
- await syncSubscriptionPlans(appDir, appName, token2);
2801
- await syncOneTimeProducts(appDir, appName, token2);
2063
+ await syncSubscriptionPlans(appDir, appName, token);
2064
+ await syncOneTimeProducts(appDir, appName, token);
2802
2065
  p4.outro("Done");
2803
2066
  return;
2804
2067
  }
2805
2068
  }
2806
2069
  s.stop("Deployed!");
2807
2070
  p4.log.success(`Live at: ${body.url}`);
2808
- p4.log.info("Secrets: local dev-only values are not pushed automatically. Run `deepspace secrets push` when you want to sync them.");
2809
- await syncSubscriptionPlans(appDir, appName, token2);
2810
- await syncOneTimeProducts(appDir, appName, token2);
2071
+ await syncSubscriptionPlans(appDir, appName, token);
2072
+ await syncOneTimeProducts(appDir, appName, token);
2811
2073
  p4.outro("Done");
2812
2074
  }
2813
2075
  });
2814
- function readLegacyUserSecrets(appDir, wranglerEnv, customBindings, doManifest) {
2815
- const path = join10(appDir, wranglerEnv ? `.dev.vars.${wranglerEnv}` : ".dev.vars");
2816
- if (!existsSync10(path)) return {};
2817
- const vars = parseDevVars(extractCustomDevVars(readFileSync9(path, "utf-8")));
2818
- const reserved = /* @__PURE__ */ new Set([
2819
- ...SDK_MANAGED_KEYS,
2820
- ...customBindings.map((b) => b.name),
2821
- ...(doManifest ?? []).flatMap((b) => [b.binding, b.className])
2822
- ]);
2823
- const out = {};
2824
- for (const [name, value] of Object.entries(vars)) {
2825
- if (!SECRET_NAME_RE2.test(name)) {
2826
- throw new Error(`.dev.vars: invalid secret name "${name}".`);
2827
- }
2828
- if (reserved.has(name)) {
2829
- throw new Error(`.dev.vars: "${name}" is reserved and cannot be deployed as a user secret.`);
2830
- }
2831
- out[name] = value;
2832
- }
2833
- return out;
2834
- }
2835
- async function syncSubscriptionPlans(appDir, appName, token2) {
2836
- const subsPath = join10(appDir, "src", "subscriptions.ts");
2837
- if (!existsSync10(subsPath)) return;
2076
+ async function syncSubscriptionPlans(appDir, appName, token) {
2077
+ const subsPath = join9(appDir, "src", "subscriptions.ts");
2078
+ if (!existsSync9(subsPath)) return;
2838
2079
  const s = createSpinner();
2839
2080
  s.start("Syncing subscription plans...");
2840
2081
  let plans;
2841
2082
  try {
2842
2083
  const esbuild = await import("esbuild");
2843
- const outDir = join10(appDir, ".wrangler", "deploy");
2844
- const outFile = join10(outDir, "subscriptions.bundle.mjs");
2084
+ const outDir = join9(appDir, ".wrangler", "deploy");
2085
+ const outFile = join9(outDir, "subscriptions.bundle.mjs");
2845
2086
  await esbuild.build({
2846
2087
  entryPoints: [subsPath],
2847
2088
  bundle: true,
@@ -2871,7 +2112,7 @@ async function syncSubscriptionPlans(appDir, appName, token2) {
2871
2112
  res = await fetch(`${API_URL}/api/subscriptions/sync`, {
2872
2113
  method: "POST",
2873
2114
  headers: {
2874
- Authorization: `Bearer ${token2}`,
2115
+ Authorization: `Bearer ${token}`,
2875
2116
  "Content-Type": "application/json"
2876
2117
  },
2877
2118
  body: JSON.stringify({ appName, plans })
@@ -2891,7 +2132,7 @@ async function syncSubscriptionPlans(appDir, appName, token2) {
2891
2132
  }
2892
2133
  const changes = (body.planChanges ?? []).filter((c) => c.affectedSubscribers > 0);
2893
2134
  if (changes.length > 0) {
2894
- await promptAndCancelChangedPlans(appName, token2, changes);
2135
+ await promptAndCancelChangedPlans(appName, token, changes);
2895
2136
  }
2896
2137
  return;
2897
2138
  }
@@ -2912,7 +2153,7 @@ function summaryLine(c) {
2912
2153
  const diffs = (c.intervals ?? []).map((i) => `${i.interval}: ${formatCents(i.oldCents)} \u2192 ${formatCents(i.newCents)}`).join("; ");
2913
2154
  return ` \u2022 ${c.slug} \u2014 repriced (${diffs}; ${suffix} grandfathered on old price)`;
2914
2155
  }
2915
- async function promptAndCancelChangedPlans(appName, token2, changes) {
2156
+ async function promptAndCancelChangedPlans(appName, token, changes) {
2916
2157
  const summary = changes.map(summaryLine).join("\n");
2917
2158
  p4.log.warn(
2918
2159
  `Plan change${changes.length === 1 ? "" : "s"} from this deploy left subscribers stranded:
@@ -2943,7 +2184,7 @@ current billing period? (Skip to leave them grandfathered.)`
2943
2184
  const res = await fetch(`${API_URL}/api/subscriptions/admin-cancel`, {
2944
2185
  method: "POST",
2945
2186
  headers: {
2946
- Authorization: `Bearer ${token2}`,
2187
+ Authorization: `Bearer ${token}`,
2947
2188
  "Content-Type": "application/json"
2948
2189
  },
2949
2190
  body: JSON.stringify({
@@ -2981,16 +2222,16 @@ current billing period? (Skip to leave them grandfathered.)`
2981
2222
  }
2982
2223
  }
2983
2224
  }
2984
- async function syncOneTimeProducts(appDir, appName, token2) {
2985
- const productsPath = join10(appDir, "src", "products.ts");
2986
- if (!existsSync10(productsPath)) return;
2225
+ async function syncOneTimeProducts(appDir, appName, token) {
2226
+ const productsPath = join9(appDir, "src", "products.ts");
2227
+ if (!existsSync9(productsPath)) return;
2987
2228
  const s = createSpinner();
2988
2229
  s.start("Syncing one-time products...");
2989
2230
  let products;
2990
2231
  try {
2991
2232
  const esbuild = await import("esbuild");
2992
- const outDir = join10(appDir, ".wrangler", "deploy");
2993
- const outFile = join10(outDir, "products.bundle.mjs");
2233
+ const outDir = join9(appDir, ".wrangler", "deploy");
2234
+ const outFile = join9(outDir, "products.bundle.mjs");
2994
2235
  await esbuild.build({
2995
2236
  entryPoints: [productsPath],
2996
2237
  bundle: true,
@@ -3020,7 +2261,7 @@ async function syncOneTimeProducts(appDir, appName, token2) {
3020
2261
  res = await fetch(`${API_URL}/api/charges/products/sync`, {
3021
2262
  method: "POST",
3022
2263
  headers: {
3023
- Authorization: `Bearer ${token2}`,
2264
+ Authorization: `Bearer ${token}`,
3024
2265
  "Content-Type": "application/json"
3025
2266
  },
3026
2267
  body: JSON.stringify({ appName, products })
@@ -3064,14 +2305,14 @@ function collectAssets(dir) {
3064
2305
  function walk(d, prefix) {
3065
2306
  for (const entry of readdirSync2(d, { withFileTypes: true })) {
3066
2307
  if (entry.name === ".assetsignore") continue;
3067
- const full = join10(d, entry.name);
2308
+ const full = join9(d, entry.name);
3068
2309
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
3069
2310
  if (entry.isDirectory()) {
3070
2311
  walk(full, rel);
3071
2312
  } else {
3072
2313
  assets.push({
3073
2314
  path: "/" + rel,
3074
- contentBase64: readFileSync9(full).toString("base64")
2315
+ contentBase64: readFileSync8(full).toString("base64")
3075
2316
  });
3076
2317
  }
3077
2318
  }
@@ -3081,10 +2322,10 @@ function collectAssets(dir) {
3081
2322
  }
3082
2323
 
3083
2324
  // src/cli/commands/undeploy.ts
3084
- import { defineCommand as defineCommand10 } from "citty";
2325
+ import { defineCommand as defineCommand9 } from "citty";
3085
2326
  import * as p5 from "@clack/prompts";
3086
2327
  var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? ENVS.prod.deploy;
3087
- var undeploy_default = defineCommand10({
2328
+ var undeploy_default = defineCommand9({
3088
2329
  meta: {
3089
2330
  name: "undeploy",
3090
2331
  description: "Remove a deployed DeepSpace app"
@@ -3119,9 +2360,9 @@ var undeploy_default = defineCommand10({
3119
2360
  p5.cancel("Provide an app name or run from a DeepSpace app directory.");
3120
2361
  process.exit(1);
3121
2362
  }
3122
- let token2;
2363
+ let token;
3123
2364
  try {
3124
- token2 = await ensureToken();
2365
+ token = await ensureToken();
3125
2366
  } catch (err) {
3126
2367
  p5.cancel(err.message);
3127
2368
  process.exit(1);
@@ -3131,7 +2372,7 @@ var undeploy_default = defineCommand10({
3131
2372
  s.start("Removing...");
3132
2373
  const res = await fetch(`${DEPLOY_URL2}/api/deploy/${appName}`, {
3133
2374
  method: "DELETE",
3134
- headers: { Authorization: `Bearer ${token2}` }
2375
+ headers: { Authorization: `Bearer ${token}` }
3135
2376
  });
3136
2377
  const body = await res.json().catch(() => ({}));
3137
2378
  if (!res.ok || !body.success) {
@@ -3145,8 +2386,8 @@ var undeploy_default = defineCommand10({
3145
2386
  });
3146
2387
 
3147
2388
  // src/cli/commands/whoami.ts
3148
- import { defineCommand as defineCommand11 } from "citty";
3149
- var whoami_default = defineCommand11({
2389
+ import { defineCommand as defineCommand10 } from "citty";
2390
+ var whoami_default = defineCommand10({
3150
2391
  meta: {
3151
2392
  name: "whoami",
3152
2393
  description: "Show the currently logged-in user"
@@ -3201,18 +2442,18 @@ var whoami_default = defineCommand11({
3201
2442
  });
3202
2443
 
3203
2444
  // src/cli/commands/add.ts
3204
- import { defineCommand as defineCommand12 } from "citty";
3205
- import { existsSync as existsSync11 } from "fs";
3206
- import { resolve as resolve7, join as join11 } from "path";
2445
+ import { defineCommand as defineCommand11 } from "citty";
2446
+ import { existsSync as existsSync10 } from "fs";
2447
+ import { resolve as resolve7, join as join10 } from "path";
3207
2448
  import { execSync as execSync3 } from "child_process";
3208
2449
  function findScript(from) {
3209
- const inNodeModules = join11(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
3210
- if (existsSync11(inNodeModules)) return inNodeModules;
3211
- const inDotDeepspace = join11(from, ".deepspace", "scripts", "add-feature.cjs");
3212
- if (existsSync11(inDotDeepspace)) return inDotDeepspace;
2450
+ const inNodeModules = join10(from, "node_modules", "deepspace", "scripts", "add-feature.cjs");
2451
+ if (existsSync10(inNodeModules)) return inNodeModules;
2452
+ const inDotDeepspace = join10(from, ".deepspace", "scripts", "add-feature.cjs");
2453
+ if (existsSync10(inDotDeepspace)) return inDotDeepspace;
3213
2454
  return null;
3214
2455
  }
3215
- var add_default = defineCommand12({
2456
+ var add_default = defineCommand11({
3216
2457
  meta: {
3217
2458
  name: "add",
3218
2459
  description: "Add a feature to your DeepSpace app"
@@ -3247,8 +2488,8 @@ var add_default = defineCommand12({
3247
2488
  if (!script) {
3248
2489
  console.error("Could not find the deepspace feature installer.");
3249
2490
  console.error("Looked in:");
3250
- console.error(` ${join11(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
3251
- console.error(` ${join11(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
2491
+ console.error(` ${join10(appDir, "node_modules", "deepspace", "scripts", "add-feature.cjs")}`);
2492
+ console.error(` ${join10(appDir, ".deepspace", "scripts", "add-feature.cjs")}`);
3252
2493
  console.error("Are you in a DeepSpace app directory? Try `npm install` first.");
3253
2494
  process.exit(1);
3254
2495
  }
@@ -3270,10 +2511,10 @@ var add_default = defineCommand12({
3270
2511
  });
3271
2512
 
3272
2513
  // src/cli/commands/skills.ts
3273
- import { defineCommand as defineCommand13 } from "citty";
2514
+ import { defineCommand as defineCommand12 } from "citty";
3274
2515
  import spawn2 from "cross-spawn";
3275
2516
  import { mkdirSync as mkdirSync5 } from "fs";
3276
- import { join as join12 } from "path";
2517
+ import { join as join11 } from "path";
3277
2518
  import { homedir as homedir5 } from "os";
3278
2519
  var SKILL_REPO = "deepdotspace/deepspace-skill";
3279
2520
  function runSkillsAdd(extraArgs) {
@@ -3292,9 +2533,9 @@ function runSkillsAdd(extraArgs) {
3292
2533
  });
3293
2534
  }
3294
2535
  function precreateClaudeDir(baseDir) {
3295
- mkdirSync5(join12(baseDir, ".claude"), { recursive: true });
2536
+ mkdirSync5(join11(baseDir, ".claude"), { recursive: true });
3296
2537
  }
3297
- var add = defineCommand13({
2538
+ var add = defineCommand12({
3298
2539
  meta: {
3299
2540
  name: "add",
3300
2541
  description: "Install the DeepSpace skill for your coding agent"
@@ -3336,7 +2577,7 @@ var add = defineCommand13({
3336
2577
  if (code !== 0) process.exit(code);
3337
2578
  }
3338
2579
  });
3339
- var skills_default = defineCommand13({
2580
+ var skills_default = defineCommand12({
3340
2581
  meta: {
3341
2582
  name: "skills",
3342
2583
  description: "Manage the DeepSpace agent skill (Claude Code, Codex, OpenCode, Cursor, ...)"
@@ -3347,14 +2588,14 @@ var skills_default = defineCommand13({
3347
2588
  });
3348
2589
 
3349
2590
  // src/cli/commands/domain.ts
3350
- import { defineCommand as defineCommand14 } from "citty";
2591
+ import { defineCommand as defineCommand13 } from "citty";
3351
2592
  import { execSync as execSync4 } from "child_process";
3352
2593
  var API_URL2 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
3353
- async function api(token2, path, init) {
2594
+ async function api(token, path, init) {
3354
2595
  const res = await fetch(`${API_URL2}${path}`, {
3355
2596
  ...init,
3356
2597
  headers: {
3357
- Authorization: `Bearer ${token2}`,
2598
+ Authorization: `Bearer ${token}`,
3358
2599
  "Content-Type": "application/json",
3359
2600
  ...init?.headers ?? {}
3360
2601
  }
@@ -3403,7 +2644,7 @@ async function confirm3(message) {
3403
2644
  });
3404
2645
  });
3405
2646
  }
3406
- var search = defineCommand14({
2647
+ var search = defineCommand13({
3407
2648
  meta: { name: "search", description: "Search for available domains" },
3408
2649
  args: {
3409
2650
  query: { type: "positional", description: "Domain or keyword", required: true },
@@ -3411,10 +2652,10 @@ var search = defineCommand14({
3411
2652
  json: { type: "boolean", description: "Emit JSON instead of a table" }
3412
2653
  },
3413
2654
  async run({ args }) {
3414
- const token2 = await ensureToken();
2655
+ const token = await ensureToken();
3415
2656
  const limit = parseInt(args.limit ?? "10", 10) || 10;
3416
2657
  const result = await api(
3417
- token2,
2658
+ token,
3418
2659
  `/api/domains/search?q=${encodeURIComponent(args.query)}&limit=${limit}`
3419
2660
  );
3420
2661
  if (args.json) {
@@ -3433,7 +2674,7 @@ var search = defineCommand14({
3433
2674
  }
3434
2675
  }
3435
2676
  });
3436
- var buy = defineCommand14({
2677
+ var buy = defineCommand13({
3437
2678
  meta: { name: "buy", description: "Buy a domain and attach it to an app" },
3438
2679
  args: {
3439
2680
  domain: { type: "positional", description: "Domain to buy", required: true },
@@ -3444,9 +2685,9 @@ var buy = defineCommand14({
3444
2685
  json: { type: "boolean", description: "Emit JSON to stdout", default: false }
3445
2686
  },
3446
2687
  async run({ args }) {
3447
- const token2 = await ensureToken();
2688
+ const token = await ensureToken();
3448
2689
  const appName = requireAppName(args.app);
3449
- const priceCheck = await api(token2, "/api/domains/check", {
2690
+ const priceCheck = await api(token, "/api/domains/check", {
3450
2691
  method: "POST",
3451
2692
  body: JSON.stringify({ domains: [args.domain] })
3452
2693
  });
@@ -3467,7 +2708,7 @@ var buy = defineCommand14({
3467
2708
  }
3468
2709
  }
3469
2710
  const checkout = await api(
3470
- token2,
2711
+ token,
3471
2712
  "/api/domains/checkout",
3472
2713
  {
3473
2714
  method: "POST",
@@ -3494,7 +2735,7 @@ var buy = defineCommand14({
3494
2735
  await new Promise((r) => setTimeout(r, 5e3));
3495
2736
  try {
3496
2737
  const detail = await api(
3497
- token2,
2738
+ token,
3498
2739
  `/api/domains/${checkout.purchaseId}`
3499
2740
  );
3500
2741
  if (detail.domain.status !== lastStatus) {
@@ -3522,14 +2763,14 @@ var buy = defineCommand14({
3522
2763
  process.exit(1);
3523
2764
  }
3524
2765
  });
3525
- var list3 = defineCommand14({
2766
+ var list2 = defineCommand13({
3526
2767
  meta: { name: "list", description: "List your domains" },
3527
2768
  args: {
3528
2769
  json: { type: "boolean", description: "Emit JSON" }
3529
2770
  },
3530
2771
  async run({ args }) {
3531
- const token2 = await ensureToken();
3532
- const result = await api(token2, "/api/domains");
2772
+ const token = await ensureToken();
2773
+ const result = await api(token, "/api/domains");
3533
2774
  if (args.json) {
3534
2775
  process.stdout.write(JSON.stringify(scrubInternal(result), null, 2) + "\n");
3535
2776
  return;
@@ -3546,15 +2787,15 @@ var list3 = defineCommand14({
3546
2787
  }
3547
2788
  }
3548
2789
  });
3549
- var status = defineCommand14({
2790
+ var status = defineCommand13({
3550
2791
  meta: { name: "status", description: "Show details for one domain" },
3551
2792
  args: {
3552
2793
  domain: { type: "positional", description: "Domain", required: true },
3553
2794
  json: { type: "boolean" }
3554
2795
  },
3555
2796
  async run({ args }) {
3556
- const token2 = await ensureToken();
3557
- const all = await api(token2, "/api/domains");
2797
+ const token = await ensureToken();
2798
+ const all = await api(token, "/api/domains");
3558
2799
  const found = all.domains.find((d) => d.domain === args.domain);
3559
2800
  if (!found) {
3560
2801
  console.error(`No domain ${args.domain} in your account`);
@@ -3574,7 +2815,7 @@ var status = defineCommand14({
3574
2815
  console.log(`Charged: ${fmtCents(found.chargedCents)}/yr`);
3575
2816
  }
3576
2817
  });
3577
- var attach = defineCommand14({
2818
+ var attach = defineCommand13({
3578
2819
  meta: { name: "attach", description: "Re-point a domain at a different app" },
3579
2820
  args: {
3580
2821
  domain: { type: "positional", description: "Domain to re-point", required: true },
@@ -3582,16 +2823,16 @@ var attach = defineCommand14({
3582
2823
  json: { type: "boolean" }
3583
2824
  },
3584
2825
  async run({ args }) {
3585
- const token2 = await ensureToken();
2826
+ const token = await ensureToken();
3586
2827
  const targetApp = requireAppName(args.app);
3587
- const all = await api(token2, "/api/domains");
2828
+ const all = await api(token, "/api/domains");
3588
2829
  const found = all.domains.find((d) => d.domain === args.domain);
3589
2830
  if (!found) {
3590
2831
  console.error(`No domain ${args.domain} in your account`);
3591
2832
  process.exit(1);
3592
2833
  }
3593
2834
  const result = await api(
3594
- token2,
2835
+ token,
3595
2836
  `/api/domains/${found.id}/reattach`,
3596
2837
  {
3597
2838
  method: "POST",
@@ -3605,7 +2846,7 @@ var attach = defineCommand14({
3605
2846
  console.log(`\u2713 ${args.domain} now points at ${targetApp}`);
3606
2847
  }
3607
2848
  });
3608
- var detach = defineCommand14({
2849
+ var detach = defineCommand13({
3609
2850
  meta: {
3610
2851
  name: "detach",
3611
2852
  description: "Stop routing the domain (keeps the registration; auto-renew unchanged)"
@@ -3615,8 +2856,8 @@ var detach = defineCommand14({
3615
2856
  yes: { type: "boolean", description: "Skip the confirmation prompt" }
3616
2857
  },
3617
2858
  async run({ args }) {
3618
- const token2 = await ensureToken();
3619
- const all = await api(token2, "/api/domains");
2859
+ const token = await ensureToken();
2860
+ const all = await api(token, "/api/domains");
3620
2861
  const found = all.domains.find((d) => d.domain === args.domain);
3621
2862
  if (!found) {
3622
2863
  console.error(`No domain ${args.domain} in your account`);
@@ -3631,11 +2872,11 @@ var detach = defineCommand14({
3631
2872
  return;
3632
2873
  }
3633
2874
  }
3634
- await api(token2, `/api/domains/${found.id}`, { method: "DELETE" });
2875
+ await api(token, `/api/domains/${found.id}`, { method: "DELETE" });
3635
2876
  console.log(`\u2713 ${args.domain} detached. Use \`deepspace domain attach\` to re-route, or \`renew --auto off\` to stop auto-renewal.`);
3636
2877
  }
3637
2878
  });
3638
- var renew = defineCommand14({
2879
+ var renew = defineCommand13({
3639
2880
  meta: { name: "renew", description: "Toggle auto-renewal at the registrar" },
3640
2881
  args: {
3641
2882
  domain: { type: "positional", description: "Domain", required: true },
@@ -3646,15 +2887,15 @@ var renew = defineCommand14({
3646
2887
  console.error('--auto must be "on" or "off"');
3647
2888
  process.exit(1);
3648
2889
  }
3649
- const token2 = await ensureToken();
3650
- const all = await api(token2, "/api/domains");
2890
+ const token = await ensureToken();
2891
+ const all = await api(token, "/api/domains");
3651
2892
  const found = all.domains.find((d) => d.domain === args.domain);
3652
2893
  if (!found) {
3653
2894
  console.error(`No domain ${args.domain} in your account`);
3654
2895
  process.exit(1);
3655
2896
  }
3656
2897
  const enabled = args.auto === "on";
3657
- await api(token2, `/api/domains/${found.id}/auto-renew`, {
2898
+ await api(token, `/api/domains/${found.id}/auto-renew`, {
3658
2899
  method: "POST",
3659
2900
  body: JSON.stringify({ autoRenew: enabled })
3660
2901
  });
@@ -3669,16 +2910,16 @@ function openBrowser2(url) {
3669
2910
  } catch {
3670
2911
  }
3671
2912
  }
3672
- var domain_default = defineCommand14({
2913
+ var domain_default = defineCommand13({
3673
2914
  meta: { name: "domain", description: "Buy and manage custom domains" },
3674
- subCommands: { search, buy, list: list3, status, attach, detach, renew }
2915
+ subCommands: { search, buy, list: list2, status, attach, detach, renew }
3675
2916
  });
3676
2917
 
3677
2918
  // src/cli/commands/integrations.ts
3678
- import { defineCommand as defineCommand15 } from "citty";
2919
+ import { defineCommand as defineCommand14 } from "citty";
3679
2920
 
3680
2921
  // src/cli/commands/_invoke-impl.ts
3681
- import { readFileSync as readFileSync10 } from "fs";
2922
+ import { readFileSync as readFileSync9 } from "fs";
3682
2923
  var API_URL3 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
3683
2924
  var DEFAULT_TIMEOUT_MS = 12e4;
3684
2925
  function parseTarget(target) {
@@ -3699,7 +2940,7 @@ function resolveBody(opts) {
3699
2940
  if (opts.body != null) {
3700
2941
  raw = opts.body;
3701
2942
  } else if (opts.bodyFile != null) {
3702
- raw = opts.bodyFile === "-" ? readFileSync10(0, "utf-8") : readFileSync10(opts.bodyFile, "utf-8");
2943
+ raw = opts.bodyFile === "-" ? readFileSync9(0, "utf-8") : readFileSync9(opts.bodyFile, "utf-8");
3703
2944
  } else {
3704
2945
  return "{}";
3705
2946
  }
@@ -3850,7 +3091,7 @@ async function runInvoke(args) {
3850
3091
  }
3851
3092
 
3852
3093
  // src/cli/commands/integrations.ts
3853
- var list4 = defineCommand15({
3094
+ var list3 = defineCommand14({
3854
3095
  meta: {
3855
3096
  name: "list",
3856
3097
  description: "List all available integrations"
@@ -3871,7 +3112,7 @@ var list4 = defineCommand15({
3871
3112
  }
3872
3113
  }
3873
3114
  });
3874
- var info = defineCommand15({
3115
+ var info = defineCommand14({
3875
3116
  meta: {
3876
3117
  name: "info",
3877
3118
  description: "Print schema + example body for an integration endpoint"
@@ -3897,7 +3138,7 @@ var info = defineCommand15({
3897
3138
  }
3898
3139
  }
3899
3140
  });
3900
- var invoke = defineCommand15({
3141
+ var invoke = defineCommand14({
3901
3142
  meta: {
3902
3143
  name: "invoke",
3903
3144
  description: "Invoke a platform integration as the logged-in user"
@@ -3950,21 +3191,21 @@ var invoke = defineCommand15({
3950
3191
  }
3951
3192
  }
3952
3193
  });
3953
- var integrations_default = defineCommand15({
3194
+ var integrations_default = defineCommand14({
3954
3195
  meta: {
3955
3196
  name: "integrations",
3956
3197
  description: "List, inspect, and invoke platform integrations"
3957
3198
  },
3958
3199
  subCommands: {
3959
- list: list4,
3200
+ list: list3,
3960
3201
  info,
3961
3202
  invoke
3962
3203
  }
3963
3204
  });
3964
3205
 
3965
3206
  // src/cli/commands/invoke.ts
3966
- import { defineCommand as defineCommand16 } from "citty";
3967
- var invoke_default = defineCommand16({
3207
+ import { defineCommand as defineCommand15 } from "citty";
3208
+ var invoke_default = defineCommand15({
3968
3209
  meta: {
3969
3210
  name: "invoke",
3970
3211
  description: "Invoke a platform integration as the logged-in user"
@@ -4036,257 +3277,14 @@ var invoke_default = defineCommand16({
4036
3277
  }
4037
3278
  });
4038
3279
 
4039
- // src/cli/commands/managed-repos.ts
4040
- import { defineCommand as defineCommand17 } from "citty";
4041
- var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
4042
- var SIMPLE_APP_ID = /^[a-z0-9][a-z0-9_.:-]{0,119}$/i;
4043
- var SIMPLE_APP_NAME = /^[a-z0-9][a-z0-9_-]{0,119}$/i;
4044
- async function api2(token2, path, init) {
4045
- const res = await fetch(`${API_URL4}${path}`, {
4046
- ...init,
4047
- headers: {
4048
- Authorization: `Bearer ${token2}`,
4049
- "Content-Type": "application/json",
4050
- ...init?.headers ?? {}
4051
- }
4052
- });
4053
- const text2 = await res.text();
4054
- if (!res.ok) {
4055
- let msg = text2;
4056
- try {
4057
- msg = JSON.parse(text2).error ?? text2;
4058
- } catch {
4059
- }
4060
- throw new Error(`API ${path} (${res.status}): ${msg}`);
4061
- }
4062
- return JSON.parse(text2);
4063
- }
4064
- function defaultAppId(appName) {
4065
- return `cli-${slugId(appName)}`;
4066
- }
4067
- function slugId(raw) {
4068
- return raw.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "app";
4069
- }
4070
- function assertSimple(value, pattern, label) {
4071
- if (!pattern.test(value)) {
4072
- throw new Error(`${label} must start with a letter or number and contain only simple identifier characters.`);
4073
- }
4074
- }
4075
- function printQuota(quota) {
4076
- console.log(`Repo quota: ${quota.activeCount} / ${quota.limit} active (${quota.remaining} remaining)`);
4077
- }
4078
- function printRepo(repo) {
4079
- console.log(`${repo.fullName}`);
4080
- console.log(` ID: ${repo.id}`);
4081
- console.log(` App: ${repo.appName}`);
4082
- console.log(` App ID: ${repo.appId}`);
4083
- console.log(` URL: ${repo.htmlUrl}`);
4084
- console.log(` Clone: ${repo.cloneUrl}`);
4085
- }
4086
- async function confirm4(message) {
4087
- if (!process.stdin.isTTY) {
4088
- throw new Error(`${message} \u2014 pass --yes to confirm non-interactively`);
4089
- }
4090
- process.stdout.write(`${message} [y/N] `);
4091
- return new Promise((resolve9) => {
4092
- process.stdin.setEncoding("utf-8");
4093
- process.stdin.once("data", (data) => {
4094
- const answer = data.toString().trim().toLowerCase();
4095
- resolve9(answer === "y" || answer === "yes");
4096
- });
4097
- });
4098
- }
4099
- var list5 = defineCommand17({
4100
- meta: {
4101
- name: "list",
4102
- description: "List your DeepSpace-managed repos and quota"
4103
- },
4104
- args: {
4105
- json: {
4106
- type: "boolean",
4107
- description: "Emit JSON instead of human output",
4108
- default: false
4109
- }
4110
- },
4111
- async run({ args }) {
4112
- const token2 = await ensureToken();
4113
- const result = await api2(token2, "/api/github/repos");
4114
- if (args.json) {
4115
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
4116
- return;
4117
- }
4118
- printQuota(result.quota);
4119
- if (result.repos.length === 0) {
4120
- console.log("No DeepSpace-managed repos. Create one with `deepspace managed-repos create <app-name>`.");
4121
- return;
4122
- }
4123
- console.log("");
4124
- for (const repo of result.repos) {
4125
- printRepo(repo);
4126
- }
4127
- }
4128
- });
4129
- var create2 = defineCommand17({
4130
- meta: {
4131
- name: "create",
4132
- description: "Create a private DeepSpace-managed GitHub repo"
4133
- },
4134
- args: {
4135
- appName: {
4136
- type: "positional",
4137
- description: "Working app name for this repo",
4138
- required: true
4139
- },
4140
- appId: {
4141
- type: "string",
4142
- description: "Stable DeepSpace repo app id (defaults to cli-<app-name>)",
4143
- required: false
4144
- },
4145
- nameHint: {
4146
- type: "string",
4147
- description: "Repo-name hint (defaults to app name)",
4148
- required: false
4149
- },
4150
- json: {
4151
- type: "boolean",
4152
- description: "Emit JSON instead of human output",
4153
- default: false
4154
- }
4155
- },
4156
- async run({ args }) {
4157
- const appName = String(args.appName);
4158
- const appId = args.appId ? String(args.appId) : defaultAppId(appName);
4159
- const nameHint = args.nameHint ? String(args.nameHint) : void 0;
4160
- try {
4161
- assertSimple(appName, SIMPLE_APP_NAME, "appName");
4162
- assertSimple(appId, SIMPLE_APP_ID, "appId");
4163
- if (nameHint) assertSimple(nameHint, SIMPLE_APP_NAME, "nameHint");
4164
- } catch (err) {
4165
- console.error(err.message);
4166
- process.exit(1);
4167
- }
4168
- const token2 = await ensureToken();
4169
- const result = await api2(token2, "/api/github/repos", {
4170
- method: "POST",
4171
- body: JSON.stringify({ appName, appId, ...nameHint ? { nameHint } : {} })
4172
- });
4173
- if (args.json) {
4174
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
4175
- return;
4176
- }
4177
- console.log(result.alreadyExists ? "Existing DeepSpace-managed repo:" : "Created DeepSpace-managed repo:");
4178
- printRepo(result.repo);
4179
- }
4180
- });
4181
- var token = defineCommand17({
4182
- meta: {
4183
- name: "token",
4184
- description: "Mint a short-lived GitHub token for a DeepSpace-managed repo"
4185
- },
4186
- args: {
4187
- repoId: {
4188
- type: "positional",
4189
- description: "Repo id from `deepspace managed-repos list`",
4190
- required: true
4191
- },
4192
- json: {
4193
- type: "boolean",
4194
- description: "Emit JSON instead of human output",
4195
- default: false
4196
- }
4197
- },
4198
- async run({ args }) {
4199
- const jwt = await ensureToken();
4200
- const result = await api2(
4201
- jwt,
4202
- `/api/github/repos/${encodeURIComponent(String(args.repoId))}/agent-token`,
4203
- { method: "POST" }
4204
- );
4205
- if (args.json) {
4206
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
4207
- return;
4208
- }
4209
- console.log(`Repo: ${result.repo.fullName}`);
4210
- console.log(`Expires: ${result.token.expiresAt}`);
4211
- console.log(`Token: ${result.token.token}`);
4212
- console.log("");
4213
- console.log(`Clone: git clone https://x-access-token:${encodeURIComponent(result.token.token)}@github.com/${result.repo.fullName}.git`);
4214
- }
4215
- });
4216
- var remove = defineCommand17({
4217
- meta: {
4218
- name: "delete",
4219
- description: "Delete a DeepSpace-managed GitHub repo"
4220
- },
4221
- args: {
4222
- repoId: {
4223
- type: "positional",
4224
- description: "Repo id from `deepspace managed-repos list`",
4225
- required: true
4226
- },
4227
- yes: {
4228
- type: "boolean",
4229
- description: "Skip the confirmation prompt",
4230
- default: false
4231
- },
4232
- json: {
4233
- type: "boolean",
4234
- description: "Emit JSON instead of human output",
4235
- default: false
4236
- }
4237
- },
4238
- async run({ args }) {
4239
- if (!args.yes) {
4240
- try {
4241
- const ok = await confirm4(
4242
- "Delete this DeepSpace-managed GitHub repo? This removes the GitHub repository and counts against your daily delete quota."
4243
- );
4244
- if (!ok) {
4245
- console.log("Cancelled.");
4246
- return;
4247
- }
4248
- } catch (err) {
4249
- console.error(err.message);
4250
- process.exit(1);
4251
- }
4252
- }
4253
- const jwt = await ensureToken();
4254
- const result = await api2(
4255
- jwt,
4256
- `/api/github/repos/${encodeURIComponent(String(args.repoId))}`,
4257
- { method: "DELETE" }
4258
- );
4259
- if (args.json) {
4260
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
4261
- return;
4262
- }
4263
- console.log(`Deleted ${result.repo.fullName}`);
4264
- console.log(
4265
- `Delete quota: ${result.deletionQuota.deletedCount} / ${result.deletionQuota.limit} used today (${result.deletionQuota.remaining} remaining)`
4266
- );
4267
- }
4268
- });
4269
- var managed_repos_default = defineCommand17({
4270
- meta: {
4271
- name: "managed-repos",
4272
- description: "Create and manage DeepSpace-owned GitHub repos"
4273
- },
4274
- subCommands: {
4275
- list: list5,
4276
- create: create2,
4277
- token,
4278
- delete: remove
4279
- }
4280
- });
4281
-
4282
3280
  // src/cli/commands/library.ts
4283
- import { defineCommand as defineCommand18 } from "citty";
4284
- import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
4285
- import { join as join13, resolve as resolve8 } from "path";
3281
+ import { defineCommand as defineCommand16 } from "citty";
3282
+ import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
3283
+ import { join as join12, resolve as resolve8 } from "path";
4286
3284
  import { parse as parseToml3 } from "smol-toml";
4287
3285
  import * as p6 from "@clack/prompts";
4288
3286
  var DEFAULT_LIBRARY_APP = "deepdotspace-site";
4289
- var publish = defineCommand18({
3287
+ var publish = defineCommand16({
4290
3288
  meta: {
4291
3289
  name: "publish",
4292
3290
  description: "Publish the current app to the DeepSpace library"
@@ -4360,11 +3358,11 @@ var publish = defineCommand18({
4360
3358
  let appName = typeof args.app === "string" && args.app.trim() ? args.app.trim() : void 0;
4361
3359
  if (!appName) {
4362
3360
  const appDir = resolve8(typeof args.dir === "string" && args.dir ? args.dir : ".");
4363
- const wranglerPath = join13(appDir, "wrangler.toml");
4364
- if (!existsSync12(wranglerPath)) {
3361
+ const wranglerPath = join12(appDir, "wrangler.toml");
3362
+ if (!existsSync11(wranglerPath)) {
4365
3363
  return die("No --app provided and no wrangler.toml found. Either pass --app <name> or run from your app's directory.");
4366
3364
  }
4367
- const cfg = parseToml3(readFileSync11(wranglerPath, "utf-8"));
3365
+ const cfg = parseToml3(readFileSync10(wranglerPath, "utf-8"));
4368
3366
  const nameRes = resolveAppName(cfg.name);
4369
3367
  if (!nameRes.ok) return die(`wrangler.toml: ${nameRes.reason}`);
4370
3368
  appName = nameRes.name;
@@ -4377,9 +3375,9 @@ var publish = defineCommand18({
4377
3375
  const tags = typeof args.tags === "string" && args.tags ? args.tags.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
4378
3376
  const libraryApp = typeof args["library-app"] === "string" && args["library-app"] ? args["library-app"] : DEFAULT_LIBRARY_APP;
4379
3377
  const libraryHost = process.env.DEEPSPACE_LIBRARY_HOST ?? `https://${libraryApp}.app.space`;
4380
- let token2;
3378
+ let token;
4381
3379
  try {
4382
- token2 = await ensureToken();
3380
+ token = await ensureToken();
4383
3381
  } catch (err) {
4384
3382
  return die(err instanceof Error ? err.message : String(err));
4385
3383
  }
@@ -4399,7 +3397,7 @@ var publish = defineCommand18({
4399
3397
  method: "POST",
4400
3398
  headers: {
4401
3399
  "Content-Type": "application/json",
4402
- Authorization: `Bearer ${token2}`
3400
+ Authorization: `Bearer ${token}`
4403
3401
  },
4404
3402
  body: JSON.stringify(payload)
4405
3403
  });
@@ -4425,7 +3423,7 @@ var publish = defineCommand18({
4425
3423
  p6.outro("Done");
4426
3424
  }
4427
3425
  });
4428
- var unpublish = defineCommand18({
3426
+ var unpublish = defineCommand16({
4429
3427
  meta: {
4430
3428
  name: "unpublish",
4431
3429
  description: "Remove a library entry (owner or admin only)"
@@ -4455,9 +3453,9 @@ var unpublish = defineCommand18({
4455
3453
  process.exit(1);
4456
3454
  };
4457
3455
  if (!json) p6.intro("Unpublishing library entry");
4458
- let token2;
3456
+ let token;
4459
3457
  try {
4460
- token2 = await ensureToken();
3458
+ token = await ensureToken();
4461
3459
  } catch (err) {
4462
3460
  return die(err instanceof Error ? err.message : String(err));
4463
3461
  }
@@ -4465,7 +3463,7 @@ var unpublish = defineCommand18({
4465
3463
  const libraryHost = process.env.DEEPSPACE_LIBRARY_HOST ?? `https://${libraryApp}.app.space`;
4466
3464
  const res = await fetch(`${libraryHost}/api/actions/library.unpublish`, {
4467
3465
  method: "POST",
4468
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${token2}` },
3466
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
4469
3467
  body: JSON.stringify({ templateHandle: String(args.handle) })
4470
3468
  });
4471
3469
  const body = await res.text();
@@ -4484,7 +3482,7 @@ var unpublish = defineCommand18({
4484
3482
  p6.outro("Done");
4485
3483
  }
4486
3484
  });
4487
- var library_default = defineCommand18({
3485
+ var library_default = defineCommand16({
4488
3486
  meta: {
4489
3487
  name: "library",
4490
3488
  description: "Manage your DeepSpace library entries"
@@ -4495,86 +3493,14 @@ var library_default = defineCommand18({
4495
3493
  }
4496
3494
  });
4497
3495
 
4498
- // src/cli/commands/admin.ts
4499
- import { defineCommand as defineCommand19 } from "citty";
4500
- import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync7 } from "fs";
4501
- import { homedir as homedir6 } from "os";
4502
- import { join as join14 } from "path";
4503
- var AUTH_URL5 = process.env.DEEPSPACE_AUTH_URL ?? ENVS.prod.auth;
4504
- var impersonate = defineCommand19({
4505
- meta: {
4506
- name: "impersonate",
4507
- description: "Store a short-lived CLI token for another user"
4508
- },
4509
- args: {
4510
- email: {
4511
- type: "string",
4512
- description: "Target user email",
4513
- required: false
4514
- },
4515
- userId: {
4516
- type: "string",
4517
- description: "Target user id",
4518
- required: false
4519
- },
4520
- secret: {
4521
- type: "string",
4522
- description: "Admin secret; defaults to DEEPSPACE_ADMIN_SECRET",
4523
- required: false
4524
- }
4525
- },
4526
- async run({ args }) {
4527
- const secret = args.secret ?? process.env.DEEPSPACE_ADMIN_SECRET;
4528
- if (!secret) {
4529
- console.error("Missing admin secret. Set DEEPSPACE_ADMIN_SECRET or pass --secret.");
4530
- process.exit(1);
4531
- }
4532
- if (!args.email && !args.userId) {
4533
- console.error("Pass --email or --userId.");
4534
- process.exit(1);
4535
- }
4536
- const res = await fetch(`${AUTH_URL5}/api/auth/admin/impersonate`, {
4537
- method: "POST",
4538
- headers: {
4539
- "Content-Type": "application/json",
4540
- Authorization: `Bearer ${secret}`
4541
- },
4542
- body: JSON.stringify({
4543
- email: args.email,
4544
- userId: args.userId
4545
- })
4546
- });
4547
- const data = await res.json().catch(() => ({}));
4548
- if (!res.ok || !data.token || !data.user) {
4549
- console.error(`Failed: ${data.error ?? `HTTP ${res.status}`}`);
4550
- process.exit(1);
4551
- }
4552
- const dir = join14(homedir6(), ".deepspace");
4553
- mkdirSync6(dir, { recursive: true });
4554
- writeFileSync7(TOKEN_PATH2, data.token, { mode: 384 });
4555
- console.log(`Impersonating ${data.user.name ?? data.user.email ?? data.user.id}`);
4556
- console.log(`Email: ${data.user.email ?? "(none)"}`);
4557
- console.log(`UserID: ${data.user.id}`);
4558
- }
4559
- });
4560
- var admin_default = defineCommand19({
4561
- meta: {
4562
- name: "admin",
4563
- description: "Maintainer-only admin commands"
4564
- },
4565
- subCommands: {
4566
- impersonate
4567
- }
4568
- });
4569
-
4570
3496
  // src/cli/commands/feedback.ts
4571
- import { defineCommand as defineCommand20 } from "citty";
3497
+ import { defineCommand as defineCommand17 } from "citty";
4572
3498
  import * as p7 from "@clack/prompts";
4573
- import { existsSync as existsSync13, readFileSync as readFileSync12 } from "fs";
4574
- import { dirname as dirname3, join as join15 } from "path";
3499
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
3500
+ import { dirname as dirname3, join as join13 } from "path";
4575
3501
  import { fileURLToPath } from "url";
4576
3502
  import { release } from "os";
4577
- var API_URL5 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
3503
+ var API_URL4 = process.env.DEEPSPACE_API_URL ?? ENVS.prod.api;
4578
3504
  var TYPES = ["bug", "feature", "other"];
4579
3505
  var TYPE_LABELS = {
4580
3506
  bug: "Bug report",
@@ -4584,11 +3510,11 @@ var TYPE_LABELS = {
4584
3510
  var MAX_TITLE_LEN = 200;
4585
3511
  var MAX_BODY_LEN = 1e4;
4586
3512
  var MAX_CONTEXT_LEN = 200;
4587
- async function api3(token2, path, init) {
4588
- const res = await fetch(`${API_URL5}${path}`, {
3513
+ async function api2(token, path, init) {
3514
+ const res = await fetch(`${API_URL4}${path}`, {
4589
3515
  ...init,
4590
3516
  headers: {
4591
- Authorization: `Bearer ${token2}`,
3517
+ Authorization: `Bearer ${token}`,
4592
3518
  "Content-Type": "application/json",
4593
3519
  ...init?.headers ?? {}
4594
3520
  }
@@ -4613,12 +3539,12 @@ function readCliVersion() {
4613
3539
  try {
4614
3540
  const here = dirname3(fileURLToPath(import.meta.url));
4615
3541
  const candidates = [
4616
- join15(here, "..", "package.json"),
4617
- join15(here, "..", "..", "..", "package.json")
3542
+ join13(here, "..", "package.json"),
3543
+ join13(here, "..", "..", "..", "package.json")
4618
3544
  ];
4619
3545
  for (const path of candidates) {
4620
- if (!existsSync13(path)) continue;
4621
- const pkg2 = JSON.parse(readFileSync12(path, "utf-8"));
3546
+ if (!existsSync12(path)) continue;
3547
+ const pkg2 = JSON.parse(readFileSync11(path, "utf-8"));
4622
3548
  if (pkg2.name === "deepspace" && pkg2.version) return pkg2.version;
4623
3549
  }
4624
3550
  } catch {
@@ -4669,7 +3595,7 @@ function buildFeedbackPayload(input) {
4669
3595
  ...input.context
4670
3596
  };
4671
3597
  }
4672
- var feedback_default = defineCommand20({
3598
+ var feedback_default = defineCommand17({
4673
3599
  meta: {
4674
3600
  name: "feedback",
4675
3601
  description: "Submit a bug report, feature request, or feedback to DeepSpace"
@@ -4802,15 +3728,15 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
4802
3728
  process.exit(0);
4803
3729
  }
4804
3730
  }
4805
- let token2;
3731
+ let token;
4806
3732
  try {
4807
- token2 = await ensureToken();
3733
+ token = await ensureToken();
4808
3734
  } catch (err) {
4809
3735
  return fail(err.message ?? "Not signed in. Run `deepspace login`.");
4810
3736
  }
4811
3737
  let result;
4812
3738
  try {
4813
- result = await api3(token2, "/api/feedback", {
3739
+ result = await api2(token, "/api/feedback", {
4814
3740
  method: "POST",
4815
3741
  body: JSON.stringify(payload)
4816
3742
  });
@@ -4832,11 +3758,11 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
4832
3758
 
4833
3759
  // src/cli/cli.ts
4834
3760
  var __dirname = dirname4(fileURLToPath2(import.meta.url));
4835
- var pkg = JSON.parse(readFileSync13(join16(__dirname, "..", "package.json"), "utf-8"));
4836
- if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync14("/etc/ssl/certs/ca-certificates.crt")) {
3761
+ var pkg = JSON.parse(readFileSync12(join14(__dirname, "..", "package.json"), "utf-8"));
3762
+ if (process.platform === "linux" && !process.env.SSL_CERT_FILE && existsSync13("/etc/ssl/certs/ca-certificates.crt")) {
4837
3763
  process.env.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt";
4838
3764
  }
4839
- var create3 = defineCommand21({
3765
+ var create2 = defineCommand18({
4840
3766
  meta: {
4841
3767
  name: "create",
4842
3768
  description: "Create a new DeepSpace app"
@@ -4855,14 +3781,14 @@ var create3 = defineCommand21({
4855
3781
  execSync5(`npm create deepspace@latest${name}`, { stdio: "inherit" });
4856
3782
  }
4857
3783
  });
4858
- var main = defineCommand21({
3784
+ var main = defineCommand18({
4859
3785
  meta: {
4860
3786
  name: "deepspace",
4861
3787
  version: pkg.version,
4862
3788
  description: "DeepSpace SDK CLI"
4863
3789
  },
4864
3790
  subCommands: {
4865
- create: create3,
3791
+ create: create2,
4866
3792
  login: login_default,
4867
3793
  logout: logout_default,
4868
3794
  whoami: whoami_default,
@@ -4874,15 +3800,12 @@ var main = defineCommand21({
4874
3800
  add: add_default,
4875
3801
  skills: skills_default,
4876
3802
  integrations: integrations_default,
4877
- "managed-repos": managed_repos_default,
4878
3803
  invoke: invoke_default,
4879
3804
  deploy: deploy_default,
4880
3805
  undeploy: undeploy_default,
4881
3806
  domain: domain_default,
4882
3807
  library: library_default,
4883
- admin: admin_default,
4884
- feedback: feedback_default,
4885
- secrets: secrets_default
3808
+ feedback: feedback_default
4886
3809
  }
4887
3810
  // No `run()` here — citty cascades parent run() AFTER subcommand finishes,
4888
3811
  // which corrupts agent-friendly output (`--json`) and prints noise on every