deepspace 0.33.0 → 0.34.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +5 -1
  3. package/dist/build.js.map +1 -1
  4. package/dist/{chunk-BRES7ZWJ.js → chunk-KELQ7OD5.js} +2 -2
  5. package/dist/{chunk-BRES7ZWJ.js.map → chunk-KELQ7OD5.js.map} +1 -1
  6. package/dist/{chunk-PIYDVPUE.js → chunk-SINBB5BQ.js} +2 -2
  7. package/dist/{chunk-PIYDVPUE.js.map → chunk-SINBB5BQ.js.map} +1 -1
  8. package/dist/cli.js +74 -15
  9. package/dist/cli.js.map +1 -1
  10. package/dist/documentation-client-core.js +1 -1
  11. package/dist/documentation-default-renderer.cjs +1 -1
  12. package/dist/documentation-react.js +1 -1
  13. package/dist/documentation-runtime.js +10 -10
  14. package/dist/documentation-server-core.js +1 -1
  15. package/dist/documentation.js +47 -22
  16. package/dist/documentation.js.map +1 -1
  17. package/dist/expo.d.ts +73 -0
  18. package/dist/expo.js +233 -0
  19. package/dist/expo.js.map +1 -0
  20. package/dist/index.d.ts +105 -22
  21. package/dist/index.js +50 -23
  22. package/dist/index.js.map +1 -1
  23. package/dist/server.d.ts +205 -37
  24. package/dist/server.js +290 -97
  25. package/dist/server.js.map +1 -1
  26. package/dist/worker.d.ts +312 -48
  27. package/dist/worker.js +499 -110
  28. package/dist/worker.js.map +1 -1
  29. package/features/documents/feature.json +15 -0
  30. package/features/documents/src/DocumentsListPage.tsx +22 -8
  31. package/features/documents/src/InviteDialog.tsx +63 -42
  32. package/features/documents/src/__tests__/documents-find-invitee-action.test.ts +131 -0
  33. package/features/documents/src/__tests__/documents-invitee-lookup.test.ts +67 -0
  34. package/features/documents/src/documents-find-invitee-action.ts +56 -0
  35. package/features/documents/src/documents-invitee-lookup.ts +38 -0
  36. package/features/documents/src/documents-ui.css +10 -0
  37. package/package.json +28 -8
package/dist/worker.js CHANGED
@@ -2374,6 +2374,7 @@ function getAllUserRecords(sql, schemaRegistry) {
2374
2374
  }
2375
2375
  async function registerUser(sql, userId, name, email, imageUrl, isAdmin, defaultRole = "viewer", schemaRegistry) {
2376
2376
  const now = (/* @__PURE__ */ new Date()).toISOString();
2377
+ const normalizedEmail = email.trim().toLowerCase();
2377
2378
  const existing = getUserRecord(sql, userId, schemaRegistry);
2378
2379
  let role;
2379
2380
  if (isAdmin) {
@@ -2384,7 +2385,7 @@ async function registerUser(sql, userId, name, email, imageUrl, isAdmin, default
2384
2385
  role = defaultRole;
2385
2386
  }
2386
2387
  if (existing) {
2387
- const updatedEmail = email || existing.data.email;
2388
+ const updatedEmail = normalizedEmail || existing.data.email;
2388
2389
  const updatedName = name && name !== "Anonymous" ? name : existing.data.name;
2389
2390
  const updatedImageUrl = imageUrl ?? existing.data.imageUrl;
2390
2391
  sql.exec(
@@ -2413,14 +2414,14 @@ async function registerUser(sql, userId, name, email, imageUrl, isAdmin, default
2413
2414
  userId,
2414
2415
  now,
2415
2416
  now,
2416
- email,
2417
+ normalizedEmail,
2417
2418
  name,
2418
2419
  imageUrl ?? null,
2419
2420
  role,
2420
2421
  now,
2421
2422
  now
2422
2423
  );
2423
- return { id: userId, email, name, imageUrl, role, createdAt: now, lastSeenAt: now };
2424
+ return { id: userId, email: normalizedEmail, name, imageUrl, role, createdAt: now, lastSeenAt: now };
2424
2425
  }
2425
2426
  function rosterFor(ctx, schema, records, publicRoster, userId, role) {
2426
2427
  if (!userId || isAnonymousUserId(userId)) return [];
@@ -2475,16 +2476,19 @@ function broadcastUserList(ctx, except) {
2475
2476
  });
2476
2477
  }
2477
2478
  }
2478
- function handleUserUpdate(ctx, _ws, attachment, payload) {
2479
+ function handleUserUpdate(ctx, _ws, attachment) {
2479
2480
  const existing = getUserRecord(ctx.sql, attachment.userId, ctx.schemaRegistry);
2480
2481
  if (!existing) return;
2481
- const data = { lastSeenAt: (/* @__PURE__ */ new Date()).toISOString() };
2482
- if (payload.name && payload.name !== "Anonymous") data.name = payload.name;
2483
- if (payload.email) data.email = payload.email;
2484
- if (payload.imageUrl !== void 0) data.imageUrl = payload.imageUrl || void 0;
2485
- putRecord(ctx, "users", attachment.userId, data, attachment.userId, "admin", true, true);
2486
- const rosterChanged = data.name !== void 0 && data.name !== existing.data.name || data.imageUrl !== void 0 && data.imageUrl !== existing.data.imageUrl;
2487
- if (rosterChanged) broadcastUserList(ctx);
2482
+ putRecord(
2483
+ ctx,
2484
+ "users",
2485
+ attachment.userId,
2486
+ { lastSeenAt: (/* @__PURE__ */ new Date()).toISOString() },
2487
+ attachment.userId,
2488
+ "admin",
2489
+ true,
2490
+ true
2491
+ );
2488
2492
  }
2489
2493
  async function handleSetRole(ctx, ws, attachment, payload) {
2490
2494
  if (attachment.role !== "admin") {
@@ -3233,7 +3237,7 @@ var RecordRoom = class extends BaseRoom {
3233
3237
  this.schemaRegistry
3234
3238
  );
3235
3239
  const regMs = Date.now() - regStart;
3236
- if (!before || before.name !== registeredUser.name || before.imageUrl !== registeredUser.imageUrl || before.role !== registeredUser.role) {
3240
+ if (!before || before.name !== registeredUser.name || before.email !== registeredUser.email || before.imageUrl !== registeredUser.imageUrl || before.role !== registeredUser.role) {
3237
3241
  broadcastUserList(this.createUserContext(), ws);
3238
3242
  }
3239
3243
  attachment = {
@@ -3360,12 +3364,7 @@ var RecordRoom = class extends BaseRoom {
3360
3364
  handleUserList(userCtx, ws, attachment);
3361
3365
  break;
3362
3366
  case MSG.USER_UPDATE:
3363
- handleUserUpdate(
3364
- recordCtx,
3365
- ws,
3366
- attachment,
3367
- payload
3368
- );
3367
+ handleUserUpdate(recordCtx, ws, attachment);
3369
3368
  break;
3370
3369
  case MSG.SET_ROLE:
3371
3370
  await handleSetRole(userCtx, ws, attachment, payload);
@@ -4609,6 +4608,7 @@ function computeNextRunAt(task, from) {
4609
4608
 
4610
4609
  // src/server/rooms/job-room.ts
4611
4610
  var RUNNING_STALE_MS = 16 * 60 * 1e3;
4611
+ var BACKGROUND_ALARM_MS = 3e4;
4612
4612
  var DEFAULT_RETENTION_MS = 24 * 60 * 60 * 1e3;
4613
4613
  var DEFAULT_SNAPSHOT_LIMIT = 100;
4614
4614
  var JobRoom = class extends BaseRoom {
@@ -4617,6 +4617,7 @@ var JobRoom = class extends BaseRoom {
4617
4617
  retentionMs;
4618
4618
  snapshotLimit;
4619
4619
  retryBackoffMs;
4620
+ backgroundJobTypes;
4620
4621
  authorizeWrite;
4621
4622
  authorizeRead;
4622
4623
  broadcastQueue = Promise.resolve();
@@ -4630,6 +4631,7 @@ var JobRoom = class extends BaseRoom {
4630
4631
  this.retentionMs = Math.max(0, config.retentionMs ?? DEFAULT_RETENTION_MS);
4631
4632
  this.snapshotLimit = Math.max(1, config.snapshotLimit ?? DEFAULT_SNAPSHOT_LIMIT);
4632
4633
  this.retryBackoffMs = Math.max(0, config.retryBackoffMs ?? 1e3);
4634
+ this.backgroundJobTypes = new Set(config.backgroundJobTypes ?? []);
4633
4635
  this.authorizeWrite = config.authorizeWrite ?? ((user) => user.role === ROLES.MEMBER || user.role === ROLES.ADMIN);
4634
4636
  this.authorizeRead = config.authorizeRead ?? this.authorizeWrite;
4635
4637
  }
@@ -4877,11 +4879,8 @@ var JobRoom = class extends BaseRoom {
4877
4879
  // ==========================================================================
4878
4880
  // Alarm / execution
4879
4881
  // ==========================================================================
4880
- /**
4881
- * Drain due jobs in FIFO order. All due jobs share the alarm's
4882
- * 15-min wall budget (a CF property, not a per-job allocation).
4883
- */
4884
4882
  async drainDueJobs() {
4883
+ if (this.inFlight.size > 0) return;
4885
4884
  const cutoff = (/* @__PURE__ */ new Date()).toISOString();
4886
4885
  while (true) {
4887
4886
  const row = this.sql.exec(
@@ -4893,7 +4892,16 @@ var JobRoom = class extends BaseRoom {
4893
4892
  cutoff
4894
4893
  ).toArray()[0];
4895
4894
  if (!row) return;
4896
- await this.executeJob(row);
4895
+ const execution = this.executeJob(row);
4896
+ if (this.backgroundJobTypes.has(row.type)) {
4897
+ this.state.waitUntil(
4898
+ execution.catch(
4899
+ (error) => console.error(`[jobs] background execution failed: ${loggableError(error)}`)
4900
+ ).finally(() => this.scheduleNextAlarm())
4901
+ );
4902
+ return;
4903
+ }
4904
+ await execution;
4897
4905
  }
4898
4906
  }
4899
4907
  async executeJob(row) {
@@ -4930,7 +4938,7 @@ var JobRoom = class extends BaseRoom {
4930
4938
  this.inFlight.delete(row.id);
4931
4939
  }
4932
4940
  const currentStatus = this.readStatus(row.id);
4933
- if (currentStatus === "canceled") {
4941
+ if (currentStatus !== "running") {
4934
4942
  this.continueState = null;
4935
4943
  return;
4936
4944
  }
@@ -5062,6 +5070,10 @@ var JobRoom = class extends BaseRoom {
5062
5070
  // Scheduling / recovery / pruning
5063
5071
  // ==========================================================================
5064
5072
  scheduleNextAlarm() {
5073
+ if (this.inFlight.size > 0) {
5074
+ this.state.storage.setAlarm(Date.now() + BACKGROUND_ALARM_MS);
5075
+ return;
5076
+ }
5065
5077
  const queued = this.sql.exec(
5066
5078
  `SELECT next_run_at FROM jobs
5067
5079
  WHERE status = 'queued'
@@ -5095,6 +5107,7 @@ var JobRoom = class extends BaseRoom {
5095
5107
  cutoff
5096
5108
  ).toArray();
5097
5109
  for (const r of stuck) {
5110
+ if (this.inFlight.has(r.id)) continue;
5098
5111
  if (r.attempts >= r.max_attempts) {
5099
5112
  this.sql.exec(
5100
5113
  `UPDATE jobs
@@ -5795,6 +5808,7 @@ var ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID = "2026-08-action-tools-delete-where"
5795
5808
  var BUILD_INJECTED_APP_ID_MIGRATION_ID = "2026-08-build-injected-app-id";
5796
5809
  var ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID = "2026-08-action-routes-bearer-guard";
5797
5810
  var FILES_SESSION_COOKIE_READS_MIGRATION_ID = "2026-09-files-session-cookie-reads";
5811
+ var AI_SDK_7_MIGRATION_ID = "2026-09-ai-sdk-7";
5798
5812
  function validateAppMigrationIds(value) {
5799
5813
  if (!Array.isArray(value)) {
5800
5814
  return { valid: false, reason: "app migrations must be a JSON string array" };
@@ -5822,8 +5836,8 @@ function validateAppMigrationIds(value) {
5822
5836
 
5823
5837
  // src/shared/ai-models.ts
5824
5838
  var DEEPSPACE_MODEL_CATALOG_PROVENANCE = {
5825
- version: "2026-08-04",
5826
- verifiedAt: "2026-08-04",
5839
+ version: "2026-09-24",
5840
+ verifiedAt: "2026-09-24",
5827
5841
  sources: {
5828
5842
  anthropic: "https://platform.claude.com/docs/en/api/beta/models/list",
5829
5843
  openai: "https://developers.openai.com/api/docs/models/all",
@@ -5849,16 +5863,17 @@ var openAIModel = createMultiStepModelFactory({
5849
5863
  providerLabel: "OpenAI",
5850
5864
  transport: "chat-completions"
5851
5865
  });
5866
+ var DIRECT_GENERATION_NOTE = "Available for direct generation; the current proxy adapter has not passed multi-step tool-result continuation.";
5852
5867
  var DEEPSPACE_AI_MODELS = [
5853
5868
  anthropicModel({
5854
- id: "claude-fable-5",
5855
- label: "Claude Fable 5",
5869
+ id: "claude-opus-5-5",
5870
+ label: "Claude Opus 5.5",
5856
5871
  family: "Claude 5",
5857
5872
  recommendation: "frontier"
5858
5873
  }),
5859
5874
  anthropicModel({
5860
- id: "claude-opus-5",
5861
- label: "Claude Opus 5",
5875
+ id: "claude-fable-5-1",
5876
+ label: "Claude Fable 5.1",
5862
5877
  family: "Claude 5",
5863
5878
  recommendation: "frontier"
5864
5879
  }),
@@ -5875,23 +5890,29 @@ var DEEPSPACE_AI_MODELS = [
5875
5890
  recommendation: "fast"
5876
5891
  }),
5877
5892
  openAIModel({
5878
- id: "gpt-5.6-sol",
5879
- label: "GPT-5.6 Sol",
5880
- family: "GPT-5.6",
5881
- recommendation: "frontier"
5882
- }),
5883
- openAIModel({
5884
- id: "gpt-5.6-terra",
5885
- label: "GPT-5.6 Terra",
5886
- family: "GPT-5.6",
5893
+ id: "gpt-6-sol",
5894
+ label: "GPT-6 Sol",
5895
+ family: "GPT-6",
5887
5896
  recommendation: "balanced"
5888
5897
  }),
5889
5898
  openAIModel({
5890
- id: "gpt-5.6-luna",
5891
- label: "GPT-5.6 Luna",
5892
- family: "GPT-5.6",
5899
+ id: "gpt-6-luna",
5900
+ label: "GPT-6 Luna",
5901
+ family: "GPT-6",
5893
5902
  recommendation: "fast"
5894
5903
  }),
5904
+ {
5905
+ id: "gpt-6-astra",
5906
+ label: "GPT-6 Astra",
5907
+ provider: "openai",
5908
+ providerLabel: "OpenAI",
5909
+ family: "GPT-6",
5910
+ agentSupport: "none",
5911
+ agentProfiles: [],
5912
+ transport: "chat-completions",
5913
+ recommendation: "limited",
5914
+ note: "Available for direct generation; its tool calling requires the Responses API, which the DeepSpace proxy does not serve."
5915
+ },
5895
5916
  {
5896
5917
  id: "gpt-oss-120b",
5897
5918
  label: "GPT-OSS 120B",
@@ -5902,12 +5923,30 @@ var DEEPSPACE_AI_MODELS = [
5902
5923
  agentProfiles: [],
5903
5924
  transport: "chat-completions",
5904
5925
  recommendation: "limited",
5905
- note: "Available for direct generation; the current proxy adapter has not passed multi-step tool-result continuation."
5906
- }
5926
+ note: DIRECT_GENERATION_NOTE
5927
+ },
5928
+ {
5929
+ id: "qwen-3.8-27b",
5930
+ label: "Qwen 3.8 27B",
5931
+ provider: "cerebras",
5932
+ providerLabel: "Cerebras",
5933
+ family: "Qwen 3.8",
5934
+ agentSupport: "single-step",
5935
+ agentProfiles: [],
5936
+ transport: "chat-completions",
5937
+ recommendation: "limited",
5938
+ note: DIRECT_GENERATION_NOTE
5939
+ },
5940
+ // Superseded models: still resolvable for apps that saved them.
5941
+ anthropicModel({ id: "claude-opus-5", label: "Claude Opus 5", family: "Claude 5", recommendation: "frontier", legacy: true }),
5942
+ anthropicModel({ id: "claude-fable-5", label: "Claude Fable 5", family: "Claude 5", recommendation: "frontier", legacy: true }),
5943
+ openAIModel({ id: "gpt-5.6-sol", label: "GPT-5.6 Sol", family: "GPT-5.6", recommendation: "frontier", legacy: true }),
5944
+ openAIModel({ id: "gpt-5.6-terra", label: "GPT-5.6 Terra", family: "GPT-5.6", recommendation: "balanced", legacy: true }),
5945
+ openAIModel({ id: "gpt-5.6-luna", label: "GPT-5.6 Luna", family: "GPT-5.6", recommendation: "fast", legacy: true })
5907
5946
  ];
5908
5947
  var DEEPSPACE_AI_DEFAULTS = {
5909
- agent: "claude-sonnet-5",
5910
- directGeneration: "claude-sonnet-5",
5948
+ agent: "claude-opus-5-5",
5949
+ directGeneration: "claude-opus-5-5",
5911
5950
  summarization: "claude-haiku-4-5"
5912
5951
  };
5913
5952
  var DEEPSPACE_AGENT_PROFILES = {
@@ -5935,7 +5974,7 @@ function getDeepSpaceAIModel(modelId) {
5935
5974
  function listDeepSpaceAgentModels(profileId = "application") {
5936
5975
  const defaultModel = DEEPSPACE_AGENT_PROFILES[profileId].defaultModel;
5937
5976
  return DEEPSPACE_AI_MODELS.filter(
5938
- (model) => model.agentProfiles.includes(profileId)
5977
+ (model) => !model.legacy && model.agentProfiles.includes(profileId)
5939
5978
  ).sort((left, right) => Number(right.id === defaultModel) - Number(left.id === defaultModel));
5940
5979
  }
5941
5980
  function resolveDeepSpaceAgentModel(modelId, profileId = "application") {
@@ -6016,6 +6055,10 @@ var BROWSER_PROXY_ROUTES = [
6016
6055
  { method: "GET", path: "/_deepspace/charges/me" }
6017
6056
  ];
6018
6057
 
6058
+ // src/shared/sandbox.ts
6059
+ var SANDBOX_SCOPES = ["user", "app"];
6060
+ var SANDBOX_SCOPE_HEADER = "x-deepspace-sandbox-scope";
6061
+
6019
6062
  // src/server/utils/cors.ts
6020
6063
  function matchOrigin(origin, patterns) {
6021
6064
  if (!origin) return null;
@@ -7664,36 +7707,57 @@ async function resolveAppRole(env, userId) {
7664
7707
  import { createAnthropic } from "@ai-sdk/anthropic";
7665
7708
  import { createOpenAI } from "@ai-sdk/openai";
7666
7709
  import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
7667
- var ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS = 4096;
7668
- function withDefaultAnthropicMaxTokens(body) {
7710
+
7711
+ // src/server/utils/app-identity.ts
7712
+ function appendAppIdentity(headers, env) {
7713
+ headers.delete("x-app-identity-token");
7714
+ headers.delete("x-app-id");
7715
+ if (!env.APP_IDENTITY_TOKEN) return;
7716
+ headers.set("x-app-identity-token", env.APP_IDENTITY_TOKEN);
7717
+ headers.set("x-app-id", env.DEEPSPACE_APP_ID);
7718
+ }
7719
+
7720
+ // src/server/utils/ai.ts
7721
+ import { defaultSettingsMiddleware, wrapLanguageModel } from "ai";
7722
+ function resolveProxyAuthToken(env, options) {
7723
+ const authToken = options.authToken ?? env.APP_OWNER_JWT;
7724
+ if (!authToken) {
7725
+ throw new Error(
7726
+ "DeepSpace AI proxy: no auth token available. Either pass `options.authToken` explicitly (for user-initiated calls), or ensure `env.APP_OWNER_JWT` is set (injected at deploy time or by `deepspace dev start`)."
7727
+ );
7728
+ }
7729
+ return authToken;
7730
+ }
7731
+ function setProxyHeaders(headers, env, authToken, scope = "user") {
7732
+ headers.set("X-Auth-Token", authToken);
7733
+ appendAppIdentity(headers, {
7734
+ DEEPSPACE_APP_ID: env.DEEPSPACE_APP_ID ?? "",
7735
+ APP_IDENTITY_TOKEN: env.APP_IDENTITY_TOKEN
7736
+ });
7737
+ headers.set(SANDBOX_SCOPE_HEADER, scope);
7738
+ }
7739
+ var ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS = 64e3;
7740
+ var OPENAI_TOOLS_NEED_NO_REASONING = /^gpt-(5\.6|6)-(sol|terra|luna)(-|$)/;
7741
+ function withOpenAIToolReasoningEffort(body) {
7669
7742
  if (typeof body !== "string") return body;
7670
7743
  try {
7671
7744
  const parsed = JSON.parse(body);
7672
- const hasExplicitLimit = typeof parsed.max_tokens === "number" || typeof parsed.max_completion_tokens === "number" || typeof parsed.max_output_tokens === "number";
7673
- if (hasExplicitLimit) return body;
7674
- return JSON.stringify({
7675
- ...parsed,
7676
- max_tokens: ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS
7677
- });
7745
+ const needsEffort = typeof parsed.model === "string" && OPENAI_TOOLS_NEED_NO_REASONING.test(parsed.model) && Array.isArray(parsed.tools) && parsed.tools.length > 0 && parsed.reasoning_effort === void 0;
7746
+ return needsEffort ? JSON.stringify({ ...parsed, reasoning_effort: "none" }) : body;
7678
7747
  } catch {
7679
7748
  return body;
7680
7749
  }
7681
7750
  }
7682
7751
  function createDeepSpaceAI(env, provider, options = {}) {
7683
7752
  const transport = resolveApiTransport(env);
7684
- const authToken = options.authToken ?? env.APP_OWNER_JWT;
7685
- if (!authToken) {
7686
- throw new Error(
7687
- "createDeepSpaceAI: no auth token available. Either pass `options.authToken` explicitly (for user-initiated calls), or ensure `env.APP_OWNER_JWT` is set (injected at deploy time or by `deepspace dev start`)."
7688
- );
7689
- }
7753
+ const authToken = resolveProxyAuthToken(env, options);
7690
7754
  const proxyFetch = (input, init) => {
7691
7755
  const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
7692
7756
  const headers = new Headers(init?.headers);
7693
7757
  headers.delete("authorization");
7694
7758
  headers.delete("x-api-key");
7695
- headers.set("X-Auth-Token", authToken);
7696
- const body = provider === "anthropic" ? withDefaultAnthropicMaxTokens(init?.body) : init?.body;
7759
+ setProxyHeaders(headers, env, authToken, options.sandboxScope);
7760
+ const body = provider === "openai" ? withOpenAIToolReasoningEffort(init?.body) : init?.body;
7697
7761
  if (body !== init?.body) {
7698
7762
  headers.delete("content-length");
7699
7763
  }
@@ -7707,8 +7771,13 @@ function createDeepSpaceAI(env, provider, options = {}) {
7707
7771
  };
7708
7772
  const baseURL = `https://api-worker.internal/api/proxy/${provider}/v1`;
7709
7773
  switch (provider) {
7710
- case "anthropic":
7711
- return createAnthropic({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
7774
+ case "anthropic": {
7775
+ const anthropic2 = createAnthropic({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
7776
+ const defaults = defaultSettingsMiddleware({
7777
+ settings: { maxOutputTokens: ANTHROPIC_DEFAULT_MAX_OUTPUT_TOKENS }
7778
+ });
7779
+ return (modelId) => wrapLanguageModel({ model: anthropic2(modelId), middleware: defaults });
7780
+ }
7712
7781
  case "openai": {
7713
7782
  const op = createOpenAI({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
7714
7783
  return op.chat;
@@ -7729,10 +7798,7 @@ function createDeepSpaceAI(env, provider, options = {}) {
7729
7798
  }
7730
7799
 
7731
7800
  // src/server/utils/agent.ts
7732
- import {
7733
- stepCountIs,
7734
- streamText
7735
- } from "ai";
7801
+ import { isStepCount, streamText } from "ai";
7736
7802
  var DeepSpaceAgentModelError = class extends Error {
7737
7803
  constructor(modelId, profile) {
7738
7804
  super(
@@ -7754,7 +7820,7 @@ var DeepSpaceAgentProfileError = class extends Error {
7754
7820
  code = "agent_profile_violation";
7755
7821
  };
7756
7822
  function streamDeepSpaceAgent(env, options) {
7757
- const { profile, modelId, authToken, ...streamOptions } = options;
7823
+ const { profile, modelId, authToken, sandboxScope, ...streamOptions } = options;
7758
7824
  const selection = resolveDeepSpaceAgentModel(modelId, profile);
7759
7825
  if (!selection) throw new DeepSpaceAgentModelError(modelId, profile);
7760
7826
  if (selection.profile.allowedTools !== "application-defined") {
@@ -7765,14 +7831,17 @@ function streamDeepSpaceAgent(env, options) {
7765
7831
  }
7766
7832
  }
7767
7833
  }
7768
- const provider = createDeepSpaceAI(env, selection.provider, authToken ? { authToken } : {});
7834
+ const provider = createDeepSpaceAI(env, selection.provider, {
7835
+ ...authToken ? { authToken } : {},
7836
+ ...sandboxScope ? { sandboxScope } : {}
7837
+ });
7769
7838
  const { prepareStep, tools, ...remainingStreamOptions } = streamOptions;
7770
7839
  const boundedTools = limitToolExecutions(tools, selection.profile.maxToolCalls);
7771
7840
  const result = streamText({
7772
7841
  ...remainingStreamOptions,
7773
7842
  ...boundedTools ? { tools: boundedTools } : {},
7774
7843
  model: provider(selection.modelId),
7775
- stopWhen: stepCountIs(selection.profile.maxSteps),
7844
+ stopWhen: isStepCount(selection.profile.maxSteps),
7776
7845
  prepareStep: enforceToolCallLimit(prepareStep, selection.profile.maxToolCalls),
7777
7846
  ...selection.provider === "openai" ? { providerOptions: { openai: { reasoningEffort: "none" } } } : {}
7778
7847
  });
@@ -7884,6 +7953,115 @@ function safeLogText(value) {
7884
7953
  ).trim().slice(0, 300);
7885
7954
  }
7886
7955
 
7956
+ // src/server/utils/sandbox.ts
7957
+ import { anthropic, forwardAnthropicContainerIdFromLastStep } from "@ai-sdk/anthropic";
7958
+ var FILES_PATH = "/api/proxy/anthropic/v1/files";
7959
+ var CODE_EXECUTION_CALLER = "code_execution_20260120";
7960
+ function codeExecutionTool() {
7961
+ return anthropic.tools.codeExecution_20260120();
7962
+ }
7963
+ function callableFromSandbox(tool3) {
7964
+ const anthropicOptions = tool3.providerOptions?.anthropic;
7965
+ return {
7966
+ ...tool3,
7967
+ providerOptions: {
7968
+ ...tool3.providerOptions,
7969
+ anthropic: { ...anthropicOptions, allowedCallers: ["direct", CODE_EXECUTION_CALLER] }
7970
+ }
7971
+ };
7972
+ }
7973
+ var forwardSandboxContainer = forwardAnthropicContainerIdFromLastStep;
7974
+ function reuseSandbox(containerId) {
7975
+ return containerId ? { anthropic: { container: { id: containerId } } } : void 0;
7976
+ }
7977
+ function sandboxUpload(file) {
7978
+ return {
7979
+ type: "file",
7980
+ mediaType: file.mime_type,
7981
+ filename: file.filename,
7982
+ data: { type: "reference", reference: { anthropic: file.id } },
7983
+ providerOptions: { anthropic: { containerUpload: true } }
7984
+ };
7985
+ }
7986
+ function collectFileIds(value, out) {
7987
+ if (Array.isArray(value)) {
7988
+ for (const item of value) collectFileIds(item, out);
7989
+ return;
7990
+ }
7991
+ if (!value || typeof value !== "object") return;
7992
+ for (const [key, child] of Object.entries(value)) {
7993
+ if (key === "file_id" && typeof child === "string" && child) out.add(child);
7994
+ else collectFileIds(child, out);
7995
+ }
7996
+ }
7997
+ function sandboxOutputs(steps) {
7998
+ let containerId = null;
7999
+ const fileIds = /* @__PURE__ */ new Set();
8000
+ for (const step of steps) {
8001
+ const container = step.providerMetadata?.anthropic?.container;
8002
+ if (typeof container?.id === "string") containerId = container.id;
8003
+ for (const part of step.content) {
8004
+ const result = part;
8005
+ if (result.type === "tool-result" && result.providerExecuted) collectFileIds(result.output, fileIds);
8006
+ }
8007
+ }
8008
+ return { containerId, fileIds: [...fileIds] };
8009
+ }
8010
+ var SandboxFileError = class extends Error {
8011
+ constructor(status, message) {
8012
+ super(message);
8013
+ this.status = status;
8014
+ this.name = "SandboxFileError";
8015
+ }
8016
+ };
8017
+ function sandboxFiles(env, options = {}) {
8018
+ const authToken = resolveProxyAuthToken(env, options);
8019
+ async function send(path, init = {}) {
8020
+ const headers = new Headers(init.headers);
8021
+ setProxyHeaders(headers, env, authToken, options.scope);
8022
+ const response = await apiWorkerFetch(env, `${FILES_PATH}${path}`, { ...init, headers });
8023
+ if (!response.ok) {
8024
+ const text = await response.text();
8025
+ let message = text || response.statusText;
8026
+ try {
8027
+ const body = JSON.parse(text);
8028
+ if (typeof body.error === "string") message = body.error;
8029
+ else if (body.error && typeof body.error === "object") message = JSON.stringify(body.error);
8030
+ } catch {
8031
+ }
8032
+ throw new SandboxFileError(response.status, `Sandbox file request failed (${response.status}): ${message}`);
8033
+ }
8034
+ return response;
8035
+ }
8036
+ const fileUrl = (fileId) => `/${encodeURIComponent(fileId)}`;
8037
+ return {
8038
+ async upload(file, { filename, expiresInSeconds } = {}) {
8039
+ const name = filename ?? (file instanceof File ? file.name : void 0);
8040
+ if (!name) throw new SandboxFileError(400, "sandboxFiles.upload: a Blob needs options.filename");
8041
+ const form = new FormData();
8042
+ form.set("file", file, name);
8043
+ if (expiresInSeconds !== void 0) form.set("expires_in_seconds", String(expiresInSeconds));
8044
+ return (await send("", { method: "POST", body: form })).json();
8045
+ },
8046
+ async get(fileId) {
8047
+ return (await send(fileUrl(fileId))).json();
8048
+ },
8049
+ download(fileId) {
8050
+ return send(`${fileUrl(fileId)}/content`);
8051
+ },
8052
+ async list({ limit, page } = {}) {
8053
+ const query = new URLSearchParams();
8054
+ if (limit !== void 0) query.set("limit", String(limit));
8055
+ if (page !== void 0) query.set("page", page);
8056
+ const suffix = query.size > 0 ? `?${query}` : "";
8057
+ return (await send(suffix)).json();
8058
+ },
8059
+ async delete(fileId) {
8060
+ await send(fileUrl(fileId), { method: "DELETE" });
8061
+ }
8062
+ };
8063
+ }
8064
+
7887
8065
  // src/server/utils/composio-tools.ts
7888
8066
  import { tool, jsonSchema } from "ai";
7889
8067
  var EMPTY_SCHEMA = { type: "object", properties: {} };
@@ -7966,15 +8144,6 @@ async function composioTools(env, options) {
7966
8144
  return tools;
7967
8145
  }
7968
8146
 
7969
- // src/server/utils/app-identity.ts
7970
- function appendAppIdentity(headers, env) {
7971
- headers.delete("x-app-identity-token");
7972
- headers.delete("x-app-id");
7973
- if (!env.APP_IDENTITY_TOKEN) return;
7974
- headers.set("x-app-identity-token", env.APP_IDENTITY_TOKEN);
7975
- headers.set("x-app-id", env.DEEPSPACE_APP_ID);
7976
- }
7977
-
7978
8147
  // src/server/utils/screenshot.ts
7979
8148
  async function captureScreenshot(env, url) {
7980
8149
  const headers = new Headers({ "content-type": "application/json" });
@@ -8327,14 +8496,14 @@ function formatTranscript(messages) {
8327
8496
  }
8328
8497
  function makeDefaultSummarizer(env, options = {}) {
8329
8498
  return async (messages) => {
8330
- const anthropic = createDeepSpaceAI(env, "anthropic", { authToken: options.authToken });
8499
+ const anthropic2 = createDeepSpaceAI(env, "anthropic", { authToken: options.authToken });
8331
8500
  const { text } = await generateText({
8332
8501
  // Stable alias — provider bug-fix snapshots roll forward without code change.
8333
- model: anthropic("claude-haiku-4-5"),
8502
+ model: anthropic2("claude-haiku-4-5"),
8334
8503
  // 2500 gives the model room to finish a sentence after hitting the
8335
8504
  // "under 2000 tokens" soft limit in the prompt.
8336
8505
  maxOutputTokens: 2500,
8337
- system: SUMMARIZER_SYSTEM_PROMPT,
8506
+ instructions: SUMMARIZER_SYSTEM_PROMPT,
8338
8507
  messages: [{ role: "user", content: formatTranscript(messages) }]
8339
8508
  });
8340
8509
  return text;
@@ -8822,6 +8991,9 @@ function splitStatements(sql) {
8822
8991
  // src/documentation/worker/routes.ts
8823
8992
  import { Hono } from "hono";
8824
8993
 
8994
+ // src/documentation/worker/assistant-routes.ts
8995
+ import { createUIMessageStreamResponse, toUIMessageStream } from "ai";
8996
+
8825
8997
  // src/documentation/resource-path.ts
8826
8998
  function canonicalNativeDocumentationRequestPath(pathname) {
8827
8999
  try {
@@ -9420,7 +9592,7 @@ function registerDocumentationAssistantRoutes(app, resolveAuth, publicBasePath =
9420
9592
  profile: "documentation",
9421
9593
  modelId: selectedModel.modelId,
9422
9594
  ...authToken ? { authToken } : {},
9423
- system: buildDocumentationAssistantPrompt(manifest.name || c.env.APP_NAME, route),
9595
+ instructions: buildDocumentationAssistantPrompt(manifest.name || c.env.APP_NAME, route),
9424
9596
  messages: [...history, { role: "user", content: question }],
9425
9597
  tools: buildDocumentationAssistantTools(corpus, publicBasePath),
9426
9598
  abortSignal: c.req.raw.signal,
@@ -9436,14 +9608,17 @@ function registerDocumentationAssistantRoutes(app, resolveAuth, publicBasePath =
9436
9608
  );
9437
9609
  return c.json({ error: "Documentation assistant is not configured" }, 503);
9438
9610
  }
9439
- return result.toUIMessageStreamResponse({
9440
- sendReasoning: false,
9441
- onError: (error) => {
9442
- console.error(
9443
- `[documentation-assistant] response error: ${deepSpaceAgentErrorSummary(error, diagnosticContext)}`
9444
- );
9445
- return "The documentation assistant could not complete this response.";
9446
- }
9611
+ return createUIMessageStreamResponse({
9612
+ stream: toUIMessageStream({
9613
+ stream: result.stream,
9614
+ sendReasoning: false,
9615
+ onError: (error) => {
9616
+ console.error(
9617
+ `[documentation-assistant] response error: ${deepSpaceAgentErrorSummary(error, diagnosticContext)}`
9618
+ );
9619
+ return "The documentation assistant could not complete this response.";
9620
+ }
9621
+ })
9447
9622
  });
9448
9623
  });
9449
9624
  }
@@ -10258,6 +10433,7 @@ function isTestAccountTier(tier) {
10258
10433
 
10259
10434
  // src/server/auth/betterAuth.ts
10260
10435
  import { betterAuth } from "better-auth";
10436
+ import { getOAuthState } from "better-auth/api";
10261
10437
  import { organization, twoFactor } from "better-auth/plugins";
10262
10438
  import { SignJWT, importPKCS8 } from "jose";
10263
10439
  function createDeepSpaceAuth(config) {
@@ -10301,6 +10477,7 @@ function createDeepSpaceAuth(config) {
10301
10477
  emailAndPassword: {
10302
10478
  enabled: config.emailAndPassword ?? true
10303
10479
  },
10480
+ ...config.userAdditionalFields ? { user: { additionalFields: config.userAdditionalFields } } : {},
10304
10481
  socialProviders,
10305
10482
  trustedOrigins: config.trustedOrigins ?? [
10306
10483
  "https://deep.space",
@@ -10336,29 +10513,45 @@ function createDeepSpaceAuth(config) {
10336
10513
  // keys) — that case is caught by the runtime assertions in
10337
10514
  // __tests__/betterAuth-hooks.test.ts, which read the wired hook back
10338
10515
  // off auth.options. Don't rename the key without running them.
10339
- databaseHooks: buildDatabaseHooks(config.onUserCreated),
10516
+ databaseHooks: buildDatabaseHooks(config.beforeUserCreate, config.onUserCreated),
10340
10517
  plugins: [organization(), twoFactor()]
10341
10518
  });
10342
10519
  }
10343
- function buildDatabaseHooks(onUserCreated) {
10344
- if (!onUserCreated) return void 0;
10520
+ function buildDatabaseHooks(beforeUserCreate, onUserCreated) {
10521
+ if (!beforeUserCreate && !onUserCreated) return void 0;
10345
10522
  return {
10346
10523
  user: {
10347
10524
  create: {
10348
- after: async (user, ctx) => {
10349
- try {
10350
- await onUserCreated(
10351
- { id: user.id, email: user.email, name: user.name },
10352
- // Forward BOTH request and standalone headers — some better-auth
10353
- // entry points populate ctx.headers without a request.
10354
- ctx ? { request: ctx.request, headers: ctx.headers ?? void 0 } : null
10355
- );
10356
- } catch (err) {
10357
- console.error(
10358
- `[deepspace] onUserCreated hook failed (signup unaffected): ${loggableError(err)}`
10359
- );
10525
+ ...beforeUserCreate ? {
10526
+ before: async (user, ctx) => beforeUserCreate(
10527
+ user,
10528
+ ctx ? {
10529
+ request: ctx.request,
10530
+ headers: ctx.headers ?? void 0,
10531
+ path: ctx.path,
10532
+ // Read from this package's Better Auth instance. In a
10533
+ // pnpm graph the consuming worker can have another
10534
+ // physical copy whose request-state singleton differs.
10535
+ oauthState: await getOAuthState()
10536
+ } : null
10537
+ )
10538
+ } : {},
10539
+ ...onUserCreated ? {
10540
+ after: async (user, ctx) => {
10541
+ try {
10542
+ await onUserCreated(
10543
+ { id: user.id, email: user.email, name: user.name },
10544
+ // Forward BOTH request and standalone headers — some better-auth
10545
+ // entry points populate ctx.headers without a request.
10546
+ ctx ? { request: ctx.request, headers: ctx.headers ?? void 0 } : null
10547
+ );
10548
+ } catch (err) {
10549
+ console.error(
10550
+ `[deepspace] onUserCreated hook failed (signup unaffected): ${loggableError(err)}`
10551
+ );
10552
+ }
10360
10553
  }
10361
- }
10554
+ } : {}
10362
10555
  }
10363
10556
  }
10364
10557
  };
@@ -10592,7 +10785,8 @@ function registerAgentToolRoutes(app, options) {
10592
10785
  output = await tool3.execute(input, {
10593
10786
  toolCallId: crypto.randomUUID(),
10594
10787
  messages: [],
10595
- abortSignal: c.req.raw.signal
10788
+ abortSignal: c.req.raw.signal,
10789
+ context: void 0
10596
10790
  });
10597
10791
  } catch {
10598
10792
  return errorResponse(500, "tool_execution_failed");
@@ -10651,6 +10845,184 @@ function normalizeAgentTargetOrigin(value, policy) {
10651
10845
  return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
10652
10846
  }
10653
10847
 
10848
+ // src/server/expo-auth.ts
10849
+ var CODE_CHALLENGE_RE = /^[A-Za-z0-9_-]{43}$/;
10850
+ var CODE_VERIFIER_RE = /^[A-Za-z0-9._~-]{43,128}$/;
10851
+ function allowedRedirect(value, options = {}) {
10852
+ try {
10853
+ new URL(value);
10854
+ return options.allowedRedirectUris?.includes(value) ?? false;
10855
+ } catch {
10856
+ return false;
10857
+ }
10858
+ }
10859
+ function validState(value) {
10860
+ return value === null || value.length >= 1 && value.length <= 1024;
10861
+ }
10862
+ function validPkce(challenge, method, required = false) {
10863
+ if (!challenge && !method) return !required;
10864
+ return method === "S256" && !!challenge && CODE_CHALLENGE_RE.test(challenge);
10865
+ }
10866
+ function authWorkerUnavailable() {
10867
+ return Response.json({ error: "The authentication service is not configured." }, { status: 503 });
10868
+ }
10869
+ function nativeAuthStart(request2, env, options) {
10870
+ const url = new URL(request2.url);
10871
+ const provider = url.searchParams.get("provider");
10872
+ const redirectUri = url.searchParams.get("redirect_uri");
10873
+ const state = url.searchParams.get("state");
10874
+ const codeChallenge = url.searchParams.get("code_challenge");
10875
+ const codeChallengeMethod = url.searchParams.get("code_challenge_method");
10876
+ if (!provider || !redirectUri || !validState(state) || !allowedRedirect(redirectUri, options) || !validPkce(codeChallenge, codeChallengeMethod, true)) {
10877
+ return Response.json({ error: "A supported provider, PKCE challenge, and registered redirect URI are required." }, { status: 400 });
10878
+ }
10879
+ if (!env.AUTH_WORKER_URL) return authWorkerUnavailable();
10880
+ const callback = new URL("/api/auth/oauth-complete", url.origin);
10881
+ callback.searchParams.set("redirect_uri", redirectUri);
10882
+ if (state) callback.searchParams.set("state", state);
10883
+ if (codeChallenge) {
10884
+ callback.searchParams.set("code_challenge", codeChallenge);
10885
+ callback.searchParams.set("code_challenge_method", "S256");
10886
+ }
10887
+ const authUrl = new URL("/login/social", env.AUTH_WORKER_URL);
10888
+ authUrl.searchParams.set("provider", provider);
10889
+ authUrl.searchParams.set("returnTo", callback.toString());
10890
+ return Response.redirect(authUrl.toString(), 302);
10891
+ }
10892
+ function nativeAuthCallback(request2, _env, options) {
10893
+ const url = new URL(request2.url);
10894
+ const redirectUri = url.searchParams.get("redirect_uri");
10895
+ const code = url.searchParams.get("code");
10896
+ const state = url.searchParams.get("state");
10897
+ const codeChallenge = url.searchParams.get("code_challenge");
10898
+ const codeChallengeMethod = url.searchParams.get("code_challenge_method");
10899
+ if (!redirectUri || !code || code.length > 4096 || !validState(state) || !validPkce(codeChallenge, codeChallengeMethod, true) || !allowedRedirect(redirectUri, options)) {
10900
+ return Response.json({ error: "The sign-in callback was incomplete." }, { status: 400 });
10901
+ }
10902
+ const destination = new URL(redirectUri);
10903
+ destination.searchParams.set("code", code);
10904
+ if (state) destination.searchParams.set("state", state);
10905
+ return Response.redirect(destination.toString(), 302);
10906
+ }
10907
+ async function nativeAuthExchange(request2, env) {
10908
+ const body = await request2.json().catch(() => null);
10909
+ if (!body || typeof body.code !== "string" || body.code.length < 8 || body.code.length > 4096 || typeof body.code_verifier !== "string" || !CODE_VERIFIER_RE.test(body.code_verifier)) {
10910
+ return Response.json({ error: "A valid one-time sign-in code and PKCE verifier are required." }, { status: 400 });
10911
+ }
10912
+ let exchange2;
10913
+ try {
10914
+ exchange2 = await authWorkerFetch(env, "/api/auth/exchange-code", {
10915
+ method: "POST",
10916
+ headers: { "Content-Type": "application/json" },
10917
+ body: JSON.stringify({ code: body.code, code_verifier: body.code_verifier })
10918
+ });
10919
+ } catch {
10920
+ return Response.json({ error: "The authentication service is unavailable." }, { status: 502 });
10921
+ }
10922
+ if (!exchange2.ok) {
10923
+ const definitiveFailure = exchange2.status === 400 || exchange2.status === 401;
10924
+ return Response.json(
10925
+ { error: definitiveFailure ? "The sign-in code expired. Please try again." : "The authentication service is unavailable." },
10926
+ { status: definitiveFailure ? 401 : 502 }
10927
+ );
10928
+ }
10929
+ const exchanged = await exchange2.json().catch(() => null);
10930
+ if (!exchanged || typeof exchanged.sessionToken !== "string") {
10931
+ return Response.json({ error: "The auth service did not issue a session." }, { status: 502 });
10932
+ }
10933
+ let tokenResponse = null;
10934
+ let token = null;
10935
+ for (let attempt = 0; attempt < 2; attempt += 1) {
10936
+ try {
10937
+ tokenResponse = await authWorkerFetch(env, "/api/auth/token", {
10938
+ method: "POST",
10939
+ headers: { Cookie: `${SESSION_COOKIE}=${encodeURIComponent(exchanged.sessionToken)}` }
10940
+ });
10941
+ } catch {
10942
+ tokenResponse = null;
10943
+ }
10944
+ if (tokenResponse?.ok) {
10945
+ token = await tokenResponse.json().catch(() => null);
10946
+ if (token && typeof token.token === "string") break;
10947
+ }
10948
+ if (tokenResponse?.status === 401) break;
10949
+ }
10950
+ if (!tokenResponse) {
10951
+ return Response.json({ error: "The authentication service is unavailable." }, { status: 502 });
10952
+ }
10953
+ if (!tokenResponse.ok) {
10954
+ return Response.json(
10955
+ tokenResponse.status === 401 ? { error: "The sign-in session expired. Please try again." } : { error: "The authentication service is unavailable." },
10956
+ { status: tokenResponse.status === 401 ? 401 : 502 }
10957
+ );
10958
+ }
10959
+ if (!token || typeof token.token !== "string") {
10960
+ return Response.json({ error: "The auth service did not issue an access token." }, { status: 502 });
10961
+ }
10962
+ return Response.json(
10963
+ { sessionToken: exchanged.sessionToken, accessToken: token.token },
10964
+ { headers: { "Cache-Control": "no-store" } }
10965
+ );
10966
+ }
10967
+ async function nativeAuthToken(request2, env) {
10968
+ const input = await request2.json().catch(() => null);
10969
+ if (!input || typeof input.sessionToken !== "string" || input.sessionToken.length < 16 || input.sessionToken.length > 4096) {
10970
+ return Response.json({ error: "A valid DeepSpace session is required." }, { status: 401 });
10971
+ }
10972
+ let response;
10973
+ try {
10974
+ response = await authWorkerFetch(env, "/api/auth/token", {
10975
+ method: "POST",
10976
+ headers: { Cookie: `${SESSION_COOKIE}=${encodeURIComponent(input.sessionToken)}` }
10977
+ });
10978
+ } catch {
10979
+ return Response.json({ error: "The authentication service is unavailable." }, { status: 502 });
10980
+ }
10981
+ if (!response.ok) {
10982
+ return Response.json(
10983
+ { error: response.status === 401 ? "The DeepSpace session expired." : "The authentication service is unavailable." },
10984
+ { status: response.status === 401 ? 401 : 502 }
10985
+ );
10986
+ }
10987
+ const body = await response.json().catch(() => null);
10988
+ if (!body || typeof body.token !== "string") {
10989
+ return Response.json({ error: "The auth service did not issue an access token." }, { status: 502 });
10990
+ }
10991
+ return Response.json(
10992
+ { accessToken: body.token },
10993
+ { headers: { "Cache-Control": "no-store" } }
10994
+ );
10995
+ }
10996
+ async function nativeAuthMe(request2, env) {
10997
+ if (!env.AUTH_JWT_PUBLIC_KEY || !env.AUTH_JWT_ISSUER) {
10998
+ return Response.json({ error: "JWT verification is not configured." }, { status: 500 });
10999
+ }
11000
+ const header = request2.headers.get("Authorization");
11001
+ const token = header?.startsWith("Bearer ") ? header.slice(7) : null;
11002
+ const verified = await verifyJwt(
11003
+ { publicKey: env.AUTH_JWT_PUBLIC_KEY, issuer: env.AUTH_JWT_ISSUER },
11004
+ token
11005
+ );
11006
+ if (!verified.result) return Response.json({ error: "Sign in required." }, { status: 401 });
11007
+ return Response.json(
11008
+ { userId: verified.result.userId, claims: verified.result.claims },
11009
+ { headers: { "Cache-Control": "no-store" } }
11010
+ );
11011
+ }
11012
+ async function nativeAuthSignOut(request2, env) {
11013
+ const body = await request2.json().catch(() => null);
11014
+ if (body && typeof body.sessionToken === "string" && body.sessionToken.length >= 16 && body.sessionToken.length <= 4096) {
11015
+ try {
11016
+ await authWorkerFetch(env, "/api/auth/sign-out", {
11017
+ method: "POST",
11018
+ headers: { Cookie: `${SESSION_COOKIE}=${encodeURIComponent(body.sessionToken)}` }
11019
+ });
11020
+ } catch {
11021
+ }
11022
+ }
11023
+ return Response.json({ ok: true });
11024
+ }
11025
+
10654
11026
  // src/shared/api-error.ts
10655
11027
  var SLUG_RE = /^[a-z0-9]+(?:[_.-][a-z0-9]+)*$/;
10656
11028
  var HUMAN_MESSAGES = {
@@ -10716,6 +11088,7 @@ export {
10716
11088
  AGENT_TOOL_RESPONSE_BODY_CAP,
10717
11089
  AI_CHATS_SCHEMA,
10718
11090
  AI_MESSAGES_SCHEMA,
11091
+ AI_SDK_7_MIGRATION_ID,
10719
11092
  ALLOWED_BINDING_TYPES,
10720
11093
  ANONYMOUS_USER_ID_PREFIX,
10721
11094
  APP_ID_RE,
@@ -10785,6 +11158,8 @@ export {
10785
11158
  ROLE_DEFAULT,
10786
11159
  RecordRoom,
10787
11160
  RegistryClientError,
11161
+ SANDBOX_SCOPES,
11162
+ SANDBOX_SCOPE_HEADER,
10788
11163
  SDK_RUN_WORKER_FIRST,
10789
11164
  SECRET_NAME_RE,
10790
11165
  SECURE_ROOM_BOUNDARIES_MIGRATION_ID,
@@ -10794,6 +11169,7 @@ export {
10794
11169
  SYSTEM_COLLECTIONS,
10795
11170
  SYSTEM_MAINTAINED_COLUMNS,
10796
11171
  SYSTEM_MANAGED_COLUMNS,
11172
+ SandboxFileError,
10797
11173
  SchemaRegistry,
10798
11174
  TEST_ACCOUNT_EMAIL_SUFFIX,
10799
11175
  UNDECLARED_ASSET_NOT_FOUND_HANDLING,
@@ -10814,6 +11190,7 @@ export {
10814
11190
  buildTableSelect,
10815
11191
  buildUiParts,
10816
11192
  callRegistry,
11193
+ callableFromSandbox,
10817
11194
  canCreate,
10818
11195
  canDelete,
10819
11196
  canRead,
@@ -10823,6 +11200,7 @@ export {
10823
11200
  checkFieldPermissions,
10824
11201
  checkUnclaimedOwnerTransition,
10825
11202
  clientBuild,
11203
+ codeExecutionTool,
10826
11204
  coerceValue,
10827
11205
  collectionTableName,
10828
11206
  columnId,
@@ -10850,6 +11228,7 @@ export {
10850
11228
  epochSeconds,
10851
11229
  folderFilter,
10852
11230
  formatBytes,
11231
+ forwardSandboxContainer,
10853
11232
  getChat,
10854
11233
  getDeepSpaceAIModel,
10855
11234
  getMessageType,
@@ -10881,6 +11260,12 @@ export {
10881
11260
  meterVectorize,
10882
11261
  mintAppId,
10883
11262
  mintUlid,
11263
+ nativeAuthCallback,
11264
+ nativeAuthExchange,
11265
+ nativeAuthMe,
11266
+ nativeAuthSignOut,
11267
+ nativeAuthStart,
11268
+ nativeAuthToken,
10884
11269
  noopPermissionContext,
10885
11270
  normalizeAgentTargetOrigin,
10886
11271
  normalizeApiError,
@@ -10904,8 +11289,12 @@ export {
10904
11289
  resolveCompatibilityFlags,
10905
11290
  resolveDeepSpaceAgentModel,
10906
11291
  resolveSessionReadAuth,
11292
+ reuseSandbox,
10907
11293
  rowToData,
10908
11294
  runMigrations,
11295
+ sandboxFiles,
11296
+ sandboxOutputs,
11297
+ sandboxUpload,
10909
11298
  serverBuild,
10910
11299
  storageLimitForTier,
10911
11300
  storageQuotaMessage,