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/CHANGELOG.md +14 -0
- package/dist/{chunk-YEJGFP6X.js → chunk-UWOOAXHQ.js} +2 -2
- package/dist/{chunk-YEJGFP6X.js.map → chunk-UWOOAXHQ.js.map} +1 -1
- package/dist/cli.js +24 -47
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +26 -12
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +63 -3
- package/dist/server.js +106 -4
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +91 -9
- package/dist/worker.js +156 -8
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
1579
|
-
|
|
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
|
-
|
|
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,
|