@standardagents/builder 0.41.6 → 0.41.8
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/built-in-routes.js +189 -40
- package/dist/built-in-routes.js.map +1 -1
- package/dist/{discovery-CIGNVJfG.d.ts → discovery-D5pmuazY.d.ts} +1 -1
- package/dist/{index-By8TkPrK.d.ts → index-ChHAVogf.d.ts} +5 -11
- package/dist/index.d.ts +5 -5
- package/dist/index.js +212 -21
- package/dist/index.js.map +1 -1
- package/dist/packing.d.ts +3 -3
- package/dist/plugin.js +9 -1
- package/dist/plugin.js.map +1 -1
- package/dist/resolver-BMZAzKD3.d.ts +4522 -0
- package/dist/runtime.d.ts +10 -4517
- package/dist/runtime.js +204 -21
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +2 -2
- package/dist/{types-D1ABHvAH.d.ts → types-Dhd0M369.d.ts} +1 -1
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _standardagents_spec from '@standardagents/spec';
|
|
2
2
|
import { ThreadState, ErrorOrigin, ToolResult as ToolResult$1, VariableDefinition, HookName, HookSignatures, HookMessage, HookToolCall, HookToolResult, CodeExecutionOptions, CodeExecutionResult, InjectMessageInput, QueueMessageInput, SubagentRegistryEntry, SubagentRelationship, PackageSignature, ProviderUsagePricing, ThreadUser, AgentDefinition, SkillMetadata, SkillFileInput, ControllerContext, Controller, ThreadEndpointHandler } from '@standardagents/spec';
|
|
3
|
-
import { N as NamespacedRegistry } from './types-
|
|
3
|
+
import { N as NamespacedRegistry } from './types-Dhd0M369.js';
|
|
4
4
|
import { DurableObjectStorage } from '@cloudflare/workers-types';
|
|
5
5
|
import { ZodObject, ZodRawShape } from 'zod';
|
|
6
6
|
|
|
@@ -1267,15 +1267,6 @@ interface RouterThreadAccess {
|
|
|
1267
1267
|
thread: Record<string, unknown>;
|
|
1268
1268
|
}
|
|
1269
1269
|
|
|
1270
|
-
/**
|
|
1271
|
-
* Router and endpoint definition module for AgentBuilder.
|
|
1272
|
-
*
|
|
1273
|
-
* This module re-exports endpoint types from @standardagents/spec and provides
|
|
1274
|
-
* the runtime router implementation for handling HTTP requests.
|
|
1275
|
-
*
|
|
1276
|
-
* @module
|
|
1277
|
-
*/
|
|
1278
|
-
|
|
1279
1270
|
/**
|
|
1280
1271
|
* Durable Object namespace interface.
|
|
1281
1272
|
* This is Cloudflare-specific and used by the builder runtime.
|
|
@@ -1580,6 +1571,9 @@ interface DurableUserHubRpc {
|
|
|
1580
1571
|
limit: number;
|
|
1581
1572
|
offset: number;
|
|
1582
1573
|
}>;
|
|
1574
|
+
setGrant(userId: string, grant: _standardagents_spec.CredentialGrant, secret: string): Promise<void>;
|
|
1575
|
+
deleteGrant(userId: string, name: string): Promise<void>;
|
|
1576
|
+
listGrants(userId: string): Promise<Array<_standardagents_spec.CredentialGrant>>;
|
|
1583
1577
|
}
|
|
1584
1578
|
/**
|
|
1585
1579
|
* Thread registry entry from DurableAgentBuilder.
|
|
@@ -1985,4 +1979,4 @@ declare function defineController<Env extends ThreadEnv = ThreadEnv>(controller:
|
|
|
1985
1979
|
*/
|
|
1986
1980
|
declare function createThreadEndpointHandler<Env extends ThreadEnv = ThreadEnv>(handler: ThreadEndpointHandler): BuilderController<Env>;
|
|
1987
1981
|
|
|
1988
|
-
export { type AuthUser as A, type BuilderController as B, CLIENT_STREAM_CHUNK_BYTES as C, type FlowResult as D, type TelemetryEvent as E, type FlowState as F, type Env as G, type FileRecord as H, type ImageMetadata as I, type AttachmentRef as J, type GrepResult as K, type LLMResponse as L, type Message as M, type FileStats as N, type TextContentPart as O, type ImageContentPart as P, type MultimodalContent as Q, type RequestContext as R, type StorageBackend as S, type
|
|
1982
|
+
export { type AuthUser as A, type BuilderController as B, CLIENT_STREAM_CHUNK_BYTES as C, type FlowResult as D, type TelemetryEvent as E, type FlowState as F, type Env as G, type FileRecord as H, type ImageMetadata as I, type AttachmentRef as J, type GrepResult as K, type LLMResponse as L, type Message as M, type FileStats as N, type TextContentPart as O, type ImageContentPart as P, type MultimodalContent as Q, type RequestContext as R, type StorageBackend as S, type ThreadEndpointContext as T, type MessageContent as U, type ProxyStreamReceiver as V, type ProxyStreamFrame as W, type ProxyStreamTarget as X, type ProxyStreamOpenResult as Y, type SkillStorageScope as Z, type BuilderControllerContext as a, type ThreadEnv as b, createThreadEndpointHandler as c, defineController as d, type BuilderThreadEndpointHandler as e, authenticate as f, requireAdmin as g, endpointCallerFromAuth as h, type AuthContext as i, callClient as j, callClientStream as k, encodeStreamChunk as l, decodeStreamChunk as m, type ClientToolRequest as n, type ClientToolResponse as o, type ClientStreamRequest as p, type ClientStreamResponse as q, requireAuth as r, supportsClientForwarding as s, type ClientDuplex as t, type ClientForwarding as u, type Agent as v, type ThreadInstance as w, type ThreadMetadata as x, type ToolCall as y, type ToolResult as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ModelDefinition, AgentDefinition } from './
|
|
2
|
-
export { AgentBuilderEnv, AgentBuilderEvent, BroadcastOptions, CodeExecutionBridge, DurableAgentBuilder, DurableThread, DurableUserHub, FlowStateSdk, FlowStateWithSdk, HandlerSide, HubClientInfo, HumanSide, ImageContextConfig, InjectMessageOptions, LLMProviderInterface, NamespaceResolutionError, PromptContent, PromptDefinition, PromptIncludePart, PromptPart, PromptSide, PromptToolConfig, Provider, ProviderContentPart, ProviderFilePart, ProviderImagePart, ProviderRegistry, ProviderTextPart, SessionToolBinding, SessionToolConfig, SideConfig, SubagentRelationship, SubagentToolConfig, SubpromptConfig, ThreadEventPayload, ThreadRegistryEntry, ThreadWatchdog, ThreadWatchdogState, ToolConfig, UpdateThreadParams, User, WatchdogCheckin, WatchdogProbeResult, applyRuntimeCors, buildImageDescription, canAccessThread, cat, createNamespaceContext, emitThreadEvent, enhanceFlowState, exists, find, forceTurn, generateImageDescription, getFileStats, getMessages, getMessagesToSummarize, getShortName, getThumbnail, getUnsummarizedImageAttachments, getVisibleAgentNames, getVisibleModelNames, getVisiblePromptNames, getVisibleToolNames, grep, hasImageAttachments, head, injectMessage, isAdminOnlyApiRoute, isHostedInstance, isPublicApiRoute, isQualifiedName, isSameOriginBrowserRequest, isTrustedLocalDevelopmentRequest, linkFile, mkdir, move, optimizeImageContext, parseQualifiedName, qualifyName, queueTool, readFile, readdir, reloadHistory, rename, replaceImagesWithDescriptions, resolveAgent, resolveHook, resolveModel, resolvePrompt, resolveTool, rmdir, runtimeCorsHeaders, runtimePreflightResponse, stat, tail, unlink, updateThread, writeFile, writeImage } from './
|
|
1
|
+
import { M as ModelDefinition, A as AgentDefinition } from './resolver-BMZAzKD3.js';
|
|
2
|
+
export { m as AgentBuilderEnv, n as AgentBuilderEvent, ah as BroadcastOptions, C as CodeExecutionBridge, h as DurableAgentBuilder, D as DurableThread, l as DurableUserHub, af as FlowStateSdk, ai as FlowStateWithSdk, G as HandlerSide, H as HubClientInfo, E as HumanSide, aq as ImageContextConfig, ae as InjectMessageOptions, as as LLMProviderInterface, aL as NamespaceResolutionError, w as PromptContent, s as PromptDefinition, y as PromptIncludePart, x as PromptPart, F as PromptSide, t as PromptToolConfig, P as Provider, at as ProviderContentPart, aw as ProviderFilePart, av as ProviderImagePart, ar as ProviderRegistry, au as ProviderTextPart, B as SessionToolBinding, z as SessionToolConfig, I as SideConfig, J as SubagentRelationship, u as SubagentToolConfig, S as SubpromptConfig, o as ThreadEventPayload, p as ThreadRegistryEntry, T as ThreadWatchdog, j as ThreadWatchdogState, v as ToolConfig, U as UpdateThreadParams, q as User, k as WatchdogCheckin, W as WatchdogProbeResult, f as applyRuntimeCors, am as buildImageDescription, c as canAccessThread, a9 as cat, aJ as createNamespaceContext, Q as emitThreadEvent, ag as enhanceFlowState, a0 as exists, ad as find, R as forceTurn, ap as generateImageDescription, a7 as getFileStats, N as getMessages, al as getMessagesToSummarize, az as getShortName, a8 as getThumbnail, ak as getUnsummarizedImageAttachments, aG as getVisibleAgentNames, aI as getVisibleModelNames, aH as getVisiblePromptNames, aF as getVisibleToolNames, ac as grep, aj as hasImageAttachments, aa as head, L as injectMessage, d as isAdminOnlyApiRoute, i as isHostedInstance, b as isPublicApiRoute, aK as isQualifiedName, e as isSameOriginBrowserRequest, a as isTrustedLocalDevelopmentRequest, Z as linkFile, a2 as mkdir, a5 as move, ao as optimizeImageContext, ax as parseQualifiedName, ay as qualifyName, K as queueTool, _ as readFile, a3 as readdir, O as reloadHistory, a6 as rename, an as replaceImagesWithDescriptions, aD as resolveAgent, aE as resolveHook, aC as resolveModel, aB as resolvePrompt, aA as resolveTool, a4 as rmdir, r as runtimeCorsHeaders, g as runtimePreflightResponse, $ as stat, ab as tail, a1 as unlink, V as updateThread, X as writeFile, Y as writeImage } from './resolver-BMZAzKD3.js';
|
|
3
3
|
export { AgentPluginOptions, agentbuilder, builder } from './plugin.js';
|
|
4
|
-
export {
|
|
4
|
+
export { v as Agent, J as AttachmentRef, i as AuthContext, A as AuthUser, e as BuilderThreadEndpointHandler, C as CLIENT_STREAM_CHUNK_BYTES, t as ClientDuplex, u as ClientForwarding, p as ClientStreamRequest, q as ClientStreamResponse, n as ClientToolRequest, o as ClientToolResponse, B as Controller, a as ControllerContext, G as Env, H as FileRecord, N as FileStats, D as FlowResult, F as FlowState, K as GrepResult, P as ImageContentPart, I as ImageMetadata, L as LLMResponse, M as Message, U as MessageContent, Q as MultimodalContent, R as RequestContext, S as StorageBackend, E as TelemetryEvent, O as TextContentPart, T as ThreadEndpointContext, b as ThreadEnv, w as ThreadInstance, x as ThreadMetadata, y as ToolCall, z as ToolResult, f as authenticate, j as callClient, k as callClientStream, c as createThreadEndpointHandler, m as decodeStreamChunk, d as defineController, l as encodeStreamChunk, h as endpointCallerFromAuth, g as requireAdmin, r as requireAuth, s as supportsClientForwarding } from './index-ChHAVogf.js';
|
|
5
5
|
export { AgentType, DefineHandlerOptions, DefinitionLoader, GlobalNamespaceContext, HANDLER_SYMBOL, HandlerDefinition, HookExecutionContext, HookExecutionSource, HookSignatures, ImageContent, ModelCapabilities, ModelProvider, NamespaceContext, PackageSignature, PackedExports, PackedMeta, PackedMetadata, PackedNamespaceContext, ParentHookRequirement, ParentHookStage, PromptInput, PromptTextPart, ProviderAssistantMessage, ProviderConfigSlot, ProviderConfigSlots, ProviderConfigValueSource, ProviderDefinition, ProviderError, ProviderErrorCode, ProviderFactory, ProviderFactoryConfig, ProviderFinishReason, ProviderGeneratedImage, ProviderMessage, ProviderMessageContent, ProviderMethodOverrides, ModelCapabilities as ProviderModelCapabilities, ProviderOverride, ProviderOverrideContext, ProviderReasoningDetail, ProviderRequest, ProviderResponse, ProviderStreamChunk, ProviderSyncOverride, ProviderSystemMessage, ProviderTool, ProviderToolCallPart, ProviderToolMessage, ProviderToolResultContent, ProviderUsage, ProviderUserMessage, ReasoningConfig, StructuredPrompt, TextContent, ThreadHookName, Tool, ToolArgs, ToolArgsNode, ToolArgsRawShape, ToolContent, belongsToPackage, defineAgent, defineHandler, defineHook, defineModel, definePrompt, defineProvider, defineTool, isHandler, isPacked, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue } from '@standardagents/spec';
|
|
6
|
-
export { C as ConstituentItem, D as DiscoveredPackage, N as NamespacedRegistry, P as PackingAnalysis, a as PackingOptions, b as PackingResult,
|
|
7
|
-
export { D as DiscoveryConfig, P as PackageDiscoveryService, d as discoverPackages } from './discovery-
|
|
6
|
+
export { C as ConstituentItem, D as DiscoveredPackage, N as NamespacedRegistry, P as PackingAnalysis, a as PackingOptions, b as PackingResult, U as UnpackOptions, c as UnpackResult } from './types-Dhd0M369.js';
|
|
7
|
+
export { D as DiscoveryConfig, P as PackageDiscoveryService, d as discoverPackages } from './discovery-D5pmuazY.js';
|
|
8
8
|
import 'cloudflare:workers';
|
|
9
9
|
import 'vite';
|
|
10
10
|
import '@cloudflare/workers-types';
|
package/dist/index.js
CHANGED
|
@@ -37709,6 +37709,8 @@ import {
|
|
|
37709
37709
|
applyRuntimeCors,
|
|
37710
37710
|
runtimeCorsHeaders,
|
|
37711
37711
|
runtimePreflightResponse,
|
|
37712
|
+
formatUpstreamTiming,
|
|
37713
|
+
withUpstreamTiming,
|
|
37712
37714
|
} from "@standardagents/builder/runtime";
|
|
37713
37715
|
import { isThreadEndpoint, getEndpointAccess } from "@standardagents/spec";
|
|
37714
37716
|
|
|
@@ -37833,13 +37835,19 @@ ${packedThreadRouteCode}
|
|
|
37833
37835
|
// thread id, for same-request reuse by controllers (AB-05). Never cached
|
|
37834
37836
|
// across requests.
|
|
37835
37837
|
let threadAccess = null;
|
|
37838
|
+
// The request handed to the controller. A protected API request carries
|
|
37839
|
+
// x-standard-upstream-timing with the authentication cost; the header is
|
|
37840
|
+
// overwritten, never merged, so a caller cannot forge upstream time.
|
|
37841
|
+
let controllerRequest = request;
|
|
37836
37842
|
|
|
37837
37843
|
// Require authentication for all API routes except public ones.
|
|
37838
37844
|
// WebSocket tickets are single-use and are consumed here. Controllers
|
|
37839
37845
|
// must reuse context.auth (resolveRequestAuth) rather than calling
|
|
37840
37846
|
// requireAuth again, or a ticket-only upgrade will 401.
|
|
37841
37847
|
if (isApiRoute && !publicRoute) {
|
|
37848
|
+
const authStartedAt = Date.now();
|
|
37842
37849
|
const authResult = await requireAuth(request, env);
|
|
37850
|
+
controllerRequest = withUpstreamTiming(request, formatUpstreamTiming('auth', Date.now() - authStartedAt));
|
|
37843
37851
|
|
|
37844
37852
|
// If requireAuth returns a Response, it's an error (401)
|
|
37845
37853
|
if (authResult instanceof Response) {
|
|
@@ -37896,7 +37904,7 @@ ${packedThreadRouteCode}
|
|
|
37896
37904
|
}
|
|
37897
37905
|
|
|
37898
37906
|
const context = {
|
|
37899
|
-
req:
|
|
37907
|
+
req: controllerRequest,
|
|
37900
37908
|
params: routeMatch.params || {},
|
|
37901
37909
|
env: env,
|
|
37902
37910
|
url: url,
|
|
@@ -39380,6 +39388,9 @@ var UserStateImpl = class {
|
|
|
39380
39388
|
host;
|
|
39381
39389
|
/** Caller descriptor for grant `allow` policy checks. */
|
|
39382
39390
|
caller;
|
|
39391
|
+
/** One identity lookup per execution: the singleton RPC runs at most once. */
|
|
39392
|
+
identityLookup = null;
|
|
39393
|
+
identityLookupMs = null;
|
|
39383
39394
|
constructor(userId, host, caller) {
|
|
39384
39395
|
this.userId = userId;
|
|
39385
39396
|
this.host = host;
|
|
@@ -39391,6 +39402,22 @@ var UserStateImpl = class {
|
|
|
39391
39402
|
return ns.get(ns.idFromName("singleton"));
|
|
39392
39403
|
}
|
|
39393
39404
|
async identity() {
|
|
39405
|
+
if (!this.identityLookup) {
|
|
39406
|
+
const started = Date.now();
|
|
39407
|
+
this.identityLookup = this.lookupIdentity().finally(() => {
|
|
39408
|
+
this.identityLookupMs = Date.now() - started;
|
|
39409
|
+
});
|
|
39410
|
+
this.identityLookup.catch(() => {
|
|
39411
|
+
this.identityLookup = null;
|
|
39412
|
+
});
|
|
39413
|
+
}
|
|
39414
|
+
return this.identityLookup;
|
|
39415
|
+
}
|
|
39416
|
+
/** Milliseconds the execution spent resolving identity, once it has. */
|
|
39417
|
+
timing() {
|
|
39418
|
+
return { identity_ms: this.identityLookupMs };
|
|
39419
|
+
}
|
|
39420
|
+
async lookupIdentity() {
|
|
39394
39421
|
const user = await this.singleton().getUserById(this.userId);
|
|
39395
39422
|
if (!user) throw new Error(`Unknown user: ${this.userId}`);
|
|
39396
39423
|
return {
|
|
@@ -39489,7 +39516,144 @@ function createExecutionChain() {
|
|
|
39489
39516
|
};
|
|
39490
39517
|
}
|
|
39491
39518
|
|
|
39519
|
+
// src/users/upstream-timing.ts
|
|
39520
|
+
var UPSTREAM_TIMING_HEADER = "x-standard-upstream-timing";
|
|
39521
|
+
var MAX_HEADER_CHARS = 512;
|
|
39522
|
+
function formatUpstreamTiming(name, durationMs) {
|
|
39523
|
+
const safe = Number.isFinite(durationMs) && durationMs > 0 ? durationMs : 0;
|
|
39524
|
+
return `${name};dur=${Math.round(safe * 10) / 10}`;
|
|
39525
|
+
}
|
|
39526
|
+
function appendUpstreamTiming(current, name, durationMs) {
|
|
39527
|
+
const entry = formatUpstreamTiming(name, durationMs);
|
|
39528
|
+
if (!current) return entry;
|
|
39529
|
+
const combined = `${current}, ${entry}`;
|
|
39530
|
+
return combined.length > MAX_HEADER_CHARS ? current : combined;
|
|
39531
|
+
}
|
|
39532
|
+
function withUpstreamTiming(request, value) {
|
|
39533
|
+
const headers = new Headers(request.headers);
|
|
39534
|
+
headers.set(UPSTREAM_TIMING_HEADER, value);
|
|
39535
|
+
return new Request(request, { headers });
|
|
39536
|
+
}
|
|
39537
|
+
function responseWithUpstreamTiming(response, name, durationMs) {
|
|
39538
|
+
if (response.status === 101) return response;
|
|
39539
|
+
const value = appendUpstreamTiming(response.headers.get(UPSTREAM_TIMING_HEADER), name, durationMs);
|
|
39540
|
+
try {
|
|
39541
|
+
response.headers.set(UPSTREAM_TIMING_HEADER, value);
|
|
39542
|
+
return response;
|
|
39543
|
+
} catch {
|
|
39544
|
+
const headers = new Headers(response.headers);
|
|
39545
|
+
headers.set(UPSTREAM_TIMING_HEADER, value);
|
|
39546
|
+
return new Response(response.body, {
|
|
39547
|
+
status: response.status,
|
|
39548
|
+
statusText: response.statusText,
|
|
39549
|
+
headers
|
|
39550
|
+
});
|
|
39551
|
+
}
|
|
39552
|
+
}
|
|
39553
|
+
|
|
39554
|
+
// src/durable-objects/DurableUserHub.ts
|
|
39555
|
+
init_bridge_owner();
|
|
39556
|
+
|
|
39492
39557
|
// src/users/grants.ts
|
|
39558
|
+
var INSTANCE_GRANTS_MAX_BYTES = 64 * 1024;
|
|
39559
|
+
var INSTANCE_GRANTS_MAX_COUNT = 64;
|
|
39560
|
+
var GRANT_NAME = /^[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
39561
|
+
var HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
|
|
39562
|
+
var QUERY_NAME = /^[A-Za-z0-9._~-]{1,128}$/;
|
|
39563
|
+
var SUPPORTED_KINDS = /* @__PURE__ */ new Set(["bearer", "header", "query", "basic"]);
|
|
39564
|
+
var RECORD_KEYS = /* @__PURE__ */ new Set(["name", "kind", "origins", "inject", "allow", "metadata", "secret"]);
|
|
39565
|
+
var ALLOW_KEYS = /* @__PURE__ */ new Set(["tools", "endpoints", "userEndpoints", "agents"]);
|
|
39566
|
+
var INJECT_KEYS = /* @__PURE__ */ new Set(["header", "format", "query"]);
|
|
39567
|
+
function parseInstanceCredentialGrants(value) {
|
|
39568
|
+
const records = /* @__PURE__ */ new Map();
|
|
39569
|
+
if (typeof value !== "string" || value.length === 0 || value.length > INSTANCE_GRANTS_MAX_BYTES) {
|
|
39570
|
+
return records;
|
|
39571
|
+
}
|
|
39572
|
+
let parsed;
|
|
39573
|
+
try {
|
|
39574
|
+
parsed = JSON.parse(value);
|
|
39575
|
+
} catch {
|
|
39576
|
+
return records;
|
|
39577
|
+
}
|
|
39578
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return records;
|
|
39579
|
+
const envelope = parsed;
|
|
39580
|
+
if (envelope.version !== 1 || !Array.isArray(envelope.grants) || envelope.grants.length > INSTANCE_GRANTS_MAX_COUNT) {
|
|
39581
|
+
return records;
|
|
39582
|
+
}
|
|
39583
|
+
for (const candidate of envelope.grants) {
|
|
39584
|
+
const record = validateCredentialGrantRecord(candidate);
|
|
39585
|
+
if (!record || records.has(record.grant.name)) return /* @__PURE__ */ new Map();
|
|
39586
|
+
records.set(record.grant.name, record);
|
|
39587
|
+
}
|
|
39588
|
+
return records;
|
|
39589
|
+
}
|
|
39590
|
+
function validateCredentialGrantRecord(value, routeName) {
|
|
39591
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
39592
|
+
const input = value;
|
|
39593
|
+
if (Object.keys(input).some((key) => !RECORD_KEYS.has(key))) return null;
|
|
39594
|
+
const name = input.name;
|
|
39595
|
+
if (typeof name !== "string" || !GRANT_NAME.test(name)) return null;
|
|
39596
|
+
if (input.name !== void 0 && input.name !== name) return null;
|
|
39597
|
+
if (typeof input.secret !== "string" || input.secret.length === 0 || input.secret.length > 16 * 1024) return null;
|
|
39598
|
+
if (typeof input.kind !== "string" || !SUPPORTED_KINDS.has(input.kind)) return null;
|
|
39599
|
+
if ((input.kind === "bearer" || input.kind === "header") && /[\r\n]/.test(input.secret)) return null;
|
|
39600
|
+
if (!Array.isArray(input.origins) || input.origins.length === 0 || input.origins.length > 64) return null;
|
|
39601
|
+
const origins = [];
|
|
39602
|
+
for (const origin of input.origins) {
|
|
39603
|
+
if (typeof origin !== "string" || origin.length > 512) return null;
|
|
39604
|
+
if (origin.startsWith("*.")) {
|
|
39605
|
+
if (!/^\*\.[a-z0-9.-]+$/i.test(origin)) return null;
|
|
39606
|
+
} else {
|
|
39607
|
+
try {
|
|
39608
|
+
const url = new URL(origin);
|
|
39609
|
+
if (url.origin !== origin || url.protocol !== "https:" || url.username || url.password) return null;
|
|
39610
|
+
} catch {
|
|
39611
|
+
return null;
|
|
39612
|
+
}
|
|
39613
|
+
}
|
|
39614
|
+
origins.push(origin);
|
|
39615
|
+
}
|
|
39616
|
+
if (!input.allow || typeof input.allow !== "object" || Array.isArray(input.allow)) return null;
|
|
39617
|
+
const allowInput = input.allow;
|
|
39618
|
+
if (Object.keys(allowInput).some((key) => !ALLOW_KEYS.has(key))) return null;
|
|
39619
|
+
const allow = {};
|
|
39620
|
+
for (const key of ["tools", "endpoints", "userEndpoints", "agents"]) {
|
|
39621
|
+
const list = allowInput[key];
|
|
39622
|
+
if (list === void 0) continue;
|
|
39623
|
+
if (!Array.isArray(list) || list.length > 128 || !list.every((item) => typeof item === "string" && item.length > 0 && item.length <= 256)) {
|
|
39624
|
+
return null;
|
|
39625
|
+
}
|
|
39626
|
+
allow[key] = [...list];
|
|
39627
|
+
}
|
|
39628
|
+
if (Object.keys(allow).length === 0) return null;
|
|
39629
|
+
const inject = input.inject;
|
|
39630
|
+
if (inject !== void 0 && (!inject || typeof inject !== "object" || Array.isArray(inject))) return null;
|
|
39631
|
+
if (inject !== void 0) {
|
|
39632
|
+
const injection = inject;
|
|
39633
|
+
if (Object.keys(injection).some((key) => !INJECT_KEYS.has(key))) return null;
|
|
39634
|
+
if (injection.header !== void 0 && (typeof injection.header !== "string" || !HEADER_NAME.test(injection.header))) return null;
|
|
39635
|
+
if (injection.format !== void 0 && (typeof injection.format !== "string" || injection.format.length > 1024 || /[\r\n]/.test(injection.format))) return null;
|
|
39636
|
+
if (injection.query !== void 0 && (typeof injection.query !== "string" || !QUERY_NAME.test(injection.query))) return null;
|
|
39637
|
+
}
|
|
39638
|
+
const metadata = input.metadata;
|
|
39639
|
+
if (metadata !== void 0 && (!metadata || typeof metadata !== "object" || Array.isArray(metadata))) return null;
|
|
39640
|
+
if (metadata !== void 0) {
|
|
39641
|
+
try {
|
|
39642
|
+
if (JSON.stringify(metadata).length > 16 * 1024) return null;
|
|
39643
|
+
} catch {
|
|
39644
|
+
return null;
|
|
39645
|
+
}
|
|
39646
|
+
}
|
|
39647
|
+
const grant = {
|
|
39648
|
+
name,
|
|
39649
|
+
kind: input.kind,
|
|
39650
|
+
origins,
|
|
39651
|
+
allow,
|
|
39652
|
+
...inject === void 0 ? {} : { inject },
|
|
39653
|
+
...metadata === void 0 ? {} : { metadata }
|
|
39654
|
+
};
|
|
39655
|
+
return { grant, secret: input.secret };
|
|
39656
|
+
}
|
|
39493
39657
|
function originAllowed(origins, target) {
|
|
39494
39658
|
if (!Array.isArray(origins)) return false;
|
|
39495
39659
|
for (const allowed of origins) {
|
|
@@ -39630,11 +39794,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39630
39794
|
if (request.headers.get("Upgrade") === "websocket") {
|
|
39631
39795
|
const pair = new WebSocketPair();
|
|
39632
39796
|
const [client, server] = [pair[0], pair[1]];
|
|
39633
|
-
const info =
|
|
39634
|
-
clientId: url.searchParams.get("client_id"),
|
|
39635
|
-
clientName: url.searchParams.get("client_name"),
|
|
39636
|
-
clientKind: url.searchParams.get("client_kind")
|
|
39637
|
-
};
|
|
39797
|
+
const info = parseBridgeClientParams(url).info;
|
|
39638
39798
|
this.ensureHeartbeatAutoResponse();
|
|
39639
39799
|
this.ctx.acceptWebSocket(server);
|
|
39640
39800
|
server.serializeAttachment({ type: "hub_client", ...info });
|
|
@@ -39733,13 +39893,21 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39733
39893
|
{ status: 500 }
|
|
39734
39894
|
);
|
|
39735
39895
|
}
|
|
39896
|
+
const queuedAt = Date.now();
|
|
39736
39897
|
return this.executionChain.run(async () => {
|
|
39898
|
+
const queueMs = Date.now() - queuedAt;
|
|
39899
|
+
const timed = withUpstreamTiming(
|
|
39900
|
+
request,
|
|
39901
|
+
appendUpstreamTiming(request.headers.get(UPSTREAM_TIMING_HEADER), "queue", queueMs)
|
|
39902
|
+
);
|
|
39737
39903
|
const user = new UserStateImpl(userId, this.scopeHost(), {
|
|
39738
39904
|
kind: "userEndpoint",
|
|
39739
39905
|
name: match.key
|
|
39740
39906
|
});
|
|
39741
39907
|
try {
|
|
39742
|
-
|
|
39908
|
+
const response = await handler.__handler(timed, user, match.params);
|
|
39909
|
+
const identityMs = user.timing().identity_ms;
|
|
39910
|
+
return identityMs === null ? response : responseWithUpstreamTiming(response, "identity", identityMs);
|
|
39743
39911
|
} catch (error) {
|
|
39744
39912
|
return Response.json(
|
|
39745
39913
|
{ error: error instanceof Error ? error.message : "User endpoint failed" },
|
|
@@ -39786,6 +39954,8 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39786
39954
|
this.ctx.waitUntil(run());
|
|
39787
39955
|
}
|
|
39788
39956
|
async webSocketClose(ws) {
|
|
39957
|
+
this.clientSockets.delete(ws);
|
|
39958
|
+
this.clientInfo.delete(ws);
|
|
39789
39959
|
const attachment = ws.deserializeAttachment();
|
|
39790
39960
|
if (attachment?.type === "user_stream") {
|
|
39791
39961
|
this.dispatchUserHooks(String(attachment.userId), "user_client_detached", [
|
|
@@ -39794,10 +39964,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39794
39964
|
kind: typeof attachment.clientKind === "string" ? attachment.clientKind : void 0
|
|
39795
39965
|
}
|
|
39796
39966
|
]);
|
|
39797
|
-
return;
|
|
39798
39967
|
}
|
|
39799
|
-
this.clientSockets.delete(ws);
|
|
39800
|
-
this.clientInfo.delete(ws);
|
|
39801
39968
|
}
|
|
39802
39969
|
// ─── User scope: credential grants (spec: Users §6) ───────────────────────
|
|
39803
39970
|
/**
|
|
@@ -39835,14 +40002,20 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39835
40002
|
`SELECT name, config FROM user_grants WHERE user_id = ? ORDER BY name ASC`,
|
|
39836
40003
|
userId
|
|
39837
40004
|
);
|
|
39838
|
-
|
|
40005
|
+
const grants = /* @__PURE__ */ new Map();
|
|
40006
|
+
for (const record of parseInstanceCredentialGrants(this.env.AGENT_BUILDER_CREDENTIAL_GRANTS).values()) {
|
|
40007
|
+
const { name, ...config } = record.grant;
|
|
40008
|
+
grants.set(name, { name, ...config });
|
|
40009
|
+
}
|
|
40010
|
+
for (const row of cursor.toArray()) {
|
|
39839
40011
|
let config = {};
|
|
39840
40012
|
try {
|
|
39841
40013
|
config = JSON.parse(row.config);
|
|
39842
40014
|
} catch {
|
|
39843
40015
|
}
|
|
39844
|
-
|
|
39845
|
-
}
|
|
40016
|
+
grants.set(row.name, { name: row.name, ...config });
|
|
40017
|
+
}
|
|
40018
|
+
return [...grants.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
39846
40019
|
}
|
|
39847
40020
|
/** Perform a privileged fetch with the grant's credential injected. */
|
|
39848
40021
|
async grantFetch(userId, grantName, req) {
|
|
@@ -39852,15 +40025,24 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39852
40025
|
userId,
|
|
39853
40026
|
grantName
|
|
39854
40027
|
);
|
|
39855
|
-
const
|
|
39856
|
-
|
|
40028
|
+
const stored = cursor.toArray()[0];
|
|
40029
|
+
const instance = stored ? null : parseInstanceCredentialGrants(this.env.AGENT_BUILDER_CREDENTIAL_GRANTS).get(grantName) ?? null;
|
|
40030
|
+
if (!stored && !instance) {
|
|
39857
40031
|
return Response.json({ error: "grant_not_found", grant: grantName }, { status: 404 });
|
|
39858
40032
|
}
|
|
39859
40033
|
let config;
|
|
39860
|
-
|
|
39861
|
-
|
|
39862
|
-
|
|
39863
|
-
|
|
40034
|
+
let secret;
|
|
40035
|
+
if (stored) {
|
|
40036
|
+
try {
|
|
40037
|
+
config = JSON.parse(stored.config);
|
|
40038
|
+
} catch {
|
|
40039
|
+
return Response.json({ error: "grant_config_invalid" }, { status: 500 });
|
|
40040
|
+
}
|
|
40041
|
+
secret = stored.secret;
|
|
40042
|
+
} else {
|
|
40043
|
+
const { name: _name, ...instanceConfig } = instance.grant;
|
|
40044
|
+
config = instanceConfig;
|
|
40045
|
+
secret = instance.secret;
|
|
39864
40046
|
}
|
|
39865
40047
|
let target;
|
|
39866
40048
|
try {
|
|
@@ -39875,7 +40057,7 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39875
40057
|
return Response.json({ error: "grant_caller_denied" }, { status: 403 });
|
|
39876
40058
|
}
|
|
39877
40059
|
const headers = new Headers(req.headers);
|
|
39878
|
-
if (!injectGrantCredential(config,
|
|
40060
|
+
if (!injectGrantCredential(config, secret, target, headers)) {
|
|
39879
40061
|
return Response.json({ error: "grant_kind_unsupported" }, { status: 501 });
|
|
39880
40062
|
}
|
|
39881
40063
|
try {
|
|
@@ -39903,7 +40085,16 @@ var DurableUserHub = class extends DurableObject {
|
|
|
39903
40085
|
});
|
|
39904
40086
|
}
|
|
39905
40087
|
async webSocketMessage(ws, _message) {
|
|
39906
|
-
|
|
40088
|
+
const attachment = ws.deserializeAttachment();
|
|
40089
|
+
if (attachment?.type !== "hub_client") return;
|
|
40090
|
+
if (!this.clientSockets.has(ws)) {
|
|
40091
|
+
this.clientSockets.add(ws);
|
|
40092
|
+
this.clientInfo.set(ws, {
|
|
40093
|
+
clientId: typeof attachment.clientId === "string" ? attachment.clientId : null,
|
|
40094
|
+
clientName: typeof attachment.clientName === "string" ? attachment.clientName : null,
|
|
40095
|
+
clientKind: typeof attachment.clientKind === "string" ? attachment.clientKind : null
|
|
40096
|
+
});
|
|
40097
|
+
}
|
|
39907
40098
|
}
|
|
39908
40099
|
async webSocketError(ws) {
|
|
39909
40100
|
await this.webSocketClose(ws);
|