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/server.d.ts CHANGED
@@ -304,7 +304,8 @@ interface StorageAdmission {
304
304
  * POST /api/files/multipart/complete → assemble the parts
305
305
  * DELETE /api/files/multipart → abandon a chunked upload
306
306
  * GET /api/files → list (prefix + optional user prefix)
307
- * GET /api/files/:key → download (validated against prefix)
307
+ * GET /api/files/:key → download (validated against prefix; Range-aware)
308
+ * HEAD /api/files/:key → the download's headers, no body
308
309
  * DELETE /api/files/:key → delete (validated against prefix)
309
310
  *
310
311
  * ## One transport discipline
@@ -531,6 +532,26 @@ interface YjsLeavePayload {
531
532
  fieldName: string;
532
533
  }
533
534
 
535
+ /**
536
+ * Platform API error normalization — the one chokepoint that turns the
537
+ * api-worker's error envelope into a render-safe + branch-safe shape.
538
+ *
539
+ * The platform emits errors as `{ error: <machine slug>, message?: <human>,
540
+ * ...details }` (e.g. 402 `{ error: 'insufficient_credits', message:
541
+ * 'Insufficient credits.', availableCredits, requiredCredits }`; some routes
542
+ * send the bare slug with no `message` at all, e.g. 409
543
+ * `{ error: 'owner_connect_not_ready' }`). Consumers must never show the slug
544
+ * to a person or make an agent parse the sentence — this module separates the
545
+ * two once, for the integration client, server actions, billing hooks, and the
546
+ * CLI.
547
+ */
548
+ /** One structured validation issue (Zod shape) from a `validation_failed` response. */
549
+ interface ApiErrorIssue {
550
+ path?: string[];
551
+ message: string;
552
+ code?: string;
553
+ }
554
+
534
555
  /**
535
556
  * Server Action Types
536
557
  *
@@ -555,7 +576,16 @@ type ActionResult<TData = unknown> = {
555
576
  } | {
556
577
  success: false;
557
578
  data?: never;
579
+ /** Human-readable error, safe to render directly. */
558
580
  error: string;
581
+ /** Machine slug for branching, when the failing tool supplied one. */
582
+ code?: string;
583
+ /** HTTP status from an upstream platform request, when applicable. */
584
+ status?: number;
585
+ /** Structured fields supplied with the error response. */
586
+ details?: Record<string, unknown>;
587
+ /** Validation issues supplied with a `validation_failed` response. */
588
+ issues?: ApiErrorIssue[];
559
589
  };
560
590
  /** Shape of the data field for `tools.query`. */
561
591
  interface QueryActionData<T = Record<string, unknown>> {
@@ -610,7 +640,9 @@ interface ActionTools {
610
640
  * api-worker. On success, `result.data` is the integration's response
611
641
  * body directly — there is no `.response` wrapper. So an OpenAI call
612
642
  * yields `result.data.choices`, a Freepik image call yields
613
- * `result.data.images`, etc.
643
+ * `result.data.images`, etc. On failure, `result.error` is human-readable;
644
+ * branch on `result.code` and inspect `status`, `details`, or `issues` when
645
+ * present.
614
646
  */
615
647
  integration<T = unknown>(endpoint: string, data?: unknown): Promise<ActionResult<T>>;
616
648
  /**
@@ -3378,6 +3410,34 @@ interface VerifyOutcome {
3378
3410
  */
3379
3411
  declare function verifyJwt(config: JwtVerifierConfig, token: string | null | undefined): Promise<VerifyOutcome>;
3380
3412
 
3413
+ /**
3414
+ * Session-cookie identity for header-less file reads.
3415
+ *
3416
+ * `<img>`, `<audio>`, `<video>`, and `<a href>` cannot send `Authorization`,
3417
+ * but the browser attaches the app-origin Better Auth session cookie to every
3418
+ * same-origin load. This exchanges that cookie for the same 15-minute JWT the
3419
+ * client already holds and returns only the verified identity.
3420
+ *
3421
+ * Bearer always wins: this applies only when no `Authorization` header is
3422
+ * present, only to GET/HEAD, and only when `Sec-Fetch-Site` is `same-origin`
3423
+ * or `none`. `app.space` is not on the Public Suffix List, so a sibling
3424
+ * `evil.app.space` is same-SITE and `SameSite=Lax` alone would let its
3425
+ * `<img src>` carry the victim's cookie; `Sec-Fetch-Site` cannot be set by
3426
+ * page script. A browser that omits it (Safari before 16.4) and a cross-site
3427
+ * top-level link both get 401 by design.
3428
+ */
3429
+
3430
+ type SessionReadEnv = AuthWorkerEnv & {
3431
+ AUTH_JWT_PUBLIC_KEY: string;
3432
+ AUTH_JWT_ISSUER: string;
3433
+ };
3434
+ /**
3435
+ * Identify a same-origin GET/HEAD by the app-origin session cookie. Returns
3436
+ * `null` — never throws — whenever the request does not qualify or the
3437
+ * exchange fails. Use it only as the fallback after bearer verification.
3438
+ */
3439
+ declare function resolveSessionReadAuth(req: Request, env: SessionReadEnv): Promise<VerifyResult | null>;
3440
+
3381
3441
  declare const AGENT_TOKEN_SCOPE = "agent";
3382
3442
  /** A separate issuer keeps agent credentials invalid at ordinary platform APIs. */
3383
3443
  declare function agentTokenIssuer(issuer: string): string;
@@ -4664,4 +4724,4 @@ declare class RefundError extends Error {
4664
4724
  constructor(message: string, status: number);
4665
4725
  }
4666
4726
 
4667
- export { ACCOUNT_STORAGE_LIMIT_BYTES, AGENT_TOKEN_SCOPE, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppMembership, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, type BindingJsonValue, CHANNELS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DELETE_WHERE_LIMIT, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, type GetActionData, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, type KnowledgeAddOptions, type KnowledgeAddResult, type KnowledgeClient, type KnowledgeEnv, KnowledgeError, type KnowledgeItem, type KnowledgeListOptions, type KnowledgeListResult, type KnowledgeSearchChunk, type KnowledgeSearchOptions, type KnowledgeSearchResult, type KnowledgeStatus, MAX_APP_FILE_BYTES, MAX_BINDING_NAME_LENGTH, MAX_DELETE_WHERE_LIMIT, MAX_DEPLOY_ASSET_FILE_BYTES, MAX_ENV_VAR_BYTES, MAX_UPLOAD_PARTS, MAX_UPLOAD_REQUEST_BYTES, MESSAGES_SCHEMA, type MutateActionData, type PermissionContext, type PermissionLevel, type PlanInfo, type PlatformWorkerEnv, type PrefixResult, type PresencePeer, PresenceRoom, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, REGISTRY_INSTANCE, RESERVED_BINDING_NAMES, RESOURCE_ID_RE, type RecordContext, RecordRoom, type RecordRoomConfig, RefundError, type RefundOpts, type RefundResult, RegistryClientError, type ResolvedColumn, type RolePermissions, type RunMigrationsResult, SECRET_NAME_RE, STRICT_APP_ID_RE, SYSTEM_ASSIGNED_COLUMNS, SYSTEM_COLLECTION_SCHEMAS, SYSTEM_MAINTAINED_COLUMNS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedKnowledgeClient, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotResult, type StorageAdmission, type StoredRecord, SubscriptionAuthError, type SubscriptionContext, type SubscriptionRead, SubscriptionRequiredError, type SubscriptionStatus, type Summarizer, TEST_ACCOUNT_EMAIL_SUFFIX, type TokenDebugInfo, type ToolResult, type ToolSchema, type ToolsApiContext, UPLOAD_PART_BYTES, USERS_COLUMNS, type User, type UserAttachment, type UserContext, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, type YjsContext, YjsRoom, agentTokenIssuer, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, armCronRoom, authWorkerFetch, bindingManifestFromOutputConfig, broadcastChange, broadcastUserList, broadcastYjsUpdate, buildCronContext, buildTableSelect, buildUiParts, callRegistry, canCreate, canDelete, canRead, canUpdate, cancelSubscription, capToolResultSize, captureScreenshot, checkFieldPermissions, checkUnclaimedOwnerTransition, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDeepSpaceAI, createDeepSpaceAuth, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deepSpaceAgentErrorSummary, deleteChatCascade, deleteRecord, enqueueJob, epochSeconds, executeQuery, folderFilter, formatBytes, getAllUsers, getChat, getOrCreateYjsDoc, getRecord, getRolePermissions, getSubscription, getUser, getYjsDocKey, handleApiRequest, handleDelete, handlePut, handleSetRole, handleSubscribe, handleToolsRequest, handleUnsubscribe, handleUserList, handleUserUpdate, handleYjsBinaryMessage, handleYjsJoin, handleYjsLeave, isAutoProvision, isFilesVerbPath, isOwner, isTestAccountClaims, isTestAccountEmail, isTestAccountTier, knowledge, lintSchema, lintSchemaSet, lintSchemas, loadMessages, makeDefaultSummarizer, matchOrigin, meterAi, meterUsage, meterVectorize, mintAppId, mintUlid, noopPermissionContext, normalizeKnowledgeFolder, parseQuotaLimit, platformCorsPatterns, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, putRecord, readRecord, recordMatchesSubscription, refundInvoice, registerUser, registryErrorJson, registryStub, requireSubscription, resolveAppMembership, resolveAppName, resolveAppRole, resolveColumn, rowToData, runMigrations, saveYjsDoc, storageLimitForTier, storageQuotaMessage, streamDeepSpaceAgent, timingSafeEqualHex, timingSafeEqualStrings, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyAgentToken, verifyJwt };
4727
+ export { ACCOUNT_STORAGE_LIMIT_BYTES, AGENT_TOKEN_SCOPE, AI_CHATS_SCHEMA, AI_MESSAGES_SCHEMA, ALLOWED_BINDING_TYPES, APP_ID_RE, APP_NAME_RULES, AUTO_PROVISIONABLE_TYPES, AUTO_PROVISION_SENTINEL, type ActionContext, type ActionHandler, type ActionResult, type ActionTools, type ApiWorkerEnv, type AppMembership, type AppNameResolution, type AppNameValidation, type AuthWorkerEnv, BASE_USERS_SCHEMA, BUILT_IN_TOOLS, BaseRoom, type BindingJsonValue, CHANNELS_SCHEMA, CHANNEL_MEMBERS_SCHEMA, COST_RATES, CancelSubscriptionError, type CancelSubscriptionOpts, type CancelSubscriptionResult, CanvasRoom, type CanvasShape, type ChatContextConfig, type ChatMessageRow, type ChatRow, type ChatTurn, type CollectionSchema, type ColumnDefinition, type ColumnInterpretation, type ComposioToolsOptions, type CronContext, type CronExecution, CronRoom, type CronRoomConfig, type CronTask, type CustomBinding, type CustomBindingManifest, DEFAULT_CONTEXT_CONFIG, DEFAULT_DELETE_WHERE_LIMIT, DEFAULT_DO_MANIFEST, DEFAULT_QUERY_LIMIT, DEPLOYED_APPS_DEFAULTS, type DOBindings, type DOManifest, type DOManifestEntry, type DebugApiContext, type DeepSpaceAIEnv, type DeepSpaceAIOptions, type DeepSpaceAgentDiagnosticContext, DeepSpaceAgentModelError, DeepSpaceAgentProfileError, type DeepSpaceAgentStream, type DeepSpaceAgentStreamOptions, type DeepSpaceAuth, type DeepSpaceAuthConfig, type DoMigrationDirective, type DoMigrationPlan, type ExistingDOBinding, type GetActionData, type Job, type JobContext, JobRoom, type JobRoomConfig, type JobStatus, type JwtClaims, type JwtVerifierConfig, type KnowledgeAddOptions, type KnowledgeAddResult, type KnowledgeClient, type KnowledgeEnv, KnowledgeError, type KnowledgeItem, type KnowledgeListOptions, type KnowledgeListResult, type KnowledgeSearchChunk, type KnowledgeSearchOptions, type KnowledgeSearchResult, type KnowledgeStatus, MAX_APP_FILE_BYTES, MAX_BINDING_NAME_LENGTH, MAX_DELETE_WHERE_LIMIT, MAX_DEPLOY_ASSET_FILE_BYTES, MAX_ENV_VAR_BYTES, MAX_UPLOAD_PARTS, MAX_UPLOAD_REQUEST_BYTES, MESSAGES_SCHEMA, type MutateActionData, type PermissionContext, type PermissionLevel, type PlanInfo, type PlatformWorkerEnv, type PrefixResult, type PresencePeer, PresenceRoom, type QueryActionData, REACTIONS_SCHEMA, READ_RECEIPTS_SCHEMA, REGISTRY_INSTANCE, RESERVED_BINDING_NAMES, RESOURCE_ID_RE, type RecordContext, RecordRoom, type RecordRoomConfig, RefundError, type RefundOpts, type RefundResult, RegistryClientError, type ResolvedColumn, type RolePermissions, type RunMigrationsResult, SECRET_NAME_RE, STRICT_APP_ID_RE, SYSTEM_ASSIGNED_COLUMNS, SYSTEM_COLLECTION_SCHEMAS, SYSTEM_MAINTAINED_COLUMNS, SYSTEM_MANAGED_COLUMNS, SchemaRegistry, type ScopeContext, type ScopedKnowledgeClient, type ScopedR2Auth, type ScopedR2Config, type ScopedR2Handler, type ScreenshotEnv, type ScreenshotResult, type StorageAdmission, type StoredRecord, SubscriptionAuthError, type SubscriptionContext, type SubscriptionRead, SubscriptionRequiredError, type SubscriptionStatus, type Summarizer, TEST_ACCOUNT_EMAIL_SUFFIX, type TokenDebugInfo, type ToolResult, type ToolSchema, type ToolsApiContext, UPLOAD_PART_BYTES, USERS_COLUMNS, type User, type UserAttachment, type UserContext, type ValidationError, type VerifiedAuth, type VerifyOutcome, type VerifyResult, type Viewport, type YjsContext, YjsRoom, agentTokenIssuer, apiWorkerFetch, appendMessage, applyAiToolDefaults, applySlidingWindow, armCronRoom, authWorkerFetch, bindingManifestFromOutputConfig, broadcastChange, broadcastUserList, broadcastYjsUpdate, buildCronContext, buildTableSelect, buildUiParts, callRegistry, canCreate, canDelete, canRead, canUpdate, cancelSubscription, capToolResultSize, captureScreenshot, checkFieldPermissions, checkUnclaimedOwnerTransition, coerceValue, collectionTableName, columnId, composioTools, computeDoMigration, computeHmacHex, createChat, createDeepSpaceAI, createDeepSpaceAuth, createScopedR2Handler, dataToColumnValues, decodeJwtPayload, deepSpaceAgentErrorSummary, deleteChatCascade, deleteRecord, enqueueJob, epochSeconds, executeQuery, folderFilter, formatBytes, getAllUsers, getChat, getOrCreateYjsDoc, getRecord, getRolePermissions, getSubscription, getUser, getYjsDocKey, handleApiRequest, handleDelete, handlePut, handleSetRole, handleSubscribe, handleToolsRequest, handleUnsubscribe, handleUserList, handleUserUpdate, handleYjsBinaryMessage, handleYjsJoin, handleYjsLeave, isAutoProvision, isFilesVerbPath, isOwner, isTestAccountClaims, isTestAccountEmail, isTestAccountTier, knowledge, lintSchema, lintSchemaSet, lintSchemas, loadMessages, makeDefaultSummarizer, matchOrigin, meterAi, meterUsage, meterVectorize, mintAppId, mintUlid, noopPermissionContext, normalizeKnowledgeFolder, parseQuotaLimit, platformCorsPatterns, platformWorkerFetch, prepareMessagesWithCompaction, priceBindingUsageEvent, putRecord, readRecord, recordMatchesSubscription, refundInvoice, registerUser, registryErrorJson, registryStub, requireSubscription, resolveAppMembership, resolveAppName, resolveAppRole, resolveColumn, resolveSessionReadAuth, rowToData, runMigrations, saveYjsDoc, storageLimitForTier, storageQuotaMessage, streamDeepSpaceAgent, timingSafeEqualHex, timingSafeEqualStrings, totalChars, truncateOldToolResults, turnsToCoreMessages, unwrapToolOutput, updateChat, validateAppName, validateBindingManifest, validateDoManifest, verifyAgentToken, verifyJwt };
package/dist/server.js CHANGED
@@ -967,7 +967,7 @@ function createScopedR2Handler(config) {
967
967
  if (!subpath && request2.method === "GET") {
968
968
  return handleList(bucket, prefix, excludedPrefixes, url, scope, auth);
969
969
  }
970
- if (subpath && request2.method === "GET") {
970
+ if (subpath && (request2.method === "GET" || request2.method === "HEAD")) {
971
971
  if (!isKeyWithinScope(subpath, prefix, excludedPrefixes)) {
972
972
  return Response.json(
973
973
  { error: "Access denied: key outside scope" },
@@ -1574,11 +1574,64 @@ async function handleList(bucket, prefix, excludedPrefixes, url, scope, auth) {
1574
1574
  { headers: CORS_HEADERS2 }
1575
1575
  );
1576
1576
  }
1577
+ function parseByteRange(header, size) {
1578
+ const [, first, last] = /^bytes=(\d*)-(\d*)$/.exec(header.trim()) ?? [];
1579
+ if (first === void 0 || first === "" && last === "") return void 0;
1580
+ const offset = first === "" ? Math.max(0, size - Number(last)) : Number(first);
1581
+ if (offset >= size) return "unsatisfiable";
1582
+ const end = first === "" || last === "" ? size - 1 : Math.min(Number(last), size - 1);
1583
+ return end < offset ? void 0 : { offset, length: end - offset + 1 };
1584
+ }
1577
1585
  async function handleDownload(request2, bucket, key, scope) {
1578
- const object = await bucket.get(key);
1579
- if (!object) {
1586
+ if (request2.method === "HEAD") {
1587
+ const object = await bucket.head(key);
1588
+ if (!object) {
1589
+ return Response.json({ error: "File not found" }, { status: 404, headers: CORS_HEADERS2 });
1590
+ }
1591
+ const headers2 = downloadHeaders(object, key, scope);
1592
+ if (scope === "app" && request2.headers.get("if-none-match") === object.httpEtag) {
1593
+ return new Response(null, { status: 304, headers: headers2 });
1594
+ }
1595
+ headers2.set("Content-Length", String(object.size));
1596
+ return new Response(null, { status: 200, headers: headers2 });
1597
+ }
1598
+ const rangeHeader = request2.headers.get("range");
1599
+ if (rangeHeader === null) {
1600
+ return wholeDownload(request2, await bucket.get(key), key, scope);
1601
+ }
1602
+ const head = await bucket.head(key);
1603
+ if (!head) {
1580
1604
  return Response.json({ error: "File not found" }, { status: 404, headers: CORS_HEADERS2 });
1581
1605
  }
1606
+ if (scope === "app" && request2.headers.get("if-none-match") === head.httpEtag) {
1607
+ return new Response(null, { status: 304, headers: downloadHeaders(head, key, scope) });
1608
+ }
1609
+ const ifRange = request2.headers.get("if-range");
1610
+ if (ifRange !== null && ifRange !== head.httpEtag) {
1611
+ return wholeDownload(request2, await bucket.get(key), key, scope);
1612
+ }
1613
+ const range = parseByteRange(rangeHeader, head.size);
1614
+ if (range === "unsatisfiable") {
1615
+ const headers2 = { ...CORS_HEADERS2, "Content-Range": `bytes */${head.size}` };
1616
+ return new Response(null, { status: 416, headers: headers2 });
1617
+ }
1618
+ if (!range) {
1619
+ return wholeDownload(request2, await bucket.get(key), key, scope);
1620
+ }
1621
+ const conditional = await bucket.get(key, {
1622
+ range,
1623
+ onlyIf: { etagMatches: head.etag }
1624
+ });
1625
+ if (!conditional || !("body" in conditional)) {
1626
+ return wholeDownload(request2, await bucket.get(key), key, scope);
1627
+ }
1628
+ const headers = downloadHeaders(conditional, key, scope);
1629
+ const end = range.offset + range.length - 1;
1630
+ headers.set("Content-Range", `bytes ${range.offset}-${end}/${conditional.size}`);
1631
+ headers.set("Content-Length", String(range.length));
1632
+ return new Response(conditional.body, { status: 206, headers });
1633
+ }
1634
+ function downloadHeaders(object, key, scope) {
1582
1635
  const headers = new Headers();
1583
1636
  const storedType = resolveMimeType(object.httpMetadata?.contentType ?? "");
1584
1637
  const mustDownload = DANGEROUS_MIME_TYPES.has(storedType);
@@ -1596,10 +1649,19 @@ async function handleDownload(request2, bucket, key, scope) {
1596
1649
  contentDisposition(originalName, mustDownload ? "attachment" : "inline")
1597
1650
  );
1598
1651
  if (mustDownload) headers.set("Content-Security-Policy", "sandbox; default-src 'none'");
1652
+ headers.set("Accept-Ranges", "bytes");
1653
+ return headers;
1654
+ }
1655
+ function wholeDownload(request2, object, key, scope) {
1656
+ if (!object) {
1657
+ return Response.json({ error: "File not found" }, { status: 404, headers: CORS_HEADERS2 });
1658
+ }
1659
+ const headers = downloadHeaders(object, key, scope);
1599
1660
  if (scope === "app" && request2.headers.get("if-none-match") === object.httpEtag) {
1600
1661
  return new Response(null, { status: 304, headers });
1601
1662
  }
1602
- return new Response(object.body, { headers });
1663
+ headers.set("Content-Length", String(object.size));
1664
+ return new Response(object.body, { status: 200, headers });
1603
1665
  }
1604
1666
 
1605
1667
  // src/server/utils/proxies.ts
@@ -8423,6 +8485,45 @@ async function verifyJwt(config, token) {
8423
8485
  }
8424
8486
  }
8425
8487
 
8488
+ // src/shared/auth-session.ts
8489
+ var SESSION_COOKIE = "__Secure-better-auth.session_token";
8490
+
8491
+ // src/server/auth/sessionReadAuth.ts
8492
+ var TTL_MS = 5 * 6e4;
8493
+ var sessions = /* @__PURE__ */ new Map();
8494
+ async function exchange(session, env) {
8495
+ try {
8496
+ const res = await authWorkerFetch(env, "/api/auth/token", {
8497
+ method: "POST",
8498
+ headers: { Cookie: `${SESSION_COOKIE}=${session}` },
8499
+ signal: AbortSignal.timeout(1e4)
8500
+ });
8501
+ const { token } = res.ok ? await res.json() : {};
8502
+ if (typeof token !== "string") return null;
8503
+ const config = { publicKey: env.AUTH_JWT_PUBLIC_KEY, issuer: env.AUTH_JWT_ISSUER };
8504
+ return (await verifyJwt(config, token)).result;
8505
+ } catch {
8506
+ return null;
8507
+ }
8508
+ }
8509
+ async function resolveSessionReadAuth(req, env) {
8510
+ const site = req.headers.get("Sec-Fetch-Site");
8511
+ if (req.method !== "GET" && req.method !== "HEAD") return null;
8512
+ if (req.headers.has("Authorization") || site !== "same-origin" && site !== "none") return null;
8513
+ const session = (req.headers.get("Cookie") ?? "").split(";").find((part) => part.trim().startsWith(`${SESSION_COOKIE}=`))?.trim().slice(SESSION_COOKIE.length + 1);
8514
+ if (!session) return null;
8515
+ const now = Date.now();
8516
+ const cached = sessions.get(session);
8517
+ if (cached && cached.expiresAt > now) return cached.promise;
8518
+ if (sessions.size >= 500) sessions.clear();
8519
+ const promise = exchange(session, env).then((result) => {
8520
+ if (!result) sessions.delete(session);
8521
+ return result;
8522
+ });
8523
+ sessions.set(session, { promise, expiresAt: now + TTL_MS });
8524
+ return promise;
8525
+ }
8526
+
8426
8527
  // src/server/auth/agentToken.ts
8427
8528
  var AGENT_TOKEN_SCOPE = "agent";
8428
8529
  function agentTokenIssuer(issuer) {
@@ -8931,6 +9032,7 @@ export {
8931
9032
  resolveAppName,
8932
9033
  resolveAppRole,
8933
9034
  resolveColumn,
9035
+ resolveSessionReadAuth,
8934
9036
  rowToData,
8935
9037
  runMigrations,
8936
9038
  saveYjsDoc,