deepspace 0.30.2 → 0.31.1

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
@@ -726,6 +726,12 @@ function effectivePlatformUrls(env = process.env) {
726
726
  deploy: env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy
727
727
  };
728
728
  }
729
+ var {
730
+ auth: AUTH_URL,
731
+ api: API_URL,
732
+ platform: PLATFORM_URL,
733
+ deploy: DEPLOY_URL
734
+ } = effectivePlatformUrls();
729
735
  var DASHBOARD_URL = DEEPSPACE_ENV === "production" ? "https://dashboard.deep.space" : DEEPSPACE_ENV === "staging" ? "https://dashboard.deepspacesites.com" : "http://127.0.0.1:9";
730
736
 
731
737
  // src/cli/auth.ts
@@ -824,7 +830,6 @@ function writeSecretFileSync(path, content) {
824
830
  }
825
831
 
826
832
  // src/cli/auth.ts
827
- var AUTH_URL = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
828
833
  var PROD_AUTH_URL = PLANE_AUTH_URLS.production;
829
834
  var DIR = join(homedir(), ".deepspace");
830
835
  function credentialSuffix(authUrl) {
@@ -843,18 +848,44 @@ function credentialPaths(authUrl = AUTH_URL) {
843
848
  return { sessionPath: join(DIR, `session${suffix}`), tokenPath: join(DIR, `token${suffix}`) };
844
849
  }
845
850
  var { sessionPath: SESSION_PATH, tokenPath: TOKEN_PATH } = credentialPaths();
851
+ function errnoCode(error) {
852
+ const code = error?.code;
853
+ return typeof code === "string" && code.length > 0 ? code : void 0;
854
+ }
855
+ function readCredential(path) {
856
+ try {
857
+ return readFileSync2(path, "utf-8").trim();
858
+ } catch (error) {
859
+ const code = errnoCode(error);
860
+ if (code === "ENOENT") return null;
861
+ throw new Refusal(
862
+ `Could not read the DeepSpace CLI credential at ${path}${code ? ` (${code})` : ""}. Fix the file or directory permissions, then retry.`,
863
+ "credential_unreadable"
864
+ );
865
+ }
866
+ }
867
+ function writeCachedToken(token) {
868
+ try {
869
+ mkdirSync(DIR, { recursive: true, mode: 448 });
870
+ writeSecretFileSync(TOKEN_PATH, token);
871
+ } catch (error) {
872
+ const code = errnoCode(error);
873
+ throw new Refusal(
874
+ `Could not save the refreshed DeepSpace CLI token at ${TOKEN_PATH}${code ? ` (${code})` : ""}. Make ${DIR} writable and check available disk space, then retry.`,
875
+ "credential_unwritable"
876
+ );
877
+ }
878
+ }
846
879
  async function ensureToken(options = {}) {
847
880
  const minimumValidityMs = options.minimumValidityMs ?? 3e4;
848
- if (existsSync(TOKEN_PATH)) {
849
- const existing = readFileSync2(TOKEN_PATH, "utf-8").trim();
850
- if (isTokenValid(existing, minimumValidityMs)) {
851
- return existing;
852
- }
853
- }
854
- if (!existsSync(SESSION_PATH)) throw notAuthenticated("Not logged in");
855
- const token = await exchangeStoredSession();
856
- if (!token)
857
- throw notAuthenticated("The stored session is no longer valid (expired or unreadable)");
881
+ const existing = readCredential(TOKEN_PATH);
882
+ if (existing !== null && isTokenValid(existing, minimumValidityMs)) {
883
+ return existing;
884
+ }
885
+ const sessionToken = readCredential(SESSION_PATH);
886
+ if (sessionToken === null) throw notAuthenticated("Not logged in");
887
+ const token = await exchangeAndCacheSession(sessionToken);
888
+ if (!token) throw notAuthenticated("The stored session is invalid");
858
889
  return token;
859
890
  }
860
891
  function loginAction() {
@@ -887,20 +918,21 @@ async function refreshTokenFromSession() {
887
918
  return await exchangeStoredSession();
888
919
  }
889
920
  async function mintAgentToken(target2) {
890
- if (!existsSync(SESSION_PATH)) throw notAuthenticated("Not logged in");
891
- const sessionToken = readFileSync2(SESSION_PATH, "utf-8").trim();
921
+ const sessionToken = readCredential(SESSION_PATH);
922
+ if (sessionToken === null) throw notAuthenticated("Not logged in");
892
923
  const token = await exchangeAgentSession(AUTH_URL, sessionToken, target2);
893
- if (!token)
894
- throw notAuthenticated("The stored session is no longer valid (expired or unreadable)");
924
+ if (!token) throw notAuthenticated("The stored session is invalid");
895
925
  return token;
896
926
  }
897
927
  async function exchangeStoredSession() {
898
- if (!existsSync(SESSION_PATH)) return null;
899
- const sessionToken = readFileSync2(SESSION_PATH, "utf-8").trim();
928
+ const sessionToken = readCredential(SESSION_PATH);
929
+ if (sessionToken === null) return null;
930
+ return await exchangeAndCacheSession(sessionToken);
931
+ }
932
+ async function exchangeAndCacheSession(sessionToken) {
900
933
  const token = await exchangeSession(AUTH_URL, sessionToken);
901
934
  if (!token) return null;
902
- mkdirSync(DIR, { recursive: true, mode: 448 });
903
- writeSecretFileSync(TOKEN_PATH, token);
935
+ writeCachedToken(token);
904
936
  return token;
905
937
  }
906
938
  registerAuthRefresh(refreshTokenFromSession);
@@ -940,8 +972,6 @@ async function readStreamText(stream, maxBytes) {
940
972
  }
941
973
 
942
974
  // src/cli/commands/login.ts
943
- var AUTH_URL2 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
944
- var API_URL = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
945
975
  var login_default = defineDeepspaceCommand({
946
976
  meta: {
947
977
  name: "login",
@@ -1073,7 +1103,7 @@ async function createCliLoginSession(codeChallenge) {
1073
1103
  let sessionRes;
1074
1104
  try {
1075
1105
  sessionRes = await fetchWithTransientRetry(
1076
- `${AUTH_URL2}/api/auth/cli/session`,
1106
+ `${AUTH_URL}/api/auth/cli/session`,
1077
1107
  () => ({
1078
1108
  method: "POST",
1079
1109
  headers: { "Content-Type": "application/json" },
@@ -1111,7 +1141,7 @@ async function pollForCompletion(sessionId, codeVerifier) {
1111
1141
  for (let i = 0; i < maxAttempts; i++) {
1112
1142
  await sleep(interval);
1113
1143
  try {
1114
- const res = await fetch(`${AUTH_URL2}/api/auth/cli/status/${sessionId}`, {
1144
+ const res = await fetch(`${AUTH_URL}/api/auth/cli/status/${sessionId}`, {
1115
1145
  headers: { "x-code-verifier": codeVerifier }
1116
1146
  });
1117
1147
  if (res.status === 410 || res.status === 404) return null;
@@ -1131,7 +1161,7 @@ async function pollForCompletion(sessionId, codeVerifier) {
1131
1161
  return null;
1132
1162
  }
1133
1163
  function storeCredentials(sessionToken, jwt) {
1134
- const { sessionPath, tokenPath } = credentialPaths(AUTH_URL2);
1164
+ const { sessionPath, tokenPath } = credentialPaths(AUTH_URL);
1135
1165
  mkdirSync2(dirname2(sessionPath), { recursive: true, mode: 448 });
1136
1166
  writeSecretFileSync(sessionPath, sessionToken);
1137
1167
  writeSecretFileSync(tokenPath, jwt);
@@ -1149,9 +1179,9 @@ function base64url(bytes) {
1149
1179
  return bytes.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1150
1180
  }
1151
1181
  async function doEmailLogin(email, password) {
1152
- const res = await fetch(`${AUTH_URL2}/api/auth/sign-in/email`, {
1182
+ const res = await fetch(`${AUTH_URL}/api/auth/sign-in/email`, {
1153
1183
  method: "POST",
1154
- headers: { "Content-Type": "application/json", Origin: AUTH_URL2 },
1184
+ headers: { "Content-Type": "application/json", Origin: AUTH_URL },
1155
1185
  body: JSON.stringify({ email, password }),
1156
1186
  redirect: "manual"
1157
1187
  });
@@ -1168,7 +1198,7 @@ async function doEmailLogin(email, password) {
1168
1198
  throw new Refusal("The auth service returned no session cookie.", "login_failed");
1169
1199
  }
1170
1200
  const sessionToken = decodeURIComponent(cookieMatch[1]);
1171
- const jwt = await exchangeSession(AUTH_URL2, sessionToken);
1201
+ const jwt = await exchangeSession(AUTH_URL, sessionToken);
1172
1202
  if (!jwt) {
1173
1203
  throw new Refusal(
1174
1204
  "Signed in, but the auth service issued no token for the session.",
@@ -1187,8 +1217,7 @@ async function doEmailLogin(email, password) {
1187
1217
 
1188
1218
  // src/cli/commands/logout.ts
1189
1219
  import { existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
1190
- var AUTH_URL3 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
1191
- var { sessionPath: SESSION_PATH2, tokenPath: TOKEN_PATH2 } = credentialPaths(AUTH_URL3);
1220
+ var { sessionPath: SESSION_PATH2, tokenPath: TOKEN_PATH2 } = credentialPaths(AUTH_URL);
1192
1221
  var logout_default = defineDeepspaceCommand({
1193
1222
  meta: {
1194
1223
  name: "logout",
@@ -1198,11 +1227,11 @@ var logout_default = defineDeepspaceCommand({
1198
1227
  const sessionToken = existsSync2(SESSION_PATH2) ? readFileSync3(SESSION_PATH2, "utf-8").trim() : null;
1199
1228
  if (sessionToken) {
1200
1229
  try {
1201
- await fetch(`${AUTH_URL3}/api/auth/sign-out`, {
1230
+ await fetch(`${AUTH_URL}/api/auth/sign-out`, {
1202
1231
  method: "POST",
1203
1232
  headers: {
1204
1233
  Cookie: `${SESSION_COOKIE}=${encodeURIComponent(sessionToken)}`,
1205
- Origin: AUTH_URL3
1234
+ Origin: AUTH_URL
1206
1235
  }
1207
1236
  });
1208
1237
  } catch {
@@ -1815,7 +1844,6 @@ function appIdFromRepoUrl(url) {
1815
1844
 
1816
1845
  // src/cli/lib/app-registration.ts
1817
1846
  import { parse as parseToml2 } from "smol-toml";
1818
- var DEPLOY_URL = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
1819
1847
  async function mintAppIdentity(appDir, token, opts = {}) {
1820
1848
  const { appId } = await apiFetch(DEPLOY_URL, token, "/api/apps/mint", {
1821
1849
  method: "POST"
@@ -3926,7 +3954,6 @@ function resolvePort(arg) {
3926
3954
  // src/cli/commands/dev.ts
3927
3955
  var DEFAULT_DEV_HOST = "0.0.0.0";
3928
3956
  var READINESS_TIMEOUT_MS = 12e4;
3929
- var DEPLOY_URL2 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
3930
3957
  function noAppDirRefusal(start) {
3931
3958
  const children = findChildApps(start);
3932
3959
  const lines = [`No wrangler.toml found at or above ${start}.`];
@@ -4017,20 +4044,13 @@ var dev_default = defineDeepspaceCommand({
4017
4044
  updatePort: explicitPort
4018
4045
  });
4019
4046
  ensureInstallReady(appDir);
4020
- let token;
4021
- try {
4022
- token = await ensureToken();
4023
- } catch (err) {
4024
- throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
4025
- action: loginAction()
4026
- });
4027
- }
4047
+ const token = await ensureToken();
4028
4048
  let payload;
4029
4049
  try {
4030
4050
  payload = decodeJwtPayload(token);
4031
4051
  } catch {
4032
4052
  throw new Refusal(
4033
- "Malformed session token. Run `npx deepspace auth login`.",
4053
+ "Malformed session token. Run `deepspace auth login` again.",
4034
4054
  "not_authenticated",
4035
4055
  { action: loginAction() }
4036
4056
  );
@@ -4047,7 +4067,7 @@ var dev_default = defineDeepspaceCommand({
4047
4067
  const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
4048
4068
  if (appIdForSecrets) {
4049
4069
  try {
4050
- const refreshed = await refreshSecretsCache(DEPLOY_URL2, token, appIdForSecrets, wranglerEnv);
4070
+ const refreshed = await refreshSecretsCache(DEPLOY_URL, token, appIdForSecrets, wranglerEnv);
4051
4071
  generatedSecretsCache = refreshed.rendered;
4052
4072
  if (refreshed.summary) say(refreshed.summary);
4053
4073
  } catch (err) {
@@ -4561,14 +4581,13 @@ var TestAccountServiceError = class extends Error {
4561
4581
  function serviceError(data, fallback) {
4562
4582
  return new TestAccountServiceError(data.error ?? fallback, data.code);
4563
4583
  }
4564
- var AUTH_URL4 = process.env.DEEPSPACE_AUTH_URL ?? PLATFORM_URLS.auth;
4565
4584
  function sessionCookie() {
4566
4585
  const token = readFileSync12(SESSION_PATH, "utf-8").trim();
4567
4586
  return `${SESSION_COOKIE}=${encodeURIComponent(token)}`;
4568
4587
  }
4569
4588
  async function fetchRemoteTestAccounts() {
4570
- const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
4571
- headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
4589
+ const response = await fetch(`${AUTH_URL}/api/auth/test-accounts`, {
4590
+ headers: { Cookie: sessionCookie(), Origin: AUTH_URL }
4572
4591
  });
4573
4592
  const data = await response.json().catch(() => ({}));
4574
4593
  if (!response.ok || !data.accounts) {
@@ -4577,12 +4596,12 @@ async function fetchRemoteTestAccounts() {
4577
4596
  return data.accounts;
4578
4597
  }
4579
4598
  async function createRemoteTestAccount(input) {
4580
- const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts`, {
4599
+ const response = await fetch(`${AUTH_URL}/api/auth/test-accounts`, {
4581
4600
  method: "POST",
4582
4601
  headers: {
4583
4602
  "Content-Type": "application/json",
4584
4603
  Cookie: sessionCookie(),
4585
- Origin: AUTH_URL4
4604
+ Origin: AUTH_URL
4586
4605
  },
4587
4606
  body: JSON.stringify(input)
4588
4607
  });
@@ -4593,9 +4612,9 @@ async function createRemoteTestAccount(input) {
4593
4612
  return { ...data, label: data.label ?? null };
4594
4613
  }
4595
4614
  async function recoverRemoteTestAccount(id) {
4596
- const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts/${id}/credential`, {
4615
+ const response = await fetch(`${AUTH_URL}/api/auth/test-accounts/${id}/credential`, {
4597
4616
  method: "POST",
4598
- headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
4617
+ headers: { Cookie: sessionCookie(), Origin: AUTH_URL }
4599
4618
  });
4600
4619
  const data = await response.json().catch(() => ({}));
4601
4620
  if (response.status === 404) {
@@ -4619,9 +4638,9 @@ async function recoverRemoteTestAccount(id) {
4619
4638
  };
4620
4639
  }
4621
4640
  async function deleteRemoteTestAccount(id) {
4622
- const response = await fetch(`${AUTH_URL4}/api/auth/test-accounts/${id}`, {
4641
+ const response = await fetch(`${AUTH_URL}/api/auth/test-accounts/${id}`, {
4623
4642
  method: "DELETE",
4624
- headers: { Cookie: sessionCookie(), Origin: AUTH_URL4 }
4643
+ headers: { Cookie: sessionCookie(), Origin: AUTH_URL }
4625
4644
  });
4626
4645
  if (!response.ok) {
4627
4646
  const data = await response.json().catch(() => ({}));
@@ -4630,12 +4649,11 @@ async function deleteRemoteTestAccount(id) {
4630
4649
  }
4631
4650
  async function syncTestAccountStore() {
4632
4651
  const accounts = await fetchRemoteTestAccounts();
4633
- const { removed } = reconcileTestAccountStore(accounts, normalizeTestAccountScope(AUTH_URL4));
4652
+ const { removed } = reconcileTestAccountStore(accounts, normalizeTestAccountScope(AUTH_URL));
4634
4653
  return { accounts, removed };
4635
4654
  }
4636
4655
 
4637
4656
  // src/cli/commands/test.ts
4638
- var DEPLOY_URL3 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
4639
4657
  var PLAYWRIGHT_OUTPUT_DIR = ".deepspace/test-results";
4640
4658
  var DEFAULT_SUITE_SPECS = ["tests/smoke.spec.ts", "tests/api.spec.ts"];
4641
4659
  function specsSkippedByDefaultSuite(appDir) {
@@ -4763,15 +4781,13 @@ var test_default = defineDeepspaceCommand({
4763
4781
  });
4764
4782
  ensureInstallReady(appDir);
4765
4783
  if (suite !== "unit") await ensurePortFree(port, "0.0.0.0");
4766
- let token;
4784
+ const token = await ensureToken();
4767
4785
  let ownerId;
4768
4786
  try {
4769
- token = await ensureToken();
4770
- const payload = decodeJwtPayload(token);
4771
- ownerId = payload.sub;
4772
- } catch (err) {
4787
+ ownerId = decodeJwtPayload(token).sub;
4788
+ } catch {
4773
4789
  throw new Refusal(
4774
- err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.",
4790
+ "Malformed session token. Run `deepspace auth login` again.",
4775
4791
  "not_authenticated",
4776
4792
  { action: loginAction() }
4777
4793
  );
@@ -4780,7 +4796,7 @@ var test_default = defineDeepspaceCommand({
4780
4796
  const appIdForSecrets = await registerForLocalRun(appDir, token, wranglerEnv);
4781
4797
  if (appIdForSecrets) {
4782
4798
  try {
4783
- const refreshed = await refreshSecretsCache(DEPLOY_URL3, token, appIdForSecrets, wranglerEnv);
4799
+ const refreshed = await refreshSecretsCache(DEPLOY_URL, token, appIdForSecrets, wranglerEnv);
4784
4800
  generatedSecretsCache = refreshed.rendered;
4785
4801
  if (refreshed.summary) say(refreshed.summary);
4786
4802
  } catch (err) {
@@ -5732,6 +5748,7 @@ var SECURE_ROOM_BOUNDARIES_MIGRATION_ID = "2026-08-secure-room-boundaries";
5732
5748
  var ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID = "2026-08-action-tools-delete-where";
5733
5749
  var BUILD_INJECTED_APP_ID_MIGRATION_ID = "2026-08-build-injected-app-id";
5734
5750
  var ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID = "2026-08-action-routes-bearer-guard";
5751
+ var FILES_SESSION_COOKIE_READS_MIGRATION_ID = "2026-09-files-session-cookie-reads";
5735
5752
  function validateAppMigrationIds(value) {
5736
5753
  if (!Array.isArray(value)) {
5737
5754
  return { valid: false, reason: "app migrations must be a JSON string array" };
@@ -5789,6 +5806,12 @@ var APP_MIGRATION_GUIDANCE = [
5789
5806
  description: "Refuse action calls without a bearer token and document their trust boundary",
5790
5807
  files: ["src/server/action-routes.ts, when the app has server actions"],
5791
5808
  guidance: "After resolveAuth, read `const authHeader = c.req.header('Authorization') ?? ''`, accept only its `Bearer ` token, and return 401 when absent. Document that X-App-Action bypasses per-record RBAC, so each action must authorize record ownership itself. If the app has no server action route, record this migration as not applicable."
5809
+ },
5810
+ {
5811
+ id: FILES_SESSION_COOKIE_READS_MIGRATION_ID,
5812
+ description: "Let private file URLs render in <img>/<audio>/<video> for the signed-in user",
5813
+ files: ["the app-owned HTTP route file that proxies /api/files/*"],
5814
+ guidance: "In the /api/files/* proxy only, replace `const auth = await resolveAuth(c.req.raw, c.env)` with `const auth = (await resolveAuth(c.req.raw, c.env)) ?? (await resolveSessionReadAuth(c.req.raw, c.env))`, importing resolveSessionReadAuth from 'deepspace/worker'. It identifies same-origin GET/HEAD by the app-origin session cookie and returns null for everything else. Do not add it to resolveAuth, which also gates writes. In the same route, skip the JSON URL rewrite for HEAD: change `if (contentType.includes('application/json'))` to `if (contentType.includes('application/json') && c.req.method !== 'HEAD')`, because a HEAD answer carries the content-type but no body and parsing it would turn every failed media probe into a 500."
5792
5815
  }
5793
5816
  ];
5794
5817
  var APP_MIGRATION_DEFINITIONS = APP_MIGRATION_GUIDANCE.map(({ id, description }) => ({
@@ -6143,7 +6166,6 @@ function normalizeApiError(status3, body) {
6143
6166
  }
6144
6167
 
6145
6168
  // src/cli/commands/deploy/commerce.ts
6146
- var API_URL2 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
6147
6169
  function errorMessage2(error) {
6148
6170
  return error instanceof Error ? error.message : String(error);
6149
6171
  }
@@ -6204,7 +6226,7 @@ Stripe will keep charging them until you cancel. Cancel at the end of their curr
6204
6226
  let stopped = false;
6205
6227
  try {
6206
6228
  while (iteration < maxIterations) {
6207
- const response = await fetch(`${API_URL2}/api/subscriptions/admin-cancel`, {
6229
+ const response = await fetch(`${API_URL}/api/subscriptions/admin-cancel`, {
6208
6230
  method: "POST",
6209
6231
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
6210
6232
  body: JSON.stringify({
@@ -6265,7 +6287,7 @@ async function syncSubscriptionPlans(appDir, appName, token, nonInteractive) {
6265
6287
  const spinner2 = createSpinner();
6266
6288
  spinner2.start("Syncing subscription plans...");
6267
6289
  try {
6268
- const response = await fetch(`${API_URL2}/api/subscriptions/sync`, {
6290
+ const response = await fetch(`${API_URL}/api/subscriptions/sync`, {
6269
6291
  method: "POST",
6270
6292
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
6271
6293
  body: JSON.stringify({ appId: appName, plans })
@@ -6319,7 +6341,7 @@ async function syncOneTimeProducts(appDir, appName, token) {
6319
6341
  const spinner2 = products.length ? createSpinner() : null;
6320
6342
  spinner2?.start("Syncing one-time products...");
6321
6343
  try {
6322
- const response = await fetch(`${API_URL2}/api/charges/products/sync`, {
6344
+ const response = await fetch(`${API_URL}/api/charges/products/sync`, {
6323
6345
  method: "POST",
6324
6346
  headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
6325
6347
  body: JSON.stringify({ appId: appName, products })
@@ -7276,20 +7298,8 @@ async function deployBuiltBundle(options) {
7276
7298
  spinner2.message(`Deploying ${appName}...`);
7277
7299
  let confirmRename = options.rename;
7278
7300
  const bail = async (message, stopLabel = "Deploy failed", code, actionRequired = false, rawAction) => {
7279
- const action = rawAction ? executableAction(rawAction) : void 0;
7280
7301
  if (stopLabel !== null) spinner2.stop(stopLabel);
7281
- p11.cancel(code ? withSlug(message, code) : message);
7282
- if (action) printAction(action);
7283
- if (output.json) {
7284
- output.emitJson({
7285
- ok: false,
7286
- ...actionRequired ? { actionRequired: true } : {},
7287
- error: message,
7288
- ...code ? { code } : {},
7289
- ...action ? { action } : {}
7290
- });
7291
- }
7292
- throw new CliExit(actionRequired ? 2 : 1);
7302
+ return output.die(message, code, { actionRequired, action: rawAction });
7293
7303
  };
7294
7304
  const makeForm = () => {
7295
7305
  const form = new FormData();
@@ -7379,7 +7389,7 @@ async function deployBuiltBundle(options) {
7379
7389
  await bail(
7380
7390
  error instanceof ApiError ? errorMessage5(error) : `Deploy request failed: ${errorMessage5(error)}`,
7381
7391
  "Deploy failed",
7382
- error instanceof ApiError ? error.code : "deploy_request_failed"
7392
+ (error instanceof ApiError ? error.code : void 0) ?? "deploy_request_failed"
7383
7393
  );
7384
7394
  throw error;
7385
7395
  }
@@ -7392,7 +7402,8 @@ async function deployBuiltBundle(options) {
7392
7402
  await bail(renameRefusalMessage(rename2), null, "rename_required");
7393
7403
  }
7394
7404
  const confirmed = await p11.confirm({ message: renamePromptMessage(rename2) });
7395
- if (p11.isCancel(confirmed) || !confirmed) await bail("Deploy cancelled.", null);
7405
+ if (p11.isCancel(confirmed) || !confirmed)
7406
+ await bail("Deploy cancelled.", null, "rename_declined");
7396
7407
  confirmRename = true;
7397
7408
  renamedFrom = rename2.fromHost;
7398
7409
  spinner2.start(`Deploying ${appName}...`);
@@ -7725,7 +7736,6 @@ function readLock(path) {
7725
7736
  }
7726
7737
 
7727
7738
  // src/cli/commands/deploy.ts
7728
- var DEPLOY_URL4 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
7729
7739
  var DEPLOY_TOKEN_MIN_VALIDITY_MS = 10 * 60 * 1e3;
7730
7740
  var POST_DEPLOY_TOKEN_MIN_VALIDITY_MS = 2 * 60 * 1e3;
7731
7741
  var deploy_default = defineCommand3({
@@ -7847,7 +7857,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
7847
7857
  }
7848
7858
  commitScaffoldIfUnborn(appDir, token);
7849
7859
  p12.log.info(`Id: ${appId}`);
7850
- const sourceState = await getAppSource(DEPLOY_URL4, token, appId).catch((error) => {
7860
+ const sourceState = await getAppSource(DEPLOY_URL, token, appId).catch((error) => {
7851
7861
  if (errorCode(error) === "forbidden") {
7852
7862
  output.die(forbiddenDeployMessage(appId, token), "forbidden");
7853
7863
  }
@@ -7859,9 +7869,9 @@ async function runLockedDeploy(args, output, appDir, envName) {
7859
7869
  "app_not_registered"
7860
7870
  );
7861
7871
  }
7862
- await requireDeployCapabilities(DEPLOY_URL4, null, output);
7872
+ await requireDeployCapabilities(DEPLOY_URL, null, output);
7863
7873
  const { configName: secretsConfig } = await loadDeploySecrets({
7864
- deployUrl: DEPLOY_URL4,
7874
+ deployUrl: DEPLOY_URL,
7865
7875
  appDir,
7866
7876
  appId,
7867
7877
  envName,
@@ -7910,7 +7920,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
7910
7920
  }
7911
7921
  const { token: deployToken } = await authenticate(appDir, output, DEPLOY_TOKEN_MIN_VALIDITY_MS);
7912
7922
  const repository = await syncDeployRepository({
7913
- deployUrl: DEPLOY_URL4,
7923
+ deployUrl: DEPLOY_URL,
7914
7924
  appDir,
7915
7925
  appId,
7916
7926
  token: deployToken,
@@ -7920,7 +7930,7 @@ async function runLockedDeploy(args, output, appDir, envName) {
7920
7930
  sourceState
7921
7931
  });
7922
7932
  const body = await deployBuiltBundle({
7923
- deployUrl: DEPLOY_URL4,
7933
+ deployUrl: DEPLOY_URL,
7924
7934
  appDir,
7925
7935
  appId,
7926
7936
  appName,
@@ -8108,7 +8118,6 @@ async function authenticate(appDir, output, minimumValidityMs) {
8108
8118
 
8109
8119
  // src/cli/commands/undeploy.ts
8110
8120
  import * as p13 from "@clack/prompts";
8111
- var DEPLOY_URL5 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
8112
8121
  var undeploy_default = defineDeepspaceCommand({
8113
8122
  meta: {
8114
8123
  name: "undeploy",
@@ -8134,19 +8143,12 @@ var undeploy_default = defineDeepspaceCommand({
8134
8143
  },
8135
8144
  async run({ args }) {
8136
8145
  const envName = typeof args.env === "string" && args.env.trim() ? args.env.trim() : void 0;
8137
- let token;
8138
- try {
8139
- token = await ensureToken();
8140
- } catch (err) {
8141
- throw new Refusal(err instanceof Error ? err.message : String(err), "not_authenticated", {
8142
- action: loginAction()
8143
- });
8144
- }
8146
+ const token = await ensureToken();
8145
8147
  let appId;
8146
8148
  let label;
8147
8149
  const positional = typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
8148
8150
  if (positional) {
8149
- appId = await resolveAppSelector(DEPLOY_URL5, token, positional);
8151
+ appId = await resolveAppSelector(DEPLOY_URL, token, positional);
8150
8152
  label = positional;
8151
8153
  } else if (hasWranglerConfig(process.cwd())) {
8152
8154
  appId = readAppId(process.cwd(), envName) ?? void 0;
@@ -8161,7 +8163,7 @@ var undeploy_default = defineDeepspaceCommand({
8161
8163
  }
8162
8164
  const target2 = label && label !== appId ? `${label} (${appId})` : appId;
8163
8165
  try {
8164
- const mine = await listApps(DEPLOY_URL5, token);
8166
+ const mine = await listApps(DEPLOY_URL, token);
8165
8167
  const entry = mine.find((app2) => app2.appId === appId);
8166
8168
  if (entry?.role === "collaborator") {
8167
8169
  throw new Refusal(
@@ -8185,7 +8187,7 @@ var undeploy_default = defineDeepspaceCommand({
8185
8187
  if (!args.json) p13.intro(`Undeploying ${target2}`);
8186
8188
  const s = args.json ? null : createSpinner();
8187
8189
  s?.start("Removing...");
8188
- const res = await fetch(`${DEPLOY_URL5}/api/deploy/${appId}`, {
8190
+ const res = await fetch(`${DEPLOY_URL}/api/deploy/${appId}`, {
8189
8191
  method: "DELETE",
8190
8192
  headers: { Authorization: `Bearer ${token}` }
8191
8193
  });
@@ -8228,19 +8230,10 @@ var undeploy_default = defineDeepspaceCommand({
8228
8230
  });
8229
8231
 
8230
8232
  // src/cli/commands/whoami.ts
8231
- var isNetworkError = (err) => err instanceof TypeError || err instanceof Error && /fetch failed|ENOTFOUND|ECONNREFUSED|ETIMEDOUT|EAI_AGAIN|getaddrinfo|network/i.test(err.message);
8232
8233
  var whoami_default = defineDeepspaceCommand({
8233
8234
  meta: { name: "whoami", description: "Show the currently logged-in user" },
8234
8235
  async run({ args }) {
8235
- let jwt;
8236
- try {
8237
- jwt = await ensureToken();
8238
- } catch (err) {
8239
- const msg = err instanceof Error ? err.message : "Not logged in. Run `deepspace auth login` first.";
8240
- throw isNetworkError(err) ? new Refusal(msg, "network_error") : new Refusal(msg, "not_authenticated", {
8241
- action: loginAction()
8242
- });
8243
- }
8236
+ const jwt = await ensureToken();
8244
8237
  let payload;
8245
8238
  try {
8246
8239
  payload = decodeJwtPayload(jwt);
@@ -8280,7 +8273,6 @@ var whoami_default = defineDeepspaceCommand({
8280
8273
  });
8281
8274
 
8282
8275
  // src/cli/commands/apps.ts
8283
- var DEPLOY_URL6 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
8284
8276
  var apps_default = defineDeepspaceCommand({
8285
8277
  meta: {
8286
8278
  name: "apps",
@@ -8288,7 +8280,7 @@ var apps_default = defineDeepspaceCommand({
8288
8280
  },
8289
8281
  async run({ args }) {
8290
8282
  const token = await ensureToken();
8291
- const { apps, pendingTransfers } = await listAppsPage(DEPLOY_URL6, token);
8283
+ const { apps, pendingTransfers } = await listAppsPage(DEPLOY_URL, token);
8292
8284
  if (!args.json) {
8293
8285
  if (!apps.length && !pendingTransfers.length) {
8294
8286
  console.log("No apps yet. Create one with `npx create-deepspace <name>` and `deepspace deploy`.");
@@ -8359,7 +8351,6 @@ function logEventText(e) {
8359
8351
  var MAX_LOG_TEXT_LENGTH = 8 * 1024;
8360
8352
 
8361
8353
  // src/cli/commands/logs.ts
8362
- var DEPLOY_URL7 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
8363
8354
  var RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
8364
8355
  var DEFAULT_WINDOW_MS = 15 * 60 * 1e3;
8365
8356
  var MIN_POLL_MS = 2500;
@@ -8520,7 +8511,7 @@ var logs_default = defineCommand4({
8520
8511
  const envArg = args.env;
8521
8512
  assertAppTargetResolvable(args.app, { wranglerEnv: envArg });
8522
8513
  const token = await ensureToken();
8523
- const appId = await resolveAppTarget(DEPLOY_URL7, token, args.app, { wranglerEnv: envArg });
8514
+ const appId = await resolveAppTarget(DEPLOY_URL, token, args.app, { wranglerEnv: envArg });
8524
8515
  if (args.level && !LOG_LEVELS.includes(args.level)) {
8525
8516
  throw new InputError(
8526
8517
  `Invalid --level "${args.level}". Use: ${LOG_LEVELS.join(", ")}`,
@@ -8539,7 +8530,7 @@ var logs_default = defineCommand4({
8539
8530
  }
8540
8531
  const initialSince = args.since ? parseSince(args.since) : Date.now() - DEFAULT_WINDOW_MS;
8541
8532
  const windowLabel = args.since?.trim() || "15m";
8542
- const registryRow = (await listApps(DEPLOY_URL7, token)).find((app2) => app2.appId === appId);
8533
+ const registryRow = (await listApps(DEPLOY_URL, token)).find((app2) => app2.appId === appId);
8543
8534
  if (registryRow && registryRow.deployedAt === null) {
8544
8535
  const appDir = args.app === void 0 ? findAppDir() : null;
8545
8536
  throw new Refusal(
@@ -8561,7 +8552,7 @@ var logs_default = defineCommand4({
8561
8552
  if (args.level) params.set("level", args.level);
8562
8553
  if (args.search) params.set("search", args.search);
8563
8554
  const path = `/api/apps/${appId}/logs?${params}`;
8564
- return signal ? apiFetch(DEPLOY_URL7, token2, path, { signal }) : apiFetchReadWithRetry(DEPLOY_URL7, token2, path);
8555
+ return signal ? apiFetch(DEPLOY_URL, token2, path, { signal }) : apiFetchReadWithRetry(DEPLOY_URL, token2, path);
8565
8556
  };
8566
8557
  const print = (events) => {
8567
8558
  for (const e of events) {
@@ -8684,7 +8675,6 @@ var logs_default = defineCommand4({
8684
8675
  });
8685
8676
 
8686
8677
  // src/cli/commands/usage.ts
8687
- var API_URL3 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
8688
8678
  function formatCredits(value) {
8689
8679
  if (value > 0 && value < 1) return "<1";
8690
8680
  if (value < 10) return value.toFixed(1).replace(/\.0$/, "");
@@ -8750,7 +8740,7 @@ var usage_default = defineDeepspaceCommand({
8750
8740
  },
8751
8741
  async run({ args }) {
8752
8742
  const token = await ensureToken();
8753
- const summary = await apiFetch(API_URL3, token, "/api/usage/summary");
8743
+ const summary = await apiFetch(API_URL, token, "/api/usage/summary");
8754
8744
  if (!args.json) console.log(renderSummary(summary));
8755
8745
  return { data: { scope: "account", ...summary } };
8756
8746
  }
@@ -9750,9 +9740,7 @@ Create one with: deepspace app create <name>`,
9750
9740
 
9751
9741
  // src/cli/commands/domain.ts
9752
9742
  import { defineCommand as defineCommand5 } from "citty";
9753
- var API_URL4 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
9754
- var DEPLOY_URL8 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
9755
- var api = (token, path, init) => apiFetch(API_URL4, token, path, init);
9743
+ var api = (token, path, init) => apiFetch(API_URL, token, path, init);
9756
9744
  function scrubInternal(value) {
9757
9745
  if (Array.isArray(value)) return value.map(scrubInternal);
9758
9746
  if (value && typeof value === "object") {
@@ -9822,7 +9810,7 @@ var buy = defineDeepspaceCommand({
9822
9810
  async run({ args }) {
9823
9811
  const domain = String(args.domain);
9824
9812
  const token = await ensureToken();
9825
- const appId = await resolveAppTarget(DEPLOY_URL8, token, args.app);
9813
+ const appId = await resolveAppTarget(DEPLOY_URL, token, args.app);
9826
9814
  const priceCheck = await api(token, "/api/domains/check", {
9827
9815
  method: "POST",
9828
9816
  body: JSON.stringify({ domains: [domain] })
@@ -9967,7 +9955,7 @@ var attach = defineDeepspaceCommand({
9967
9955
  const domain = String(args.domain);
9968
9956
  const token = await ensureToken();
9969
9957
  const targetAppId = await resolveAppTarget(
9970
- DEPLOY_URL8,
9958
+ DEPLOY_URL,
9971
9959
  token,
9972
9960
  args.app
9973
9961
  );
@@ -10274,11 +10262,9 @@ async function downloadAppFile(baseUrl, token, appId, key, destination) {
10274
10262
  }
10275
10263
 
10276
10264
  // src/cli/commands/app-files.ts
10277
- var DEPLOY_URL9 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
10278
- var PLATFORM_URL = process.env.DEEPSPACE_PLATFORM_URL ?? PLATFORM_URLS.platform;
10279
10265
  async function target(app2) {
10280
10266
  const token = await ensureToken();
10281
- const appId = await resolveAppTarget(DEPLOY_URL9, token, app2);
10267
+ const appId = await resolveAppTarget(DEPLOY_URL, token, app2);
10282
10268
  return { token, appId };
10283
10269
  }
10284
10270
  var MAX_LIST_LIMIT = 1e3;
@@ -10464,12 +10450,10 @@ function isTestAccountEmail(email) {
10464
10450
  }
10465
10451
 
10466
10452
  // src/cli/commands/collaborators.ts
10467
- var API_URL5 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
10468
- var DEPLOY_URL10 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
10469
10453
  var COLLABORATOR_GRANTS = ["deploy", "secrets:read", "secrets:write"];
10470
10454
  var COLLABORATOR_GRANT_SENTENCE = `grants ${COLLABORATOR_GRANTS.join(", ")} \u2014 they can deploy the app AND read and change every app secret in plaintext; they cannot undeploy or transfer it`;
10471
10455
  function api2(token, path, init) {
10472
- return apiFetch(API_URL5, token, path, init);
10456
+ return apiFetch(API_URL, token, path, init);
10473
10457
  }
10474
10458
  var list4 = defineDeepspaceCommand({
10475
10459
  meta: { name: "list", description: "List collaborators on your app" },
@@ -10478,7 +10462,7 @@ var list4 = defineDeepspaceCommand({
10478
10462
  },
10479
10463
  async run({ args }) {
10480
10464
  const token = await ensureToken();
10481
- const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
10465
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10482
10466
  const { owner, collaborators, pending = [] } = await api2(token, `/api/app-collaborators/${encodeURIComponent(app2)}`);
10483
10467
  if (!args.json && owner) console.log(`OWNER: ${owner.emailDisplay}`);
10484
10468
  if (!collaborators.length && !pending.length) {
@@ -10522,7 +10506,7 @@ var add = defineDeepspaceCommand({
10522
10506
  async run({ args }) {
10523
10507
  const email = String(args.email);
10524
10508
  const token = await ensureToken();
10525
- const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
10509
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10526
10510
  if (isTestAccountEmail(email)) {
10527
10511
  throw new Refusal(
10528
10512
  "Test accounts (@deepspace.test) cannot be added as collaborators. Use a real DeepSpace account.",
@@ -10569,7 +10553,7 @@ var remove = defineDeepspaceCommand({
10569
10553
  async run({ args }) {
10570
10554
  const email = String(args.email);
10571
10555
  const token = await ensureToken();
10572
- const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
10556
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10573
10557
  const { collaborators } = await api2(
10574
10558
  token,
10575
10559
  `/api/app-collaborators/${encodeURIComponent(app2)}`
@@ -10590,7 +10574,7 @@ var remove = defineDeepspaceCommand({
10590
10574
  return { data: { removed: found } };
10591
10575
  }
10592
10576
  });
10593
- var cancel3 = defineDeepspaceCommand({
10577
+ var cancel2 = defineDeepspaceCommand({
10594
10578
  meta: { name: "cancel", description: "Cancel a pending (un-accepted) email invite" },
10595
10579
  args: {
10596
10580
  email: { type: "positional", description: "Invited email", required: true },
@@ -10599,7 +10583,7 @@ var cancel3 = defineDeepspaceCommand({
10599
10583
  async run({ args }) {
10600
10584
  const email = String(args.email);
10601
10585
  const token = await ensureToken();
10602
- const app2 = await resolveAppTarget(DEPLOY_URL10, token, args.app);
10586
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10603
10587
  const { pending = [] } = await api2(
10604
10588
  token,
10605
10589
  `/api/app-collaborators/${encodeURIComponent(app2)}`
@@ -10672,14 +10656,12 @@ var accept = defineDeepspaceCommand({
10672
10656
  });
10673
10657
  var collaborators_default = defineCommand7({
10674
10658
  meta: { name: "collaborators", description: "Manage who can deploy your app" },
10675
- subCommands: { list: list4, add, remove, cancel: cancel3, invites, accept }
10659
+ subCommands: { list: list4, add, remove, cancel: cancel2, invites, accept }
10676
10660
  });
10677
10661
 
10678
10662
  // src/cli/commands/transfer.ts
10679
10663
  import { defineCommand as defineCommand8 } from "citty";
10680
10664
  import * as p14 from "@clack/prompts";
10681
- var API_URL6 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
10682
- var DEPLOY_URL11 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
10683
10665
  var offer = defineDeepspaceCommand({
10684
10666
  meta: { name: "offer", description: "Offer this app to another DeepSpace user" },
10685
10667
  args: {
@@ -10693,9 +10675,9 @@ var offer = defineDeepspaceCommand({
10693
10675
  async run({ args }) {
10694
10676
  const email = String(args.email);
10695
10677
  const token = await ensureToken();
10696
- const app2 = await resolveAppTarget(DEPLOY_URL11, token, args.app);
10678
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10697
10679
  const pending = await apiFetch(
10698
- API_URL6,
10680
+ API_URL,
10699
10681
  token,
10700
10682
  `/api/app-transfers/${encodeURIComponent(app2)}`
10701
10683
  );
@@ -10715,7 +10697,7 @@ var offer = defineDeepspaceCommand({
10715
10697
  }
10716
10698
  }
10717
10699
  const { expiresAt } = await apiFetch(
10718
- API_URL6,
10700
+ API_URL,
10719
10701
  token,
10720
10702
  `/api/app-transfers/${encodeURIComponent(app2)}`,
10721
10703
  { method: "POST", body: JSON.stringify({ email }) }
@@ -10753,8 +10735,8 @@ var status2 = defineDeepspaceCommand({
10753
10735
  },
10754
10736
  async run({ args }) {
10755
10737
  const token = await ensureToken();
10756
- const app2 = await resolveAppTarget(DEPLOY_URL11, token, args.app);
10757
- const { transfer } = await apiFetch(API_URL6, token, `/api/app-transfers/${encodeURIComponent(app2)}`);
10738
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10739
+ const { transfer } = await apiFetch(API_URL, token, `/api/app-transfers/${encodeURIComponent(app2)}`);
10758
10740
  if (!transfer) {
10759
10741
  if (!args.json) console.log(`No pending transfer for ${app2}.`);
10760
10742
  return { data: { app: app2, transfer: null } };
@@ -10782,7 +10764,7 @@ var accept2 = defineDeepspaceCommand({
10782
10764
  const msg = err instanceof Error ? err.message : String(err);
10783
10765
  throw new Refusal(msg, msg.startsWith("No app id") ? "not_in_app_repo" : "invalid_app");
10784
10766
  }
10785
- const { replayed, acceptedAt, inheritedCollaborators } = await apiFetch(DEPLOY_URL11, token, `/api/apps/${encodeURIComponent(app2)}/transfer/accept`, {
10767
+ const { replayed, acceptedAt, inheritedCollaborators } = await apiFetch(DEPLOY_URL, token, `/api/apps/${encodeURIComponent(app2)}/transfer/accept`, {
10786
10768
  method: "POST"
10787
10769
  });
10788
10770
  if (!args.json) {
@@ -10810,31 +10792,28 @@ var accept2 = defineDeepspaceCommand({
10810
10792
  };
10811
10793
  }
10812
10794
  });
10813
- var cancel4 = defineDeepspaceCommand({
10795
+ var cancel3 = defineDeepspaceCommand({
10814
10796
  meta: { name: "cancel", description: "Cancel/decline the pending offer (either party)" },
10815
10797
  args: {
10816
10798
  app: { type: "string", alias: "a", description: "App id or name (defaults to ./wrangler.toml)" }
10817
10799
  },
10818
10800
  async run({ args }) {
10819
10801
  const token = await ensureToken();
10820
- const app2 = await resolveAppTarget(DEPLOY_URL11, token, args.app);
10821
- await apiFetch(API_URL6, token, `/api/app-transfers/${encodeURIComponent(app2)}`, { method: "DELETE" });
10802
+ const app2 = await resolveAppTarget(DEPLOY_URL, token, args.app);
10803
+ await apiFetch(API_URL, token, `/api/app-transfers/${encodeURIComponent(app2)}`, { method: "DELETE" });
10822
10804
  if (!args.json) console.log(`\u2713 Transfer offer for ${app2} cancelled.`);
10823
10805
  return { data: { app: app2, cancelled: true } };
10824
10806
  }
10825
10807
  });
10826
10808
  var transfer_default = defineCommand8({
10827
10809
  meta: { name: "transfer", description: "Transfer app ownership to another user" },
10828
- subCommands: { offer, status: status2, accept: accept2, cancel: cancel4 }
10810
+ subCommands: { offer, status: status2, accept: accept2, cancel: cancel3 }
10829
10811
  });
10830
10812
 
10831
10813
  // src/cli/commands/integrations.ts
10832
10814
  import { defineCommand as defineCommand9 } from "citty";
10833
-
10834
- // src/cli/commands/_invoke-impl.ts
10835
10815
  import { readFileSync as readFileSync21 } from "fs";
10836
10816
  import * as p15 from "@clack/prompts";
10837
- var API_URL7 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
10838
10817
  var DEFAULT_TIMEOUT_MS = 12e4;
10839
10818
  function parseTarget(target2) {
10840
10819
  if (!target2 || typeof target2 !== "string") {
@@ -10899,7 +10878,7 @@ async function resolveBody(opts) {
10899
10878
  }
10900
10879
  async function fetchCatalog(opts = {}) {
10901
10880
  try {
10902
- return await fetchIntegrationCatalog(API_URL7, { summary: opts.summary });
10881
+ return await fetchIntegrationCatalog(API_URL, { summary: opts.summary });
10903
10882
  } catch (err) {
10904
10883
  if (err instanceof ApiError) throw new Refusal(err.message, err.code ?? "catalog_unavailable");
10905
10884
  throw err;
@@ -11060,21 +11039,13 @@ async function runInvoke(args) {
11060
11039
  }
11061
11040
  }
11062
11041
  }
11063
- let jwt;
11064
- try {
11065
- jwt = await ensureToken();
11066
- } catch (err) {
11067
- const msg = err instanceof Error ? err.message : String(err);
11068
- throw new Refusal(msg, "not_authenticated", {
11069
- action: loginAction()
11070
- });
11071
- }
11042
+ const jwt = await ensureToken();
11072
11043
  const controller = new AbortController();
11073
11044
  const timer = setTimeout(() => controller.abort(), timeoutMs);
11074
11045
  const startedAt = Date.now();
11075
11046
  let res;
11076
11047
  try {
11077
- res = await fetch(`${API_URL7}/api/integrations/${integration}/${endpoint}`, {
11048
+ res = await fetch(`${API_URL}/api/integrations/${integration}/${endpoint}`, {
11078
11049
  method: "POST",
11079
11050
  headers: {
11080
11051
  "Content-Type": "application/json",
@@ -11126,8 +11097,6 @@ async function runInvoke(args) {
11126
11097
  extra: rest
11127
11098
  });
11128
11099
  }
11129
-
11130
- // src/cli/commands/integrations.ts
11131
11100
  var list5 = defineDeepspaceCommand({
11132
11101
  meta: {
11133
11102
  name: "list",
@@ -11628,7 +11597,6 @@ import { existsSync as existsSync25, readFileSync as readFileSync22 } from "fs";
11628
11597
  import { dirname as dirname11, join as join24 } from "path";
11629
11598
  import { fileURLToPath as fileURLToPath2 } from "url";
11630
11599
  import { release } from "os";
11631
- var API_URL8 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
11632
11600
  var TYPES = ["bug", "feature", "other"];
11633
11601
  var TYPE_LABELS = {
11634
11602
  bug: "Bug report",
@@ -11638,7 +11606,7 @@ var TYPE_LABELS = {
11638
11606
  var MAX_TITLE_LEN = 200;
11639
11607
  var MAX_BODY_LEN = 1e4;
11640
11608
  var MAX_CONTEXT_LEN = 200;
11641
- var api3 = (token, path, init) => apiFetch(API_URL8, token, path, init);
11609
+ var api3 = (token, path, init) => apiFetch(API_URL, token, path, init);
11642
11610
  function normalizeType(raw) {
11643
11611
  const value = (raw ?? "bug").toLowerCase();
11644
11612
  if (TYPES.includes(value)) return value;
@@ -11821,16 +11789,7 @@ Context: deepspace ${payload.cliVersion} \xB7 ${payload.nodeVersion} \xB7 ${payl
11821
11789
  return { data: { submitted: false, cancelled: true } };
11822
11790
  }
11823
11791
  }
11824
- let token;
11825
- try {
11826
- token = await ensureToken();
11827
- } catch (err) {
11828
- throw new Refusal(
11829
- err.message ?? "Not signed in. Run `deepspace auth login`.",
11830
- "not_authenticated",
11831
- { action: loginAction() }
11832
- );
11833
- }
11792
+ const token = await ensureToken();
11834
11793
  const result = await api3(token, "/api/feedback", {
11835
11794
  method: "POST",
11836
11795
  body: JSON.stringify(payload)
@@ -11882,7 +11841,6 @@ function parseCursorArg(raw) {
11882
11841
  }
11883
11842
 
11884
11843
  // src/cli/commands/secrets.ts
11885
- var DEPLOY_URL12 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
11886
11844
  var COMMON_ARGS = {
11887
11845
  app: {
11888
11846
  type: "string",
@@ -11914,7 +11872,7 @@ async function resolveTarget(args, opts = {}) {
11914
11872
  const { wranglerEnv } = parseWranglerEnvArg(args.env);
11915
11873
  const configName = validateConfigName(args.config?.trim() || defaultConfigNameForEnv(wranglerEnv));
11916
11874
  const token = await ensureToken();
11917
- const appId = await resolveAppTarget(DEPLOY_URL12, token, args.app, { wranglerEnv, register });
11875
+ const appId = await resolveAppTarget(DEPLOY_URL, token, args.app, { wranglerEnv, register });
11918
11876
  return { appId, configName, token };
11919
11877
  }
11920
11878
  function ok(json, data, human) {
@@ -11943,7 +11901,7 @@ var list6 = defineCommand11({
11943
11901
  },
11944
11902
  async run({ args }) {
11945
11903
  const t = await resolveTarget(args);
11946
- const { secrets } = await listSecrets(DEPLOY_URL12, t.token, t.appId, t.configName);
11904
+ const { secrets } = await listSecrets(DEPLOY_URL, t.token, t.appId, t.configName);
11947
11905
  if (args.json) {
11948
11906
  console.log(JSON.stringify({ ok: true, appId: t.appId, config: t.configName, secrets }));
11949
11907
  return;
@@ -12023,9 +11981,9 @@ var set = defineCommand11({
12023
11981
  }
12024
11982
  if (Object.keys(secrets).length === 1) {
12025
11983
  const [[k, v]] = Object.entries(secrets);
12026
- await setSecret(DEPLOY_URL12, t.token, t.appId, t.configName, k, v);
11984
+ await setSecret(DEPLOY_URL, t.token, t.appId, t.configName, k, v);
12027
11985
  } else {
12028
- await uploadSecrets(DEPLOY_URL12, t.token, t.appId, t.configName, secrets, false);
11986
+ await uploadSecrets(DEPLOY_URL, t.token, t.appId, t.configName, secrets, false);
12029
11987
  }
12030
11988
  const n = Object.keys(secrets).length;
12031
11989
  ok(
@@ -12058,11 +12016,11 @@ var get2 = defineCommand11({
12058
12016
  const t = await resolveTarget(args);
12059
12017
  const key = validateSecretName(args.key);
12060
12018
  if (args.plain) {
12061
- const { value } = await getSecretPlain(DEPLOY_URL12, t.token, t.appId, t.configName, key);
12019
+ const { value } = await getSecretPlain(DEPLOY_URL, t.token, t.appId, t.configName, key);
12062
12020
  process.stdout.write(process.stdout.isTTY ? value + "\n" : value);
12063
12021
  return;
12064
12022
  }
12065
- const { secrets } = await listSecrets(DEPLOY_URL12, t.token, t.appId, t.configName);
12023
+ const { secrets } = await listSecrets(DEPLOY_URL, t.token, t.appId, t.configName);
12066
12024
  const item = secrets.find((s) => s.key === key);
12067
12025
  if (!item)
12068
12026
  throw new InputError(`Secret "${key}" not found in ${t.configName}`, "secret_not_found");
@@ -12093,7 +12051,7 @@ var del2 = defineCommand11({
12093
12051
  for (const key of keys) {
12094
12052
  const name = validateSecretName(key);
12095
12053
  try {
12096
- const result = await deleteSecret(DEPLOY_URL12, t.token, t.appId, t.configName, name);
12054
+ const result = await deleteSecret(DEPLOY_URL, t.token, t.appId, t.configName, name);
12097
12055
  if (result.deleted === false) absent++;
12098
12056
  else deleted++;
12099
12057
  } catch (err) {
@@ -12135,7 +12093,7 @@ var upload = defineCommand11({
12135
12093
  const secrets = parseSecretsUpload(await readUploadSource(String(args.file)));
12136
12094
  if (Object.keys(secrets).length === 0)
12137
12095
  throw new InputError("No secrets found in the input.", "empty_input");
12138
- await uploadSecrets(DEPLOY_URL12, t.token, t.appId, t.configName, secrets, args.replace);
12096
+ await uploadSecrets(DEPLOY_URL, t.token, t.appId, t.configName, secrets, args.replace);
12139
12097
  const uploaded = Object.keys(secrets);
12140
12098
  ok(
12141
12099
  args.json === true,
@@ -12210,7 +12168,7 @@ var download = defineCommand11({
12210
12168
  "invalid_format"
12211
12169
  );
12212
12170
  }
12213
- const { secrets } = await fetchSecretsValues(DEPLOY_URL12, t.token, t.appId, t.configName);
12171
+ const { secrets } = await fetchSecretsValues(DEPLOY_URL, t.token, t.appId, t.configName);
12214
12172
  process.stdout.write(formatSecretsDownload(secrets, format));
12215
12173
  }
12216
12174
  });
@@ -12219,7 +12177,7 @@ var configsList = defineCommand11({
12219
12177
  args: { ...COMMON_ARGS },
12220
12178
  async run({ args }) {
12221
12179
  const t = await resolveTarget(args);
12222
- const { configs: configs2 } = await listConfigs(DEPLOY_URL12, t.token, t.appId);
12180
+ const { configs: configs2 } = await listConfigs(DEPLOY_URL, t.token, t.appId);
12223
12181
  ok(args.json === true, { appId: t.appId, configs: configs2 }, () => {
12224
12182
  if (configs2.length === 0) {
12225
12183
  console.log("No configs yet \u2014 the first `secrets set` creates one.");
@@ -12242,7 +12200,7 @@ var configsCreate = defineCommand11({
12242
12200
  const t = await resolveTarget(args, { register: true });
12243
12201
  const name = validateConfigName(args.name);
12244
12202
  const copyFrom = args["copy-from"] || void 0;
12245
- const { configs: configs2 } = await listConfigs(DEPLOY_URL12, t.token, t.appId);
12203
+ const { configs: configs2 } = await listConfigs(DEPLOY_URL, t.token, t.appId);
12246
12204
  if (configs2.some((c) => c.name === name)) {
12247
12205
  if (copyFrom) {
12248
12206
  throw new InputError(
@@ -12257,7 +12215,7 @@ var configsCreate = defineCommand11({
12257
12215
  );
12258
12216
  return;
12259
12217
  }
12260
- await createConfig(DEPLOY_URL12, t.token, t.appId, name, copyFrom);
12218
+ await createConfig(DEPLOY_URL, t.token, t.appId, name, copyFrom);
12261
12219
  ok(
12262
12220
  args.json === true,
12263
12221
  { appId: t.appId, config: name, created: true, ...copyFrom ? { copyFrom } : {} },
@@ -12286,7 +12244,7 @@ var configsDelete = defineCommand11({
12286
12244
  json: args.json === true,
12287
12245
  message: `Deleting config ${name} removes every secret in it permanently.`,
12288
12246
  prompt: async () => {
12289
- const { secrets } = await listSecrets(DEPLOY_URL12, t.token, t.appId, name);
12247
+ const { secrets } = await listSecrets(DEPLOY_URL, t.token, t.appId, name);
12290
12248
  count = secrets.length;
12291
12249
  const detail = count === 0 ? `Config ${name} is empty.` : `Config ${name} holds ${count} secret${count === 1 ? "" : "s"}: ${secrets.map((secret) => secret.key).slice(0, 8).join(", ")}${count > 8 ? `, \u2026` : ""}.`;
12292
12250
  return `${detail} Deleting it removes ${count === 1 ? "that secret" : "them all"} permanently.`;
@@ -12296,11 +12254,11 @@ var configsDelete = defineCommand11({
12296
12254
  });
12297
12255
  if (count === null) {
12298
12256
  try {
12299
- count = (await listSecrets(DEPLOY_URL12, t.token, t.appId, name)).secrets.length;
12257
+ count = (await listSecrets(DEPLOY_URL, t.token, t.appId, name)).secrets.length;
12300
12258
  } catch {
12301
12259
  }
12302
12260
  }
12303
- await deleteConfig(DEPLOY_URL12, t.token, t.appId, name);
12261
+ await deleteConfig(DEPLOY_URL, t.token, t.appId, name);
12304
12262
  ok(
12305
12263
  args.json === true,
12306
12264
  { appId: t.appId, config: name, deleted: true, secretsDeleted: count },
@@ -12328,7 +12286,6 @@ var secrets_default = defineCommand11({
12328
12286
  });
12329
12287
 
12330
12288
  // src/cli/commands/init.ts
12331
- var DEPLOY_URL13 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
12332
12289
  var init_default = defineDeepspaceCommand({
12333
12290
  meta: {
12334
12291
  name: "init",
@@ -12369,7 +12326,7 @@ var init_default = defineDeepspaceCommand({
12369
12326
  const token2 = await ensureToken();
12370
12327
  let state;
12371
12328
  try {
12372
- state = await getAppSource(DEPLOY_URL13, token2, existing);
12329
+ state = await getAppSource(DEPLOY_URL, token2, existing);
12373
12330
  } catch (error) {
12374
12331
  if (error instanceof ApiError && error.code === "forbidden") {
12375
12332
  throw new Refusal(
@@ -13554,7 +13511,6 @@ var clone_default = defineDeepspaceCommand({
13554
13511
  import * as p21 from "@clack/prompts";
13555
13512
 
13556
13513
  // src/cli/lib/actor-labels.ts
13557
- var API_URL9 = process.env.DEEPSPACE_API_URL ?? PLATFORM_URLS.api;
13558
13514
  async function actorLabels(token, appId) {
13559
13515
  const labels = /* @__PURE__ */ new Map();
13560
13516
  try {
@@ -13563,7 +13519,7 @@ async function actorLabels(token, appId) {
13563
13519
  } catch {
13564
13520
  }
13565
13521
  try {
13566
- const { collaborators } = await apiFetch(API_URL9, token, `/api/app-collaborators/${encodeURIComponent(appId)}`);
13522
+ const { collaborators } = await apiFetch(API_URL, token, `/api/app-collaborators/${encodeURIComponent(appId)}`);
13567
13523
  for (const c of collaborators) {
13568
13524
  if (!labels.has(c.userId)) labels.set(c.userId, c.emailDisplay);
13569
13525
  }
@@ -13573,7 +13529,6 @@ async function actorLabels(token, appId) {
13573
13529
  }
13574
13530
 
13575
13531
  // src/cli/commands/releases.ts
13576
- var DEPLOY_URL14 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
13577
13532
  var releases_default = defineDeepspaceCommand({
13578
13533
  meta: {
13579
13534
  name: "releases",
@@ -13608,8 +13563,8 @@ var releases_default = defineDeepspaceCommand({
13608
13563
  const spinner2 = args.json ? null : createSpinner();
13609
13564
  spinner2?.start("Loading release history\u2026");
13610
13565
  const token = await ensureToken();
13611
- const appId = await resolveAppTarget(DEPLOY_URL14, token, appArg, { wranglerEnv: envArg });
13612
- const { releases } = await repoApi(DEPLOY_URL14, token, appId).listReleases(limit);
13566
+ const appId = await resolveAppTarget(DEPLOY_URL, token, appArg, { wranglerEnv: envArg });
13567
+ const { releases } = await repoApi(DEPLOY_URL, token, appId).listReleases(limit);
13613
13568
  spinner2?.stop(`Loaded ${releases.length} ${releases.length === 1 ? "release" : "releases"}.`);
13614
13569
  if (!args.json) {
13615
13570
  if (releases.length === 0) {
@@ -13644,7 +13599,6 @@ Retry in a moment, or re-run with --allow-do-deletion to accept the risk.`,
13644
13599
  "do_guard_unavailable"
13645
13600
  );
13646
13601
  }
13647
- var DEPLOY_URL15 = process.env.DEEPSPACE_DEPLOY_URL ?? PLATFORM_URLS.deploy;
13648
13602
  function pickPreviousRelease(releases) {
13649
13603
  if (releases.length === 0) {
13650
13604
  return { error: "No releases recorded yet \u2014 nothing to roll back to.", code: "no_releases" };
@@ -13712,8 +13666,8 @@ var rollback_default = defineDeepspaceCommand({
13712
13666
  const spinner2 = args.json ? null : createSpinner();
13713
13667
  spinner2?.start("Preparing rollback\u2026");
13714
13668
  const token = await ensureToken();
13715
- const appId = await resolveAppTarget(DEPLOY_URL15, token, appArg, { wranglerEnv: envArg });
13716
- const api4 = repoApi(DEPLOY_URL15, token, appId);
13669
+ const appId = await resolveAppTarget(DEPLOY_URL, token, appArg, { wranglerEnv: envArg });
13670
+ const api4 = repoApi(DEPLOY_URL, token, appId);
13717
13671
  let releaseId = args.release ? String(args.release).trim() : "";
13718
13672
  if (!releaseId) {
13719
13673
  const { releases } = await api4.listReleases(2);
@@ -13732,7 +13686,7 @@ var rollback_default = defineDeepspaceCommand({
13732
13686
  spinner2?.start(`Rolling back to ${releaseId}\u2026`);
13733
13687
  let result;
13734
13688
  try {
13735
- result = await apiFetch(DEPLOY_URL15, token, `/api/deploy/${appId}/rollback`, {
13689
+ result = await apiFetch(DEPLOY_URL, token, `/api/deploy/${appId}/rollback`, {
13736
13690
  method: "POST",
13737
13691
  body: JSON.stringify({
13738
13692
  releaseId,
@@ -15991,7 +15945,7 @@ import { join as join28, resolve as resolve22 } from "path";
15991
15945
  // package.json
15992
15946
  var package_default = {
15993
15947
  name: "deepspace",
15994
- version: "0.30.2",
15948
+ version: "0.31.1",
15995
15949
  engines: {
15996
15950
  node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
15997
15951
  },