deepspace 0.30.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -706,6 +706,9 @@ var INVALID_URLS = {
706
706
  function appDomainForEnv(env) {
707
707
  return env === "production" ? "app.space" : env === "staging" ? "spacestest.com" : null;
708
708
  }
709
+ function platformDomainForEnv(env) {
710
+ return env === "production" ? "deep.space" : env === "staging" ? "deepspacesites.com" : null;
711
+ }
709
712
  var PLATFORM_URLS = DEEPSPACE_ENV === "production" ? PROD_URLS : DEEPSPACE_ENV === "staging" ? STAGING_URLS : INVALID_URLS;
710
713
  var PLANE_URLS = {
711
714
  production: PROD_URLS,
@@ -5729,6 +5732,7 @@ var SECURE_ROOM_BOUNDARIES_MIGRATION_ID = "2026-08-secure-room-boundaries";
5729
5732
  var ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID = "2026-08-action-tools-delete-where";
5730
5733
  var BUILD_INJECTED_APP_ID_MIGRATION_ID = "2026-08-build-injected-app-id";
5731
5734
  var ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID = "2026-08-action-routes-bearer-guard";
5735
+ var FILES_SESSION_COOKIE_READS_MIGRATION_ID = "2026-09-files-session-cookie-reads";
5732
5736
  function validateAppMigrationIds(value) {
5733
5737
  if (!Array.isArray(value)) {
5734
5738
  return { valid: false, reason: "app migrations must be a JSON string array" };
@@ -5786,6 +5790,12 @@ var APP_MIGRATION_GUIDANCE = [
5786
5790
  description: "Refuse action calls without a bearer token and document their trust boundary",
5787
5791
  files: ["src/server/action-routes.ts, when the app has server actions"],
5788
5792
  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."
5793
+ },
5794
+ {
5795
+ id: FILES_SESSION_COOKIE_READS_MIGRATION_ID,
5796
+ description: "Let private file URLs render in <img>/<audio>/<video> for the signed-in user",
5797
+ files: ["the app-owned HTTP route file that proxies /api/files/*"],
5798
+ 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."
5789
5799
  }
5790
5800
  ];
5791
5801
  var APP_MIGRATION_DEFINITIONS = APP_MIGRATION_GUIDANCE.map(({ id, description }) => ({
@@ -11230,10 +11240,13 @@ function normalizeAgentTargetOrigin(value, policy) {
11230
11240
  return policy.allowLoopback && ["http:", "https:"].includes(url.protocol) ? url.origin : null;
11231
11241
  }
11232
11242
  if (url.protocol !== "https:" || url.port) return null;
11233
- if (policy.appDomain.toLowerCase() === PRODUCTION_APP_DOMAIN && PRODUCTION_OFFICIAL_AGENT_ORIGINS.includes(url.origin)) {
11243
+ const appDomain = policy.appDomain.toLowerCase();
11244
+ const platformDomain = policy.platformDomain?.toLowerCase();
11245
+ const officialAdminOrigin = platformDomain ? `https://admin.${platformDomain}` : appDomain === PRODUCTION_APP_DOMAIN ? PRODUCTION_OFFICIAL_AGENT_ORIGINS[0] : null;
11246
+ if (url.origin === officialAdminOrigin) {
11234
11247
  return url.origin;
11235
11248
  }
11236
- const suffix = `.${policy.appDomain.toLowerCase()}`;
11249
+ const suffix = `.${appDomain}`;
11237
11250
  if (!hostname.endsWith(suffix)) return null;
11238
11251
  const label = hostname.slice(0, -suffix.length);
11239
11252
  return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
@@ -11297,7 +11310,8 @@ function resolveAgentTarget(app2, plane = DEEPSPACE_ENV) {
11297
11310
  if (typeof app2 !== "string" || !app2)
11298
11311
  badApp("App must be a canonical app name or canonical app URL.");
11299
11312
  const appDomain = appDomainForEnv(plane);
11300
- if (!appDomain) badApp("The selected DeepSpace environment is invalid.");
11313
+ const platformDomain = platformDomainForEnv(plane);
11314
+ if (!appDomain || !platformDomain) badApp("The selected DeepSpace environment is invalid.");
11301
11315
  if (app2.toLowerCase() === "localhost") {
11302
11316
  badApp("Pass an explicit loopback URL for local development (e.g. 'http://localhost:8787').");
11303
11317
  }
@@ -11306,6 +11320,7 @@ function resolveAgentTarget(app2, plane = DEEPSPACE_ENV) {
11306
11320
  }
11307
11321
  const url = normalizeAgentTargetOrigin(app2, {
11308
11322
  appDomain,
11323
+ platformDomain,
11309
11324
  allowLoopback: true
11310
11325
  });
11311
11326
  if (!url) {
@@ -13904,24 +13919,6 @@ async function loadWorkspaceLines(appDir, token, api4, trunkOid) {
13904
13919
  return /* @__PURE__ */ new Map();
13905
13920
  }
13906
13921
  }
13907
- async function listOverlaps(appId, token, api4, views) {
13908
- const appDir = findAppDir();
13909
- if (!appDir || readAppId(appDir) !== appId) return /* @__PURE__ */ new Map();
13910
- try {
13911
- assertSyncableRepo(appDir);
13912
- ensureSpaceRemote(appDir, appId);
13913
- const refs = await api4.getRefs().catch(() => null);
13914
- try {
13915
- fetchTrunk(appDir, token, refs?.head ?? null);
13916
- } catch {
13917
- }
13918
- fetchPeerWorkspaceRefs(appDir, token);
13919
- const lines = changedPathsByWorkspace(appDir, views, localTrunkOid(appDir, refs));
13920
- return new Map([...lines].map(([id, line]) => [id, overlapsWith(line.paths, lines, id)]));
13921
- } catch {
13922
- return /* @__PURE__ */ new Map();
13923
- }
13924
- }
13925
13922
  function printOverlaps(overlaps, json) {
13926
13923
  if (json) return;
13927
13924
  for (const overlap of overlaps) {
@@ -14869,12 +14866,6 @@ var syncWorkspaceCommand = defineDeepspaceCommand({
14869
14866
 
14870
14867
  // src/cli/commands/workspace/list.ts
14871
14868
  import * as p28 from "@clack/prompts";
14872
- function withWorkspaceOverlaps(views, overlapsById) {
14873
- return views.map((view) => ({
14874
- ...view,
14875
- overlaps: overlapsById.get(view.workspace.id) ?? []
14876
- }));
14877
- }
14878
14869
  var listWorkspacesCommand = defineDeepspaceCommand({
14879
14870
  meta: { name: "list", description: "List workspaces on the cloud repo" },
14880
14871
  args: {
@@ -14901,31 +14892,17 @@ var listWorkspacesCommand = defineDeepspaceCommand({
14901
14892
  }
14902
14893
  return { data: { workspaces: views, truncated: truncated === true } };
14903
14894
  }
14904
- spinner2?.message("Checking workspace overlaps\u2026");
14905
- const overlapsPromise = listOverlaps(appId, token, api4, views);
14906
14895
  if (args.json) {
14907
- return {
14908
- data: {
14909
- workspaces: withWorkspaceOverlaps(views, await overlapsPromise),
14910
- truncated: truncated === true
14911
- }
14912
- };
14896
+ return { data: { workspaces: views, truncated: truncated === true } };
14913
14897
  }
14914
- const [actors, overlapsById] = await Promise.all([actorLabels(token, appId), overlapsPromise]);
14915
- const workspaces = withWorkspaceOverlaps(views, overlapsById);
14898
+ const actors = await actorLabels(token, appId);
14916
14899
  spinner2?.stop(`Loaded ${views.length} ${views.length === 1 ? "workspace" : "workspaces"}.`);
14917
- for (const view of workspaces) {
14900
+ for (const view of views) {
14918
14901
  const workspace = view.workspace;
14919
- const overlaps = view.overlaps;
14920
- const marker = workspace.status === "active" ? overlaps.length > 0 ? "\u26A0" : " " : workspace.status === "landed" ? "\u2713" : "\u2717";
14902
+ const marker = workspace.status === "active" ? " " : workspace.status === "landed" ? "\u2713" : "\u2717";
14921
14903
  console.log(
14922
14904
  `${marker} ${workspace.id} ${workspace.status} \u2191${formatCount(view.aheadOfBase)} \u2193${formatCount(view.behindTrunk)} ${actors.get(workspace.createdBy) ?? workspace.createdBy} ${workspace.updatedAt} ${workspace.task}`
14923
14905
  );
14924
- for (const overlap of overlaps) {
14925
- console.log(
14926
- ` overlaps ${overlap.workspaceId}: ${overlap.paths.slice(0, 3).join(", ")}${overlap.paths.length + overlap.morePaths > 3 ? ` (+${overlap.paths.length + overlap.morePaths - 3} more)` : ""}`
14927
- );
14928
- }
14929
14906
  }
14930
14907
  if (truncated) {
14931
14908
  p28.log.warn(
@@ -14933,7 +14910,7 @@ var listWorkspacesCommand = defineDeepspaceCommand({
14933
14910
  );
14934
14911
  }
14935
14912
  p28.log.info("\u2191 commits ahead of base \xB7 \u2193 trunk commits since base (staleness)");
14936
- return { data: { workspaces, truncated: truncated === true } };
14913
+ return { data: { workspaces: views, truncated: truncated === true } };
14937
14914
  }
14938
14915
  });
14939
14916
 
@@ -16021,7 +15998,7 @@ import { join as join28, resolve as resolve22 } from "path";
16021
15998
  // package.json
16022
15999
  var package_default = {
16023
16000
  name: "deepspace",
16024
- version: "0.30.1",
16001
+ version: "0.31.0",
16025
16002
  engines: {
16026
16003
  node: ">=22.15.0 <23 || >=24 <25 || >=26 <27"
16027
16004
  },