deepspace 0.27.1 → 0.28.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/worker.js CHANGED
@@ -1345,7 +1345,7 @@ function handleDelete(ctx, ws, attachment, payload) {
1345
1345
  ctx.send(ws, serverBuild.error(result.error));
1346
1346
  }
1347
1347
  }
1348
- function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac = false, systemUpdate = false) {
1348
+ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac = false, systemUpdate = false, updateOnly = false) {
1349
1349
  const resolved = resolveCollection(ctx, collection);
1350
1350
  if (!resolved.ok) return { success: false, error: resolved.error };
1351
1351
  const schema = resolved.schema;
@@ -1363,6 +1363,12 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
1363
1363
  }
1364
1364
  const existing = getRecord(ctx.sql, collection, recordId, schema);
1365
1365
  const isUpdate = existing !== null;
1366
+ if (updateOnly && !isUpdate) {
1367
+ return {
1368
+ success: false,
1369
+ error: `records.update: no record "${recordId}" in ${collection} \u2014 updates never create; use records.create.`
1370
+ };
1371
+ }
1366
1372
  const mergedData = isUpdate ? { ...existing.data, ...data } : { ...data };
1367
1373
  for (const col of columns) {
1368
1374
  if (col.readonly) continue;
@@ -2521,7 +2527,7 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
2521
2527
  if (!collection) return { success: false, error: "Missing required param: collection" };
2522
2528
  if (!recordId) return { success: false, error: "Missing required param: recordId" };
2523
2529
  if (!data) return { success: false, error: "Missing required param: data" };
2524
- return putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac);
2530
+ return putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac, false, true);
2525
2531
  }
2526
2532
  case "records.delete": {
2527
2533
  const collection = params.collection;
@@ -6186,10 +6192,10 @@ async function writeQuotaSummary(bucket, key, previousEtag, summary) {
6186
6192
  });
6187
6193
  return object ? { etag: object.etag, summary } : null;
6188
6194
  }
6189
- async function ensureQuotaSummary(bucket, storage, prefixes, forceMeasure = false, excludedMarkerKey) {
6195
+ async function ensureQuotaSummary(bucket, storage, prefixes, measure = "reuse", excludedMarkerKey) {
6190
6196
  for (let attempt = 0; attempt < 4; attempt++) {
6191
6197
  const current = await readQuotaSummary(bucket, storage.quotaKey);
6192
- if (!forceMeasure && current.summary && accountPrefixesEqual(current.summary.prefixes, prefixes)) {
6198
+ if (measure !== "force" && current.summary && accountPrefixesEqual(current.summary.prefixes, prefixes) && !(measure === "repairDirty" && current.summary.dirty && Date.now() - current.summary.measuredAt >= QUOTA_REPAIR_COOLDOWN_MS)) {
6193
6199
  return current;
6194
6200
  }
6195
6201
  const usedBytes = await measuredAllocationUsage(bucket, storage, prefixes, excludedMarkerKey);
@@ -6377,7 +6383,7 @@ async function reserveQuotaSummary(bucket, storage, prefixes, initial, chargeByt
6377
6383
  bucket,
6378
6384
  storage,
6379
6385
  prefixes,
6380
- false,
6386
+ "reuse",
6381
6387
  markerKey ?? void 0
6382
6388
  );
6383
6389
  if (!ensured) {
@@ -6402,7 +6408,7 @@ async function reserveQuotaSummary(bucket, storage, prefixes, initial, chargeByt
6402
6408
  bucket,
6403
6409
  storage,
6404
6410
  prefixes,
6405
- true,
6411
+ "force",
6406
6412
  markerKey ?? void 0
6407
6413
  );
6408
6414
  if (!refreshed?.summary) {
@@ -6495,7 +6501,7 @@ async function storageUsage(bucket, storage) {
6495
6501
  try {
6496
6502
  const prefixes = await allocationPrefixes(storage);
6497
6503
  if (prefixes === null) return null;
6498
- const current = await ensureQuotaSummary(bucket, storage, prefixes);
6504
+ const current = await ensureQuotaSummary(bucket, storage, prefixes, "repairDirty");
6499
6505
  return current?.summary?.usedBytes ?? null;
6500
6506
  } catch (error) {
6501
6507
  console.error("[files:quota] usage:", error);
@@ -7444,8 +7450,8 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
7444
7450
  }
7445
7451
 
7446
7452
  // src/server/utils/app-role.ts
7447
- async function resolveAppRole(env, userId) {
7448
- if (userId === env.OWNER_USER_ID) return "admin";
7453
+ async function resolveAppMembership(env, userId, signal) {
7454
+ if (userId === env.OWNER_USER_ID) return { member: true, role: "admin" };
7449
7455
  const stub = env.RECORD_ROOMS.get(env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`));
7450
7456
  try {
7451
7457
  const res = await stub.fetch(
@@ -7459,16 +7465,21 @@ async function resolveAppRole(env, userId) {
7459
7465
  body: JSON.stringify({
7460
7466
  tool: "records.get",
7461
7467
  params: { collection: "users", recordId: userId }
7462
- })
7468
+ }),
7469
+ signal
7463
7470
  })
7464
7471
  );
7465
7472
  const json = await res.json();
7466
- const role = json.data?.record?.data?.role;
7467
- return json.success && isWriterRole(role) ? role : "viewer";
7473
+ if (!json.success || !json.data?.record) return { member: false, role: "viewer" };
7474
+ const role = json.data.record.data?.role;
7475
+ return { member: true, role: isWriterRole(role) ? role : "viewer" };
7468
7476
  } catch {
7469
- return "viewer";
7477
+ return null;
7470
7478
  }
7471
7479
  }
7480
+ async function resolveAppRole(env, userId) {
7481
+ return (await resolveAppMembership(env, userId))?.role ?? "viewer";
7482
+ }
7472
7483
 
7473
7484
  // src/server/utils/ai.ts
7474
7485
  import { createAnthropic } from "@ai-sdk/anthropic";
@@ -7903,6 +7914,9 @@ function locateTrimmableArray(result) {
7903
7914
  }
7904
7915
  return void 0;
7905
7916
  }
7917
+ function utf8ByteLength(text) {
7918
+ return new TextEncoder().encode(text).byteLength;
7919
+ }
7906
7920
  function capToolResultSize(result, byteCap) {
7907
7921
  let serialized;
7908
7922
  try {
@@ -7911,7 +7925,7 @@ function capToolResultSize(result, byteCap) {
7911
7925
  return { success: false, error: "Tool result could not be serialized." };
7912
7926
  }
7913
7927
  if (typeof serialized !== "string") return result;
7914
- if (serialized.length <= byteCap) return result;
7928
+ if (utf8ByteLength(serialized) <= byteCap) return result;
7915
7929
  if (result && typeof result === "object") {
7916
7930
  const located = locateTrimmableArray(result);
7917
7931
  if (located) {
@@ -7920,7 +7934,7 @@ function capToolResultSize(result, byteCap) {
7920
7934
  const build = (k) => setPath(result, path, items.slice(0, k), { truncated: true, returned: k, total });
7921
7935
  const fits = (k) => {
7922
7936
  try {
7923
- return JSON.stringify(build(k)).length <= byteCap;
7937
+ return utf8ByteLength(JSON.stringify(build(k))) <= byteCap;
7924
7938
  } catch {
7925
7939
  return false;
7926
7940
  }
@@ -7940,7 +7954,7 @@ function capToolResultSize(result, byteCap) {
7940
7954
  return {
7941
7955
  success: false,
7942
7956
  truncated: true,
7943
- error: `Tool result exceeded ${byteCap} bytes (was ${serialized.length}). Retry with a narrower query (e.g. add a \`where\` filter, reduce \`limit\`, or call records.get for a single record).`,
7957
+ error: `Tool result exceeded ${byteCap} bytes (was ${utf8ByteLength(serialized)}). Retry with a narrower query (e.g. add a \`where\` filter, reduce \`limit\`, or call records.get for a single record).`,
7944
7958
  preview: serialized.slice(0, 2e3)
7945
7959
  };
7946
7960
  }
@@ -8092,10 +8106,15 @@ async function prepareMessagesWithCompaction(messages, config, options) {
8092
8106
  newSummary: { text, throughId }
8093
8107
  };
8094
8108
  } catch (err) {
8095
- console.error("prepareMessagesWithCompaction: summarizer failed, falling back to sliding window", err);
8109
+ console.error(
8110
+ "prepareMessagesWithCompaction: summarizer failed, falling back to sliding window",
8111
+ err
8112
+ );
8096
8113
  }
8097
8114
  } else {
8098
- console.warn("prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window");
8115
+ console.warn(
8116
+ "prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window"
8117
+ );
8099
8118
  }
8100
8119
  return {
8101
8120
  messages: applySlidingWindow(working, config.contextBudget, config.minKept)
@@ -9094,38 +9113,43 @@ function documentationLimiterErrorSummary(error) {
9094
9113
  });
9095
9114
  }
9096
9115
 
9097
- // src/documentation/worker/request-body.ts
9098
- var RequestBodyTooLargeError = class extends Error {
9116
+ // src/shared/bounded-body.ts
9117
+ var BodyTooLargeError = class extends Error {
9099
9118
  constructor(maxBytes) {
9100
- super(`Request body exceeds ${maxBytes} bytes`);
9119
+ super(`Body exceeds ${maxBytes} bytes`);
9101
9120
  this.maxBytes = maxBytes;
9102
- this.name = "RequestBodyTooLargeError";
9121
+ this.name = "BodyTooLargeError";
9103
9122
  }
9104
9123
  };
9105
- async function readBoundedRequestText(request2, maxBytes) {
9124
+ async function readBoundedBodyText(source, maxBytes) {
9106
9125
  if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0) {
9107
9126
  throw new TypeError("maxBytes must be a positive safe integer");
9108
9127
  }
9109
- const declared = request2.headers.get("content-length");
9128
+ const declared = source.headers.get("content-length");
9110
9129
  if (declared && /^\d+$/.test(declared.trim()) && Number(declared) > maxBytes) {
9111
- throw new RequestBodyTooLargeError(maxBytes);
9130
+ await source.body?.cancel().catch(() => void 0);
9131
+ throw new BodyTooLargeError(maxBytes);
9112
9132
  }
9113
- if (!request2.body) return "";
9114
- const reader = request2.body.getReader();
9133
+ if (!source.body) return "";
9134
+ const reader = source.body.getReader();
9115
9135
  const decoder = new TextDecoder();
9116
9136
  let bytes = 0;
9117
9137
  let text = "";
9118
- while (true) {
9119
- const chunk = await reader.read();
9120
- if (chunk.done) break;
9121
- bytes += chunk.value.byteLength;
9122
- if (bytes > maxBytes) {
9123
- await reader.cancel().catch(() => void 0);
9124
- throw new RequestBodyTooLargeError(maxBytes);
9138
+ try {
9139
+ while (true) {
9140
+ const chunk = await reader.read();
9141
+ if (chunk.done) break;
9142
+ bytes += chunk.value.byteLength;
9143
+ if (bytes > maxBytes) {
9144
+ await reader.cancel().catch(() => void 0);
9145
+ throw new BodyTooLargeError(maxBytes);
9146
+ }
9147
+ text += decoder.decode(chunk.value, { stream: true });
9125
9148
  }
9126
- text += decoder.decode(chunk.value, { stream: true });
9149
+ return text + decoder.decode();
9150
+ } finally {
9151
+ reader.releaseLock();
9127
9152
  }
9128
- return text + decoder.decode();
9129
9153
  }
9130
9154
 
9131
9155
  // src/documentation/worker/assistant-routes.ts
@@ -9165,13 +9189,13 @@ function registerDocumentationAssistantRoutes(app, resolveAuth, publicBasePath =
9165
9189
  }
9166
9190
  let body = null;
9167
9191
  try {
9168
- const raw = await readBoundedRequestText(c.req.raw, MAX_REQUEST_BYTES);
9192
+ const raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES);
9169
9193
  const parsed = JSON.parse(raw);
9170
9194
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
9171
9195
  body = parsed;
9172
9196
  }
9173
9197
  } catch (error) {
9174
- if (error instanceof RequestBodyTooLargeError) {
9198
+ if (error instanceof BodyTooLargeError) {
9175
9199
  return c.json({ error: `request exceeds ${MAX_REQUEST_BYTES} bytes` }, 413);
9176
9200
  }
9177
9201
  return c.json({ error: "request body must be valid JSON" }, 400);
@@ -9591,9 +9615,9 @@ function registerDocumentationMcpRoutes(app, publicBasePath = DOCUMENTATION_BASE
9591
9615
  }
9592
9616
  let raw;
9593
9617
  try {
9594
- raw = await readBoundedRequestText(c.req.raw, MAX_REQUEST_BYTES2);
9618
+ raw = await readBoundedBodyText(c.req.raw, MAX_REQUEST_BYTES2);
9595
9619
  } catch (error) {
9596
- if (error instanceof RequestBodyTooLargeError) {
9620
+ if (error instanceof BodyTooLargeError) {
9597
9621
  return mcpError(null, -32600, `Request exceeds ${MAX_REQUEST_BYTES2} bytes`, 413);
9598
9622
  }
9599
9623
  return mcpError(null, -32700, "Unable to read request body", 400);
@@ -9922,6 +9946,24 @@ async function verifyJwt(config, token) {
9922
9946
  }
9923
9947
  }
9924
9948
 
9949
+ // src/server/auth/agentToken.ts
9950
+ var AGENT_TOKEN_SCOPE = "agent";
9951
+ function agentTokenIssuer(issuer) {
9952
+ return `${issuer.replace(/\/+$/, "")}/agent`;
9953
+ }
9954
+ async function verifyAgentToken(config, token, targetOrigin) {
9955
+ const outcome = await verifyJwt(
9956
+ {
9957
+ ...config,
9958
+ issuer: agentTokenIssuer(config.issuer),
9959
+ audience: targetOrigin
9960
+ },
9961
+ token
9962
+ );
9963
+ if (!outcome.result || outcome.result.claims.scope === AGENT_TOKEN_SCOPE) return outcome;
9964
+ return { ...outcome, result: null, error: new Error("Invalid agent token scope") };
9965
+ }
9966
+
9925
9967
  // src/server/auth/internalAuth.ts
9926
9968
  var nodeCryptoPromise = null;
9927
9969
  async function loadNodeCrypto() {
@@ -10200,6 +10242,231 @@ function registerClientErrorRoute(app) {
10200
10242
  app.post(CLIENT_ERROR_PATH, (c) => handleClientErrorReport(c.req.raw));
10201
10243
  }
10202
10244
 
10245
+ // src/server/agent-tools.ts
10246
+ import { asSchema } from "ai";
10247
+
10248
+ // src/shared/agent-tool-protocol.ts
10249
+ var AGENT_TOOL_REQUEST_BODY_CAP = 64 * 1024;
10250
+ var AGENT_TOOL_RESPONSE_BODY_CAP = 1024 * 1024;
10251
+
10252
+ // src/server/agent-tools.ts
10253
+ function jsonResponse3(body, status = 200) {
10254
+ return rawJsonResponse(JSON.stringify(body), status);
10255
+ }
10256
+ function rawJsonResponse(body, status = 200) {
10257
+ return new Response(body, {
10258
+ status,
10259
+ headers: {
10260
+ "Cache-Control": "no-store",
10261
+ "Content-Type": "application/json; charset=utf-8"
10262
+ }
10263
+ });
10264
+ }
10265
+ function errorResponse(status, code) {
10266
+ const errors = {
10267
+ unauthenticated: "Authentication is required.",
10268
+ forbidden: "You are not allowed to use assistant tools.",
10269
+ access_check_unavailable: "Access could not be verified. Try again.",
10270
+ tool_not_found: "The requested tool is not available.",
10271
+ invalid_json: "The request body must be valid JSON.",
10272
+ invalid_tool_input: "The tool input is invalid.",
10273
+ payload_too_large: "The request body is too large.",
10274
+ tool_configuration_error: "Assistant tools are not configured correctly.",
10275
+ tool_execution_failed: "The tool could not be executed.",
10276
+ invalid_tool_result: "The tool returned an invalid result.",
10277
+ tool_result_too_large: "The tool returned a result that is too large."
10278
+ };
10279
+ return jsonResponse3({ ok: false, code, error: errors[code] }, status);
10280
+ }
10281
+ function parseToolRequestBody(text) {
10282
+ let parsed;
10283
+ try {
10284
+ parsed = JSON.parse(text);
10285
+ } catch {
10286
+ return void 0;
10287
+ }
10288
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
10289
+ if (!Object.hasOwn(parsed, "input")) return null;
10290
+ return { input: parsed.input };
10291
+ }
10292
+ function isAsyncIterable(value) {
10293
+ return value !== null && (typeof value === "object" || typeof value === "function") && Symbol.asyncIterator in value;
10294
+ }
10295
+ function jsonText(value) {
10296
+ try {
10297
+ const serialized = JSON.stringify(value);
10298
+ return typeof serialized === "string" ? serialized : void 0;
10299
+ } catch {
10300
+ return void 0;
10301
+ }
10302
+ }
10303
+ function executableTool(tools, name) {
10304
+ if (!Object.hasOwn(tools, name)) return void 0;
10305
+ const tool3 = tools[name];
10306
+ return typeof tool3.execute === "function" ? { ...tool3, execute: tool3.execute } : void 0;
10307
+ }
10308
+ function toolMetadata(tools) {
10309
+ return Object.entries(tools).flatMap(([name, tool3]) => {
10310
+ if (typeof tool3.execute !== "function") return [];
10311
+ const inputSchema = asSchema(tool3.inputSchema);
10312
+ const entry = {
10313
+ name,
10314
+ description: typeof tool3.description === "string" ? tool3.description : "",
10315
+ inputSchema: inputSchema.jsonSchema
10316
+ };
10317
+ if (tool3.outputSchema) entry.outputSchema = asSchema(tool3.outputSchema).jsonSchema;
10318
+ return [entry];
10319
+ }).sort((left, right) => left.name.localeCompare(right.name));
10320
+ }
10321
+ function createUserToolExecutor(env, userId, signal) {
10322
+ const roomId = env.RECORD_ROOMS.idFromName(`app:${env.DEEPSPACE_APP_ID}`);
10323
+ const room = env.RECORD_ROOMS.get(roomId);
10324
+ return async (toolName, params) => {
10325
+ const response = await room.fetch(
10326
+ new Request("https://internal/api/tools/execute", {
10327
+ method: "POST",
10328
+ headers: {
10329
+ "Content-Type": "application/json",
10330
+ "X-User-Id": userId
10331
+ },
10332
+ body: JSON.stringify({ tool: toolName, params }),
10333
+ signal
10334
+ })
10335
+ );
10336
+ return capToolResultSize(await response.json(), DEFAULT_CONTEXT_CONFIG.toolResultCap);
10337
+ };
10338
+ }
10339
+ async function resolveCallerTools(options, request2, env) {
10340
+ let access;
10341
+ try {
10342
+ access = await options.resolveAccess(request2, env);
10343
+ } catch {
10344
+ return errorResponse(500, "tool_configuration_error");
10345
+ }
10346
+ if (!access.ok) {
10347
+ return errorResponse(
10348
+ access.status,
10349
+ access.status === 401 ? "unauthenticated" : access.status === 403 ? "forbidden" : "access_check_unavailable"
10350
+ );
10351
+ }
10352
+ try {
10353
+ return options.buildTools(createUserToolExecutor(env, access.auth.userId, request2.signal));
10354
+ } catch {
10355
+ return errorResponse(500, "tool_configuration_error");
10356
+ }
10357
+ }
10358
+ function registerAgentToolRoutes(app, options) {
10359
+ app.get("/_deepspace/agent/tools", async (c) => {
10360
+ const tools = await resolveCallerTools(options, c.req.raw, c.env);
10361
+ if (tools instanceof Response) return tools;
10362
+ try {
10363
+ const serialized = jsonText({
10364
+ ok: true,
10365
+ app: { id: c.env.DEEPSPACE_APP_ID, name: c.env.APP_NAME },
10366
+ tools: toolMetadata(tools)
10367
+ });
10368
+ if (!serialized || utf8ByteLength(serialized) > AGENT_TOOL_RESPONSE_BODY_CAP) {
10369
+ return errorResponse(500, "tool_configuration_error");
10370
+ }
10371
+ return rawJsonResponse(serialized);
10372
+ } catch {
10373
+ return errorResponse(500, "tool_configuration_error");
10374
+ }
10375
+ });
10376
+ app.post("/_deepspace/agent/tools/:name", async (c) => {
10377
+ const tools = await resolveCallerTools(options, c.req.raw, c.env);
10378
+ if (tools instanceof Response) return tools;
10379
+ let tool3;
10380
+ try {
10381
+ tool3 = executableTool(tools, c.req.param("name"));
10382
+ } catch {
10383
+ return errorResponse(500, "tool_configuration_error");
10384
+ }
10385
+ if (!tool3) return errorResponse(404, "tool_not_found");
10386
+ let text;
10387
+ try {
10388
+ text = await readBoundedBodyText(c.req.raw, AGENT_TOOL_REQUEST_BODY_CAP);
10389
+ } catch (error) {
10390
+ return error instanceof BodyTooLargeError ? errorResponse(413, "payload_too_large") : errorResponse(400, "invalid_json");
10391
+ }
10392
+ const body = parseToolRequestBody(text);
10393
+ if (body === void 0) return errorResponse(400, "invalid_json");
10394
+ if (body === null) return errorResponse(400, "invalid_tool_input");
10395
+ let input = body.input;
10396
+ try {
10397
+ const validation = asSchema(tool3.inputSchema).validate;
10398
+ if (validation) {
10399
+ const result = await validation(input);
10400
+ if (!result.success) return errorResponse(400, "invalid_tool_input");
10401
+ input = result.value;
10402
+ }
10403
+ } catch {
10404
+ return errorResponse(400, "invalid_tool_input");
10405
+ }
10406
+ let output;
10407
+ try {
10408
+ output = await tool3.execute(input, {
10409
+ toolCallId: crypto.randomUUID(),
10410
+ messages: [],
10411
+ abortSignal: c.req.raw.signal
10412
+ });
10413
+ } catch {
10414
+ return errorResponse(500, "tool_execution_failed");
10415
+ }
10416
+ if (isAsyncIterable(output)) return errorResponse(500, "invalid_tool_result");
10417
+ try {
10418
+ if (tool3.outputSchema) {
10419
+ const validation = asSchema(tool3.outputSchema).validate;
10420
+ if (validation) {
10421
+ const result = await validation(output);
10422
+ if (!result.success) return errorResponse(500, "invalid_tool_result");
10423
+ output = result.value;
10424
+ }
10425
+ }
10426
+ } catch {
10427
+ return errorResponse(500, "invalid_tool_result");
10428
+ }
10429
+ const serialized = jsonText(output === void 0 ? null : output);
10430
+ if (!serialized) return errorResponse(500, "invalid_tool_result");
10431
+ if (utf8ByteLength(serialized) > DEFAULT_CONTEXT_CONFIG.toolResultCap) {
10432
+ return errorResponse(500, "tool_result_too_large");
10433
+ }
10434
+ return rawJsonResponse(`{"ok":true,"result":${serialized}}`);
10435
+ });
10436
+ app.all("/_deepspace/agent", () => errorResponse(404, "tool_not_found"));
10437
+ app.all("/_deepspace/agent/*", () => errorResponse(404, "tool_not_found"));
10438
+ }
10439
+
10440
+ // src/server/agent-target.ts
10441
+ var PRODUCTION_OFFICIAL_AGENT_ORIGINS = ["https://admin.deep.space"];
10442
+ var PRODUCTION_APP_DOMAIN = "app.space";
10443
+ function normalizeAgentTargetOrigin(value, policy) {
10444
+ if (typeof value !== "string" || !value) return null;
10445
+ let url;
10446
+ try {
10447
+ url = new URL(value);
10448
+ } catch {
10449
+ return null;
10450
+ }
10451
+ if (url.username || url.password || url.search || url.hash || url.pathname !== "/") return null;
10452
+ const hostname = url.hostname.toLowerCase();
10453
+ const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(hostname);
10454
+ if (loopback) {
10455
+ return policy.allowLoopback && ["http:", "https:"].includes(url.protocol) ? url.origin : null;
10456
+ }
10457
+ if (url.protocol !== "https:" || url.port) return null;
10458
+ if (policy.appDomain.toLowerCase() === PRODUCTION_APP_DOMAIN && PRODUCTION_OFFICIAL_AGENT_ORIGINS.includes(url.origin)) {
10459
+ return url.origin;
10460
+ }
10461
+ const suffix = `.${policy.appDomain.toLowerCase()}`;
10462
+ if (!hostname.endsWith(suffix)) return null;
10463
+ const label = hostname.slice(0, -suffix.length);
10464
+ return !label.includes(".") && validateAppName(label).valid ? url.origin : null;
10465
+ }
10466
+
10467
+ // src/shared/auth-session.ts
10468
+ var SESSION_COOKIE = "__Secure-better-auth.session_token";
10469
+
10203
10470
  // src/shared/log-events.ts
10204
10471
  var LOG_LEVELS = ["debug", "log", "info", "warn", "error"];
10205
10472
  var APP_LOG_EVENT_KEYS = [
@@ -10217,6 +10484,9 @@ export {
10217
10484
  ACCOUNT_STORAGE_LIMIT_BYTES,
10218
10485
  ACTION_ROUTES_BEARER_GUARD_MIGRATION_ID,
10219
10486
  ACTION_TOOLS_DELETE_WHERE_MIGRATION_ID,
10487
+ AGENT_TOKEN_SCOPE,
10488
+ AGENT_TOOL_REQUEST_BODY_CAP,
10489
+ AGENT_TOOL_RESPONSE_BODY_CAP,
10220
10490
  AI_CHATS_SCHEMA,
10221
10491
  AI_MESSAGES_SCHEMA,
10222
10492
  ALLOWED_BINDING_TYPES,
@@ -10268,6 +10538,7 @@ export {
10268
10538
  MSG_SYNC_UPDATE,
10269
10539
  MSG_YJS_AWARENESS,
10270
10540
  MSG_YJS_SYNC,
10541
+ PRODUCTION_OFFICIAL_AGENT_ORIGINS,
10271
10542
  PresenceRoom,
10272
10543
  REACTIONS_SCHEMA,
10273
10544
  READ_RECEIPTS_SCHEMA,
@@ -10286,6 +10557,7 @@ export {
10286
10557
  RegistryClientError,
10287
10558
  SDK_RUN_WORKER_FIRST,
10288
10559
  SECURE_ROOM_BOUNDARIES_MIGRATION_ID,
10560
+ SESSION_COOKIE,
10289
10561
  STRICT_APP_ID_RE,
10290
10562
  SYSTEM_ASSIGNED_COLUMNS,
10291
10563
  SYSTEM_COLLECTIONS,
@@ -10298,6 +10570,7 @@ export {
10298
10570
  USERS_COLUMNS,
10299
10571
  WORKER_OWNED_NOT_FOUND_MIGRATION_ID,
10300
10572
  YjsRoom,
10573
+ agentTokenIssuer,
10301
10574
  apiWorkerFetch,
10302
10575
  appendMessage,
10303
10576
  applyAiToolDefaults,
@@ -10331,6 +10604,7 @@ export {
10331
10604
  createDeepSpaceAuth,
10332
10605
  createEncoder,
10333
10606
  createScopedR2Handler,
10607
+ createUserToolExecutor,
10334
10608
  dataToColumnValues,
10335
10609
  decodeJwtPayload,
10336
10610
  deepSpaceAgentErrorSummary,
@@ -10376,6 +10650,7 @@ export {
10376
10650
  mintAppId,
10377
10651
  mintUlid,
10378
10652
  noopPermissionContext,
10653
+ normalizeAgentTargetOrigin,
10379
10654
  normalizeKnowledgeFolder,
10380
10655
  parseQuotaLimit,
10381
10656
  platformCorsPatterns,
@@ -10384,10 +10659,12 @@ export {
10384
10659
  priceBindingUsageEvent,
10385
10660
  readVarUint,
10386
10661
  readVarUint8Array,
10662
+ registerAgentToolRoutes,
10387
10663
  registerClientErrorRoute,
10388
10664
  registerDeepSpaceDocumentation,
10389
10665
  registryErrorJson,
10390
10666
  registryStub,
10667
+ resolveAppMembership,
10391
10668
  resolveAppName,
10392
10669
  resolveAppRole,
10393
10670
  resolveColumn,
@@ -10411,6 +10688,7 @@ export {
10411
10688
  validateAppName,
10412
10689
  validateBindingManifest,
10413
10690
  validateDoManifest,
10691
+ verifyAgentToken,
10414
10692
  verifyJwt,
10415
10693
  writeVarUint,
10416
10694
  writeVarUint8Array