@tangle-network/agent-core 0.9.4 → 0.9.6
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/auth/browser.d.ts +2 -22
- package/dist/auth/browser.js +1 -42
- package/dist/auth/index.d.ts +3 -17
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +8 -45
- package/dist/auth/index.js.map +1 -1
- package/dist/computer-use/index.d.ts.map +1 -1
- package/dist/computer-use/index.js +4 -3
- package/dist/computer-use/index.js.map +1 -1
- package/dist/{errors-DJ6U6cHY.js → errors-GuWACHTg.js} +11 -8
- package/dist/{errors-DJ6U6cHY.js.map → errors-GuWACHTg.js.map} +1 -1
- package/dist/events/index.d.ts +2 -2
- package/dist/events/index.js +1 -1
- package/dist/{events-CUWh9qrv.js → events-U7kxNUpM.js} +7 -5
- package/dist/{events-CUWh9qrv.js.map → events-U7kxNUpM.js.map} +1 -1
- package/dist/{index-D59fZ7n3.d.ts → index-BFYASYJk.d.ts} +1 -1
- package/dist/index-BFYASYJk.d.ts.map +1 -0
- package/dist/{index-Bgao-NCe.d.ts → index-BvjA5i93.d.ts} +1 -1
- package/dist/index-BvjA5i93.d.ts.map +1 -0
- package/dist/{index-HMlPCgTI.d.ts → index-CKDeaS7l.d.ts} +2 -3
- package/dist/index-CKDeaS7l.d.ts.map +1 -0
- package/dist/{index-CDLuQTT2.d.ts → index-CQPGv8jg.d.ts} +10 -11
- package/dist/index-CQPGv8jg.d.ts.map +1 -0
- package/dist/{index-C_1MnL24.d.ts → index-CuBvSsBf.d.ts} +1 -1
- package/dist/index-CuBvSsBf.d.ts.map +1 -0
- package/dist/{index-B4yy8ghH.d.ts → index-Dq6SfGaX.d.ts} +1 -1
- package/dist/index-Dq6SfGaX.d.ts.map +1 -0
- package/dist/index.d.ts +8 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -8
- package/dist/index.js.map +1 -1
- package/dist/interactions/index.d.ts +1 -2
- package/dist/interactions/index.d.ts.map +1 -1
- package/dist/interactions/index.js +2 -2
- package/dist/interactions/index.js.map +1 -1
- package/dist/interactions/mcp-server.d.ts +1 -2
- package/dist/interactions/mcp-server.d.ts.map +1 -1
- package/dist/interactions/mcp-server.js +3 -2
- package/dist/interactions/mcp-server.js.map +1 -1
- package/dist/{lifecycle-CXKYetbu.js → lifecycle-BljLcnY5.js} +1 -1
- package/dist/{lifecycle-CXKYetbu.js.map → lifecycle-BljLcnY5.js.map} +1 -1
- package/dist/resilience/index.d.ts +2 -2
- package/dist/resilience/index.js +1 -1
- package/dist/{resilience-BQzDfw_C.js → resilience-CFKHZSub.js} +4 -2
- package/dist/{resilience-BQzDfw_C.js.map → resilience-CFKHZSub.js.map} +1 -1
- package/dist/sse/index.d.ts.map +1 -1
- package/dist/sse/index.js +1 -1
- package/dist/sse/index.js.map +1 -1
- package/dist/telemetry/index.d.ts +2 -2
- package/dist/telemetry/index.js +1 -1
- package/dist/{telemetry-x1wNw1P4.js → telemetry-DTOiMSzM.js} +1 -1
- package/dist/{telemetry-x1wNw1P4.js.map → telemetry-DTOiMSzM.js.map} +1 -1
- package/dist/{types-Cd5jUzcr.d.ts → tokens-browser-DCV3-WHc.d.ts} +28 -10
- package/dist/tokens-browser-DCV3-WHc.d.ts.map +1 -0
- package/dist/{tools-D-I3A7Us.d.ts → tools-DeZkIW3h.d.ts} +1 -2
- package/dist/tools-DeZkIW3h.d.ts.map +1 -0
- package/dist/transport/index.d.ts +2 -2
- package/dist/transport/index.js +1 -1
- package/dist/{transport-XLxpQmUW.js → transport-DAfw3oL0.js} +5 -4
- package/dist/{transport-XLxpQmUW.js.map → transport-DAfw3oL0.js.map} +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -1
- package/dist/{types-DC6OJ1um.js → types--u-Om3vE.js} +56 -3
- package/dist/types--u-Om3vE.js.map +1 -0
- package/dist/{types-Ci7hcTnp.js → types-DVN5qATk.js} +1 -1
- package/dist/{types-Ci7hcTnp.js.map → types-DVN5qATk.js.map} +1 -1
- package/package.json +7 -7
- package/dist/auth/browser.d.ts.map +0 -1
- package/dist/auth/browser.js.map +0 -1
- package/dist/index-B4yy8ghH.d.ts.map +0 -1
- package/dist/index-Bgao-NCe.d.ts.map +0 -1
- package/dist/index-CDLuQTT2.d.ts.map +0 -1
- package/dist/index-C_1MnL24.d.ts.map +0 -1
- package/dist/index-D59fZ7n3.d.ts.map +0 -1
- package/dist/index-HMlPCgTI.d.ts.map +0 -1
- package/dist/tools-D-I3A7Us.d.ts.map +0 -1
- package/dist/types-Cd5jUzcr.d.ts.map +0 -1
- package/dist/types-DC6OJ1um.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import {
|
|
3
|
-
import { EnvTokenAuth, ProductAuth, ProductTokenIssuer, SidecarAuth, canBatchTokenAccessChannel, canProjectTokenAccessChannel, canSessionTokenAccessChannel, canTokenAccessChannel,
|
|
4
|
-
import { n as EventChannel, r as EventBuffer, t as EventDeduplicator } from "./events-
|
|
5
|
-
import { a as sleep, c as CircuitOpenError, i as createTimeoutController, n as withProtection, o as withTimeout, r as TimeoutError, s as CircuitBreaker, t as createProtectedFn } from "./resilience-
|
|
1
|
+
import { _ as isTokenExpiringSoon, a as ReadTokenPayloadSchema, c as CallbackAuth, d as RefreshableTokenAuth, f as StaticTokenAuth, g as getTokenTTL, h as decodeToken, i as ProjectScopedTokenPayloadSchema, l as NoAuth, n as CreateSessionRequestSchema, o as SendMessageRequestSchema, r as ProductSchema, s as SessionScopedTokenPayloadSchema, t as BatchScopedTokenPayloadSchema, u as ReadTokenAuth } from "./types--u-Om3vE.js";
|
|
2
|
+
import { n as isRetryable, r as isSDKError, t as SDKError } from "./errors-GuWACHTg.js";
|
|
3
|
+
import { EnvTokenAuth, ProductAuth, ProductTokenIssuer, SidecarAuth, canBatchTokenAccessChannel, canProjectTokenAccessChannel, canSessionTokenAccessChannel, canTokenAccessChannel, extractProjectFromChannel, extractSessionFromChannel, generateApiKey, generateSecureToken, generateSigningSecret, getAllowedChannelPatterns, getTokenScope, hashApiKey, isBatchScopedToken, isProjectScopedToken, isSessionScopedToken, issueBatchScopedToken, issueProjectScopedToken, issueReadToken, issueSessionScopedToken, validateChannelSubscription, validateTokenScope, verifyApiKey, verifyReadToken } from "./auth/index.js";
|
|
4
|
+
import { n as EventChannel, r as EventBuffer, t as EventDeduplicator } from "./events-U7kxNUpM.js";
|
|
5
|
+
import { a as sleep, c as CircuitOpenError, i as createTimeoutController, n as withProtection, o as withTimeout, r as TimeoutError, s as CircuitBreaker, t as createProtectedFn } from "./resilience-CFKHZSub.js";
|
|
6
6
|
import { SSEChunkParser, StreamUsageExtractor, consumeSSEStream, createStreamUsageExtractor, createUsageCallback, parseSSEData, parseSSEStream } from "./sse/index.js";
|
|
7
|
-
import { $ as CONTENT_TOOL_ARGS_KEY, A as TANGLE_TRIGGER_ID_KEY, B as GEN_AI_OPERATION_NAME, C as RUN_KIND_ATTRS, D as TANGLE_RUN_KIND_KEY, E as TANGLE_RUN_ID_KEY, F as TRIGGER_SOURCE_ATTRS, G as GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, H as GEN_AI_REQUEST_MODEL, I as WORKFLOW_MARKER_ATTRS, J as genAiUsageAttributes, K as GEN_AI_USAGE_INPUT_TOKENS, L as GEN_AI_CONVERSATION_ID, M as TANGLE_TRIGGER_SOURCE_KEY, N as TANGLE_WORKFLOW_ID_KEY, O as TANGLE_RUN_PARENT_ID_KEY, P as TRIGGER_ID_ATTRS, Q as CONTENT_PROMPT_KEY, R as GEN_AI_INPUT_TOKEN_KEYS, S as RUN_KEY_ATTRS, T as TANGLE_RUN_ID_CAMEL_KEY, U as GEN_AI_RESPONSE_MODEL, V as GEN_AI_OUTPUT_TOKEN_KEYS, W as GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, X as CONTENT_KEYS, Y as CONTENT_COMPLETION_KEY, Z as CONTENT_KEY_FIELD, _ as readTokenCostUsd, a as TOKEN_USAGE_CACHE_READ_INCLUSIVE_KEYS, at as classifyAgent, b as tokenUsageSource, c as TOKEN_USAGE_COST_KEYS, ct as hasContent, d as TOKEN_USAGE_OUTPUT_KEYS, dt as resolveDeclaredIntent, et as CONTENT_TOOL_NAME_KEY, f as addTokenUsage, g as promptTokens, h as firstUsageCostUsd, i as TOKEN_USAGE_CACHE_READ_EXCLUSIVE_KEYS, it as asContentString, j as TANGLE_TRIGGER_KIND_KEY, k as TANGLE_SUBJECT_KEY, l as TOKEN_USAGE_DETAIL_KEYS, lt as logRecordContentBag, m as firstTokenCount, n as TOKEN_USAGE_CACHE_BAG_READ_KEYS, nt as INDEXED_CONTENT_KEY_LIKE_PATTERNS, o as TOKEN_USAGE_CACHE_WRITE_EXCLUSIVE_KEYS, ot as declaredTaskText, p as cacheHitRate, q as GEN_AI_USAGE_OUTPUT_TOKENS, r as TOKEN_USAGE_CACHE_BAG_WRITE_KEYS, rt as asContentField, s as TOKEN_USAGE_CACHE_WRITE_INCLUSIVE_KEYS, st as extractContent, t as TOKEN_USAGE_CACHE_BAG_KEYS, tt as CONTENT_TOOL_RESULT_KEY, u as TOKEN_USAGE_INPUT_KEYS, ut as normalizeContentAttributes, v as readTokenUsage, w as SUBJECT_KEY_ATTRS, x as PARENT_RUN_KEY_ATTRS, y as tokenCount, z as GEN_AI_MODEL_KEYS } from "./telemetry-
|
|
8
|
-
import { i as DEFAULT_RECONNECTION_CONFIG, n as BaseTransportAdapter, r as ConnectionManager, t as MockTransportAdapter } from "./transport-
|
|
9
|
-
import { a as isTextPart, i as isSubtaskPart, n as isFilePart, o as isToolPart, r as isReasoningPart, t as AgentEventTypeSchema } from "./types-
|
|
7
|
+
import { $ as CONTENT_TOOL_ARGS_KEY, A as TANGLE_TRIGGER_ID_KEY, B as GEN_AI_OPERATION_NAME, C as RUN_KIND_ATTRS, D as TANGLE_RUN_KIND_KEY, E as TANGLE_RUN_ID_KEY, F as TRIGGER_SOURCE_ATTRS, G as GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS, H as GEN_AI_REQUEST_MODEL, I as WORKFLOW_MARKER_ATTRS, J as genAiUsageAttributes, K as GEN_AI_USAGE_INPUT_TOKENS, L as GEN_AI_CONVERSATION_ID, M as TANGLE_TRIGGER_SOURCE_KEY, N as TANGLE_WORKFLOW_ID_KEY, O as TANGLE_RUN_PARENT_ID_KEY, P as TRIGGER_ID_ATTRS, Q as CONTENT_PROMPT_KEY, R as GEN_AI_INPUT_TOKEN_KEYS, S as RUN_KEY_ATTRS, T as TANGLE_RUN_ID_CAMEL_KEY, U as GEN_AI_RESPONSE_MODEL, V as GEN_AI_OUTPUT_TOKEN_KEYS, W as GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS, X as CONTENT_KEYS, Y as CONTENT_COMPLETION_KEY, Z as CONTENT_KEY_FIELD, _ as readTokenCostUsd, a as TOKEN_USAGE_CACHE_READ_INCLUSIVE_KEYS, at as classifyAgent, b as tokenUsageSource, c as TOKEN_USAGE_COST_KEYS, ct as hasContent, d as TOKEN_USAGE_OUTPUT_KEYS, dt as resolveDeclaredIntent, et as CONTENT_TOOL_NAME_KEY, f as addTokenUsage, g as promptTokens, h as firstUsageCostUsd, i as TOKEN_USAGE_CACHE_READ_EXCLUSIVE_KEYS, it as asContentString, j as TANGLE_TRIGGER_KIND_KEY, k as TANGLE_SUBJECT_KEY, l as TOKEN_USAGE_DETAIL_KEYS, lt as logRecordContentBag, m as firstTokenCount, n as TOKEN_USAGE_CACHE_BAG_READ_KEYS, nt as INDEXED_CONTENT_KEY_LIKE_PATTERNS, o as TOKEN_USAGE_CACHE_WRITE_EXCLUSIVE_KEYS, ot as declaredTaskText, p as cacheHitRate, q as GEN_AI_USAGE_OUTPUT_TOKENS, r as TOKEN_USAGE_CACHE_BAG_WRITE_KEYS, rt as asContentField, s as TOKEN_USAGE_CACHE_WRITE_INCLUSIVE_KEYS, st as extractContent, t as TOKEN_USAGE_CACHE_BAG_KEYS, tt as CONTENT_TOOL_RESULT_KEY, u as TOKEN_USAGE_INPUT_KEYS, ut as normalizeContentAttributes, v as readTokenUsage, w as SUBJECT_KEY_ATTRS, x as PARENT_RUN_KEY_ATTRS, y as tokenCount, z as GEN_AI_MODEL_KEYS } from "./telemetry-DTOiMSzM.js";
|
|
8
|
+
import { i as DEFAULT_RECONNECTION_CONFIG, n as BaseTransportAdapter, r as ConnectionManager, t as MockTransportAdapter } from "./transport-DAfw3oL0.js";
|
|
9
|
+
import { a as isTextPart, i as isSubtaskPart, n as isFilePart, o as isToolPart, r as isReasoningPart, t as AgentEventTypeSchema } from "./types-DVN5qATk.js";
|
|
10
10
|
//#region src/cache/index.ts
|
|
11
11
|
/** In-memory LRU cache */
|
|
12
12
|
var MemoryCache = class {
|
|
@@ -245,6 +245,7 @@ var MemoryStorage = class {
|
|
|
245
245
|
};
|
|
246
246
|
/** Browser localStorage wrapper */
|
|
247
247
|
var LocalStorage = class {
|
|
248
|
+
prefix;
|
|
248
249
|
constructor(prefix = "sdk_") {
|
|
249
250
|
this.prefix = prefix;
|
|
250
251
|
}
|
|
@@ -286,6 +287,7 @@ var LocalStorage = class {
|
|
|
286
287
|
};
|
|
287
288
|
/** Offline queue manager */
|
|
288
289
|
var OfflineQueue = class {
|
|
290
|
+
storage;
|
|
289
291
|
storageKey = "offline_queue";
|
|
290
292
|
constructor(storage) {
|
|
291
293
|
this.storage = storage;
|
|
@@ -446,6 +448,7 @@ var NodeNetworkInfo = class {
|
|
|
446
448
|
* Uses provided Storage implementation for state persistence.
|
|
447
449
|
*/
|
|
448
450
|
var StoragePersistence = class {
|
|
451
|
+
storage;
|
|
449
452
|
constructor(storage) {
|
|
450
453
|
this.storage = storage;
|
|
451
454
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["sleep"],"sources":["../src/cache/index.ts","../src/middleware/index.ts","../src/storage/index.ts","../src/platform/index.ts","../src/retry/index.ts","../src/utils/channel-matching.ts","../src/utils/session-translator.ts"],"sourcesContent":["/**\n * Response Caching\n *\n * In-memory cache with TTL and cache-control support.\n */\n\n/** Cache entry */\ninterface CacheEntry<T> {\n data: T;\n cachedAt: number;\n expiresAt: number;\n etag?: string;\n}\n\n/** Cache configuration */\nexport interface CacheConfig {\n /** Default TTL in ms (default: 60000 = 1 minute) */\n defaultTtlMs?: number;\n /** Max entries (default: 1000) */\n maxEntries?: number;\n /** Cache key generator */\n keyGenerator?: (path: string, params?: Record<string, unknown>) => string;\n}\n\n/** Cache interface for different storage backends */\nexport interface CacheStorage<T = unknown> {\n get(key: string): T | undefined | Promise<T | undefined>;\n set(key: string, value: T, ttlMs?: number): void | Promise<void>;\n delete(key: string): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\n/** In-memory LRU cache */\nexport class MemoryCache<T = unknown> implements CacheStorage<CacheEntry<T>> {\n private cache = new Map<string, CacheEntry<T>>();\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n get(key: string): CacheEntry<T> | undefined {\n const entry = this.cache.get(key);\n if (!entry) return undefined;\n\n // Check expiration\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, entry);\n\n return entry;\n }\n\n set(key: string, value: CacheEntry<T>): void {\n // Evict oldest if at capacity\n if (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next().value;\n if (oldest) this.cache.delete(oldest);\n }\n\n this.cache.set(key, value);\n }\n\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n /** Get cache stats */\n stats(): { size: number; maxEntries: number } {\n return { size: this.cache.size, maxEntries: this.maxEntries };\n }\n}\n\n/** Response cache manager */\nexport class ResponseCache<T = unknown> {\n private storage: CacheStorage<CacheEntry<T>>;\n private defaultTtlMs: number;\n private keyGenerator: (\n path: string,\n params?: Record<string, unknown>,\n ) => string;\n\n constructor(config: CacheConfig = {}) {\n this.storage = new MemoryCache<T>(config.maxEntries);\n this.defaultTtlMs = config.defaultTtlMs ?? 60000;\n this.keyGenerator = config.keyGenerator ?? this.defaultKeyGenerator;\n }\n\n private defaultKeyGenerator(\n path: string,\n params?: Record<string, unknown>,\n ): string {\n if (!params || Object.keys(params).length === 0) return path;\n const sorted = Object.keys(params).sort();\n const qs = sorted.map((k) => `${k}=${JSON.stringify(params[k])}`).join(\"&\");\n return `${path}?${qs}`;\n }\n\n /** Get cached response */\n async get(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T | undefined> {\n const key = this.keyGenerator(path, params);\n const entry = await this.storage.get(key);\n return entry?.data;\n }\n\n /** Get with stale-while-revalidate support */\n async getWithMeta(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<{ data: T; stale: boolean; etag?: string } | undefined> {\n const key = this.keyGenerator(path, params);\n const entry = await this.storage.get(key);\n\n if (!entry) return undefined;\n\n const now = Date.now();\n const stale = now > entry.expiresAt;\n\n return { data: entry.data, stale, etag: entry.etag };\n }\n\n /** Cache response */\n async set(\n path: string,\n data: T,\n options?: {\n params?: Record<string, unknown>;\n ttlMs?: number;\n etag?: string;\n },\n ): Promise<void> {\n const key = this.keyGenerator(path, options?.params);\n const now = Date.now();\n const ttl = options?.ttlMs ?? this.defaultTtlMs;\n\n await this.storage.set(key, {\n data,\n cachedAt: now,\n expiresAt: now + ttl,\n etag: options?.etag,\n });\n }\n\n /** Invalidate cache entry */\n async invalidate(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<void> {\n const key = this.keyGenerator(path, params);\n await this.storage.delete(key);\n }\n\n /** Invalidate all entries matching prefix */\n async invalidatePrefix(_prefix: string): Promise<void> {\n // Only works with MemoryCache\n if (this.storage instanceof MemoryCache) {\n // Need to iterate - not ideal but works for in-memory\n const cache = this.storage as MemoryCache<T>;\n // Can't iterate Map while modifying, so just clear for now\n cache.clear();\n }\n }\n\n /** Clear entire cache */\n async clear(): Promise<void> {\n await this.storage.clear();\n }\n\n /** Parse Cache-Control header */\n static parseCacheControl(header: string): {\n maxAge?: number;\n noCache?: boolean;\n noStore?: boolean;\n } {\n const result: { maxAge?: number; noCache?: boolean; noStore?: boolean } =\n {};\n\n const parts = header.split(\",\").map((p) => p.trim().toLowerCase());\n\n for (const part of parts) {\n if (part === \"no-cache\") result.noCache = true;\n if (part === \"no-store\") result.noStore = true;\n if (part.startsWith(\"max-age=\")) {\n const age = Number.parseInt(part.slice(8), 10);\n if (!Number.isNaN(age)) result.maxAge = age * 1000; // Convert to ms\n }\n }\n\n return result;\n }\n}\n","/**\n * Request/Response Interceptors\n *\n * Middleware for modifying requests, responses, and handling errors.\n */\n\nimport type { SDKError } from \"../errors/index.js\";\nimport type { RequestOptions } from \"../transport/types.js\";\n\n/** Request context passed through interceptor chain */\nexport interface RequestContext {\n /** Original request options */\n request: RequestOptions;\n /** Request start time */\n startedAt: number;\n /** Unique request ID */\n requestId: string;\n /** Retry attempt number (0 = first attempt) */\n attempt: number;\n /** Custom metadata */\n meta: Record<string, unknown>;\n}\n\n/** Response context */\nexport interface ResponseContext<T = unknown> {\n /** Request context */\n request: RequestContext;\n /** Response data */\n data: T;\n /** Response time in ms */\n durationMs: number;\n /** HTTP status (if available) */\n status?: number;\n}\n\n/** Error context */\nexport interface ErrorContext {\n /** Request context */\n request: RequestContext;\n /** The error */\n error: SDKError;\n /** Duration before error */\n durationMs: number;\n}\n\n/** Interceptor interface */\nexport interface Interceptor {\n /** Modify request before sending */\n onRequest?(ctx: RequestContext): RequestContext | Promise<RequestContext>;\n /** Process successful response */\n onResponse?<T>(ctx: ResponseContext<T>): T | Promise<T>;\n /** Handle error (can transform or rethrow) */\n onError?(ctx: ErrorContext): void | Promise<void>;\n}\n\n/** Interceptor chain executor */\nexport class InterceptorChain {\n private interceptors: Interceptor[] = [];\n\n /** Add interceptor to chain */\n use(interceptor: Interceptor): this {\n this.interceptors.push(interceptor);\n return this;\n }\n\n /** Remove interceptor */\n remove(interceptor: Interceptor): this {\n const idx = this.interceptors.indexOf(interceptor);\n if (idx >= 0) this.interceptors.splice(idx, 1);\n return this;\n }\n\n /** Run request through interceptors */\n async executeRequest(ctx: RequestContext): Promise<RequestContext> {\n let current = ctx;\n for (const interceptor of this.interceptors) {\n if (interceptor.onRequest) {\n current = await interceptor.onRequest(current);\n }\n }\n return current;\n }\n\n /** Run response through interceptors (reverse order) */\n async executeResponse<T>(ctx: ResponseContext<T>): Promise<T> {\n let data = ctx.data;\n for (let i = this.interceptors.length - 1; i >= 0; i--) {\n const interceptor = this.interceptors[i];\n if (interceptor.onResponse) {\n data = await interceptor.onResponse({ ...ctx, data });\n }\n }\n return data;\n }\n\n /** Notify interceptors of error */\n async executeError(ctx: ErrorContext): Promise<void> {\n for (const interceptor of this.interceptors) {\n if (interceptor.onError) {\n await interceptor.onError(ctx);\n }\n }\n }\n}\n\n/** Generate unique request ID */\nexport function generateRequestId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n// Built-in interceptors\n\n/** Logging interceptor */\nexport function createLoggingInterceptor(\n logger: {\n debug?(msg: string, data?: unknown): void;\n info?(msg: string, data?: unknown): void;\n error?(msg: string, data?: unknown): void;\n } = console,\n): Interceptor {\n return {\n onRequest(ctx) {\n logger.debug?.(\n `[${ctx.requestId}] ${ctx.request.method ?? \"GET\"} ${ctx.request.path}`,\n {\n attempt: ctx.attempt,\n },\n );\n return ctx;\n },\n onResponse(ctx) {\n logger.info?.(\n `[${ctx.request.requestId}] ${ctx.request.request.method ?? \"GET\"} ${ctx.request.request.path} ${ctx.status ?? 200} (${ctx.durationMs}ms)`,\n );\n return ctx.data;\n },\n onError(ctx) {\n logger.error?.(\n `[${ctx.request.requestId}] ${ctx.request.request.method ?? \"GET\"} ${ctx.request.request.path} ${ctx.error.code} (${ctx.durationMs}ms)`,\n {\n error: ctx.error.message,\n },\n );\n },\n };\n}\n\n/** Metrics interceptor */\nexport function createMetricsInterceptor(\n onMetric: (metric: {\n path: string;\n method: string;\n status: \"success\" | \"error\";\n durationMs: number;\n errorCode?: string;\n }) => void,\n): Interceptor {\n return {\n onResponse(ctx) {\n onMetric({\n path: ctx.request.request.path,\n method: ctx.request.request.method ?? \"GET\",\n status: \"success\",\n durationMs: ctx.durationMs,\n });\n return ctx.data;\n },\n onError(ctx) {\n onMetric({\n path: ctx.request.request.path,\n method: ctx.request.request.method ?? \"GET\",\n status: \"error\",\n durationMs: ctx.durationMs,\n errorCode: ctx.error.code,\n });\n },\n };\n}\n\n/** Header injection interceptor */\nexport function createHeaderInterceptor(\n headers:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>),\n): Interceptor {\n return {\n async onRequest(ctx) {\n const h = typeof headers === \"function\" ? await headers() : headers;\n return {\n ...ctx,\n request: {\n ...ctx.request,\n headers: { ...ctx.request.headers, ...h },\n },\n };\n },\n };\n}\n","/**\n * Offline Storage Abstraction\n *\n * Platform-agnostic storage interface with implementations for different environments.\n */\n\n/** Storage interface */\nexport interface Storage {\n get<T>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n clear(): Promise<void>;\n keys(): Promise<string[]>;\n}\n\n/** In-memory storage (default fallback) */\nexport class MemoryStorage implements Storage {\n private data = new Map<string, string>();\n\n async get<T>(key: string): Promise<T | null> {\n const value = this.data.get(key);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.data.set(key, JSON.stringify(value));\n }\n\n async delete(key: string): Promise<void> {\n this.data.delete(key);\n }\n\n async clear(): Promise<void> {\n this.data.clear();\n }\n\n async keys(): Promise<string[]> {\n return Array.from(this.data.keys());\n }\n}\n\n/** Browser localStorage wrapper */\nexport class LocalStorage implements Storage {\n constructor(private prefix = \"sdk_\") {}\n\n private key(k: string): string {\n return `${this.prefix}${k}`;\n }\n\n async get<T>(key: string): Promise<T | null> {\n if (typeof localStorage === \"undefined\") return null;\n const value = localStorage.getItem(this.key(key));\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(this.key(key), JSON.stringify(value));\n }\n\n async delete(key: string): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(this.key(key));\n }\n\n async clear(): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n const keys = await this.keys();\n for (const key of keys) {\n localStorage.removeItem(this.key(key));\n }\n }\n\n async keys(): Promise<string[]> {\n if (typeof localStorage === \"undefined\") return [];\n const result: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(this.prefix)) {\n result.push(key.slice(this.prefix.length));\n }\n }\n return result;\n }\n}\n\n/** Offline request queue */\nexport interface QueuedRequest {\n id: string;\n path: string;\n method: string;\n body?: unknown;\n headers?: Record<string, string>;\n createdAt: number;\n attempts: number;\n idempotencyKey?: string;\n}\n\n/** Offline queue manager */\nexport class OfflineQueue {\n private readonly storageKey = \"offline_queue\";\n\n constructor(private storage: Storage) {}\n\n /** Add request to queue */\n async enqueue(\n request: Omit<QueuedRequest, \"id\" | \"createdAt\" | \"attempts\">,\n ): Promise<string> {\n const queue = await this.getQueue();\n const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n queue.push({\n ...request,\n id,\n createdAt: Date.now(),\n attempts: 0,\n });\n\n await this.storage.set(this.storageKey, queue);\n return id;\n }\n\n /** Get all queued requests */\n async getQueue(): Promise<QueuedRequest[]> {\n return (await this.storage.get<QueuedRequest[]>(this.storageKey)) ?? [];\n }\n\n /** Get next request to process */\n async peek(): Promise<QueuedRequest | null> {\n const queue = await this.getQueue();\n return queue[0] ?? null;\n }\n\n /** Remove request from queue */\n async dequeue(id: string): Promise<void> {\n const queue = await this.getQueue();\n const filtered = queue.filter((r) => r.id !== id);\n await this.storage.set(this.storageKey, filtered);\n }\n\n /** Increment attempt count */\n async incrementAttempts(id: string): Promise<void> {\n const queue = await this.getQueue();\n const request = queue.find((r) => r.id === id);\n if (request) {\n request.attempts++;\n await this.storage.set(this.storageKey, queue);\n }\n }\n\n /** Get queue size */\n async size(): Promise<number> {\n const queue = await this.getQueue();\n return queue.length;\n }\n\n /** Clear queue */\n async clear(): Promise<void> {\n await this.storage.delete(this.storageKey);\n }\n\n /** Process queue with handler */\n async process(\n handler: (request: QueuedRequest) => Promise<boolean>,\n options?: { maxAttempts?: number; batchSize?: number },\n ): Promise<{ processed: number; failed: number }> {\n const maxAttempts = options?.maxAttempts ?? 3;\n const batchSize = options?.batchSize ?? 10;\n\n const queue = await this.getQueue();\n let processed = 0;\n let failed = 0;\n\n for (let i = 0; i < Math.min(queue.length, batchSize); i++) {\n const request = queue[i];\n\n if (request.attempts >= maxAttempts) {\n await this.dequeue(request.id);\n failed++;\n continue;\n }\n\n try {\n const success = await handler(request);\n if (success) {\n await this.dequeue(request.id);\n processed++;\n } else {\n await this.incrementAttempts(request.id);\n }\n } catch {\n await this.incrementAttempts(request.id);\n }\n }\n\n return { processed, failed };\n }\n}\n\n/** Detect available storage */\nexport function detectStorage(): Storage {\n // Browser with localStorage\n if (typeof localStorage !== \"undefined\") {\n return new LocalStorage();\n }\n\n // Fallback to memory\n return new MemoryStorage();\n}\n","/**\n * Platform Abstraction Layer\n *\n * Interfaces and adapters that enable the SDK to run across\n * mobile, desktop, TUI, and web without vendor lock-in.\n *\n * Each platform provides its own implementations:\n * - Web: localStorage, navigator.onLine, fetch\n * - React Native: AsyncStorage, NetInfo, fetch polyfill\n * - Electron: electron-store, net module, node-fetch\n * - Tauri: tauri-plugin-store, tauri events, fetch\n * - Node/TUI: fs-based, always online, node-fetch\n */\n\nimport { detectStorage, type Storage } from \"../storage/index.js\";\n\n/**\n * Secure credential storage interface.\n * Implementations should use platform-specific secure storage:\n * - Web: Encrypted localStorage or IndexedDB\n * - React Native: react-native-keychain\n * - Electron: safeStorage + electron-store\n * - Tauri: tauri-plugin-keyring\n * - Node: keytar or encrypted file\n */\nexport interface SecureStorage {\n /** Store a credential securely */\n setCredential(key: string, value: string): Promise<void>;\n /** Retrieve a credential */\n getCredential(key: string): Promise<string | null>;\n /** Delete a credential */\n deleteCredential(key: string): Promise<void>;\n /** Check if secure storage is available */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Network connectivity information.\n * Implementations should use platform-specific APIs:\n * - Web: navigator.onLine + online/offline events\n * - React Native: @react-native-community/netinfo\n * - Electron: net.online\n * - Tauri: network events\n * - Node/TUI: assume online or use dns lookup\n */\nexport interface NetworkInfo {\n /** Check if device is online */\n isOnline(): boolean;\n /** Subscribe to connectivity changes */\n onConnectivityChange(callback: (online: boolean) => void): () => void;\n /** Get connection quality hint (optional) */\n getConnectionType?(): \"wifi\" | \"cellular\" | \"ethernet\" | \"unknown\";\n}\n\n/**\n * State persistence adapter for cross-session state.\n * Handles syncing SDK state (sessions, queued requests, cache)\n * to platform-appropriate storage.\n */\nexport interface PersistenceAdapter {\n /** Save state snapshot */\n saveState<T>(namespace: string, state: T): Promise<void>;\n /** Load state snapshot */\n loadState<T>(namespace: string): Promise<T | null>;\n /** Clear namespace */\n clearState(namespace: string): Promise<void>;\n /** Subscribe to external state changes (for multi-window/tab sync) */\n onExternalChange?(\n namespace: string,\n callback: (state: unknown) => void,\n ): () => void;\n}\n\n/**\n * Platform capabilities descriptor.\n * Used to adapt SDK behavior to platform constraints.\n */\nexport interface PlatformCapabilities {\n /** Platform identifier */\n platform: \"web\" | \"react-native\" | \"electron\" | \"tauri\" | \"node\";\n /** Supports background execution */\n supportsBackground: boolean;\n /** Supports secure credential storage */\n supportsSecureStorage: boolean;\n /** Supports WebSocket */\n supportsWebSocket: boolean;\n /** Supports SSE (EventSource) */\n supportsSSE: boolean;\n /** Max concurrent connections (browser limits) */\n maxConnections?: number;\n}\n\n/**\n * Platform adapter combining all platform-specific interfaces.\n * Each platform provides one implementation of this interface.\n */\nexport interface PlatformAdapter {\n /** Platform capabilities */\n capabilities: PlatformCapabilities;\n /** General key-value storage */\n storage: Storage;\n /** Secure credential storage (optional) */\n secureStorage?: SecureStorage;\n /** Network info (optional) */\n network?: NetworkInfo;\n /** State persistence (optional) */\n persistence?: PersistenceAdapter;\n /** Fetch implementation */\n fetch: typeof fetch;\n}\n\n// ============================================================================\n// Default Implementations\n// ============================================================================\n\n/**\n * In-memory secure storage fallback.\n * NOT SECURE - use only for development/testing.\n */\nexport class MemorySecureStorage implements SecureStorage {\n private credentials = new Map<string, string>();\n\n async setCredential(key: string, value: string): Promise<void> {\n this.credentials.set(key, value);\n }\n\n async getCredential(key: string): Promise<string | null> {\n return this.credentials.get(key) ?? null;\n }\n\n async deleteCredential(key: string): Promise<void> {\n this.credentials.delete(key);\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Browser-based network info using navigator.onLine.\n */\nexport class BrowserNetworkInfo implements NetworkInfo {\n isOnline(): boolean {\n return typeof navigator !== \"undefined\" ? navigator.onLine : true;\n }\n\n onConnectivityChange(callback: (online: boolean) => void): () => void {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n\n const onOnline = () => callback(true);\n const onOffline = () => callback(false);\n\n window.addEventListener(\"online\", onOnline);\n window.addEventListener(\"offline\", onOffline);\n\n return () => {\n window.removeEventListener(\"online\", onOnline);\n window.removeEventListener(\"offline\", onOffline);\n };\n }\n\n getConnectionType(): \"wifi\" | \"cellular\" | \"ethernet\" | \"unknown\" {\n // Use Network Information API if available\n const nav = navigator as Navigator & {\n connection?: { effectiveType?: string; type?: string };\n };\n if (nav.connection?.type) {\n const type = nav.connection.type;\n if (type === \"wifi\") return \"wifi\";\n if (type === \"cellular\") return \"cellular\";\n if (type === \"ethernet\") return \"ethernet\";\n }\n return \"unknown\";\n }\n}\n\n/**\n * Node.js network info (assumes always online).\n */\nexport class NodeNetworkInfo implements NetworkInfo {\n isOnline(): boolean {\n return true;\n }\n\n onConnectivityChange(_callback: (online: boolean) => void): () => void {\n // Node doesn't have native connectivity events\n return () => {};\n }\n}\n\n/**\n * Storage-based persistence adapter.\n * Uses provided Storage implementation for state persistence.\n */\nexport class StoragePersistence implements PersistenceAdapter {\n constructor(private storage: Storage) {}\n\n async saveState<T>(namespace: string, state: T): Promise<void> {\n await this.storage.set(`state:${namespace}`, state);\n }\n\n async loadState<T>(namespace: string): Promise<T | null> {\n return this.storage.get<T>(`state:${namespace}`);\n }\n\n async clearState(namespace: string): Promise<void> {\n await this.storage.delete(`state:${namespace}`);\n }\n}\n\n/**\n * Browser persistence with localStorage and storage events for tab sync.\n */\nexport class BrowserPersistence implements PersistenceAdapter {\n private prefix: string;\n\n constructor(prefix = \"sdk_state:\") {\n this.prefix = prefix;\n }\n\n async saveState<T>(namespace: string, state: T): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(`${this.prefix}${namespace}`, JSON.stringify(state));\n }\n\n async loadState<T>(namespace: string): Promise<T | null> {\n if (typeof localStorage === \"undefined\") return null;\n const value = localStorage.getItem(`${this.prefix}${namespace}`);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async clearState(namespace: string): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(`${this.prefix}${namespace}`);\n }\n\n onExternalChange(\n namespace: string,\n callback: (state: unknown) => void,\n ): () => void {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n\n const key = `${this.prefix}${namespace}`;\n const handler = (event: StorageEvent) => {\n if (event.key === key && event.newValue) {\n try {\n callback(JSON.parse(event.newValue));\n } catch {\n // Ignore parse errors\n }\n }\n };\n\n window.addEventListener(\"storage\", handler);\n return () => window.removeEventListener(\"storage\", handler);\n }\n}\n\n// ============================================================================\n// Platform Detection and Default Adapter\n// ============================================================================\n\n/**\n * Detect current platform.\n */\nexport function detectPlatform(): PlatformCapabilities[\"platform\"] {\n // Check for Tauri\n if (\n typeof window !== \"undefined\" &&\n \"__TAURI__\" in (window as unknown as Record<string, unknown>)\n ) {\n return \"tauri\";\n }\n\n // Check for Electron\n if (\n typeof process !== \"undefined\" &&\n process.versions &&\n \"electron\" in process.versions\n ) {\n return \"electron\";\n }\n\n // Check for React Native\n if (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") {\n return \"react-native\";\n }\n\n // Check for browser\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n return \"web\";\n }\n\n // Default to Node\n return \"node\";\n}\n\n/**\n * Create default platform adapter for current environment.\n * Override with platform-specific implementations for better integration.\n */\nexport function createDefaultPlatformAdapter(): PlatformAdapter {\n const platform = detectPlatform();\n const isBrowser = platform === \"web\" || platform === \"tauri\";\n const storage = detectStorage();\n\n const capabilities: PlatformCapabilities = {\n platform,\n supportsBackground: platform === \"node\" || platform === \"electron\",\n supportsSecureStorage: false, // Requires platform-specific impl\n supportsWebSocket: true,\n supportsSSE: true,\n maxConnections: isBrowser ? 6 : undefined,\n };\n\n return {\n capabilities,\n storage,\n secureStorage: new MemorySecureStorage(), // Fallback, not secure\n network: isBrowser ? new BrowserNetworkInfo() : new NodeNetworkInfo(),\n persistence: isBrowser\n ? new BrowserPersistence()\n : new StoragePersistence(storage),\n fetch: globalThis.fetch.bind(globalThis),\n };\n}\n\n/**\n * Type-safe platform adapter factory.\n * Use this to create platform adapters with proper typing.\n */\nexport function createPlatformAdapter(\n config: Partial<PlatformAdapter> & { capabilities: PlatformCapabilities },\n): PlatformAdapter {\n const defaults = createDefaultPlatformAdapter();\n return {\n ...defaults,\n ...config,\n };\n}\n","/**\n * Request Retry Logic\n *\n * Per-request retry with exponential backoff and idempotency.\n */\n\nimport { isRetryable, SDKError } from \"../errors/index.js\";\n\n/** Retry configuration */\nexport interface RetryConfig {\n /** Max retry attempts (default: 3) */\n maxAttempts?: number;\n /** Initial delay in ms (default: 1000) */\n initialDelayMs?: number;\n /** Max delay in ms (default: 30000) */\n maxDelayMs?: number;\n /** Backoff multiplier (default: 2) */\n multiplier?: number;\n /** Jitter factor 0-1 (default: 0.2) */\n jitter?: number;\n /** Custom retry predicate */\n shouldRetry?: (error: SDKError, attempt: number) => boolean;\n /** Callback before retry */\n onRetry?: (error: SDKError, attempt: number, delayMs: number) => void;\n /** Cancels pending backoff and prevents another attempt. */\n signal?: AbortSignal;\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<\n Omit<RetryConfig, \"shouldRetry\" | \"onRetry\" | \"signal\">\n> = {\n maxAttempts: 3,\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n multiplier: 2,\n jitter: 0.2,\n};\n\n/** Calculate delay for attempt with jitter */\nexport function calculateDelay(attempt: number, config: RetryConfig): number {\n const { initialDelayMs, maxDelayMs, multiplier, jitter } = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n const baseDelay = Math.min(\n initialDelayMs * multiplier ** attempt,\n maxDelayMs,\n );\n\n const jitterRange = baseDelay * jitter;\n const jitterValue = Math.random() * jitterRange * 2 - jitterRange;\n\n return Math.max(0, Math.floor(baseDelay + jitterValue));\n}\n\n/** Execute function with retry */\nexport async function withRetry<T>(\n fn: (attempt: number) => Promise<T>,\n config: RetryConfig = {},\n): Promise<T> {\n const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;\n let lastError: SDKError | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n config.signal?.throwIfAborted();\n try {\n return await fn(attempt);\n } catch (error) {\n config.signal?.throwIfAborted();\n lastError = SDKError.fromError(error);\n\n // Check if we should retry\n const shouldRetry = config.shouldRetry\n ? config.shouldRetry(lastError, attempt)\n : isRetryable(lastError);\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n throw lastError;\n }\n\n // Calculate delay (use server's retry-after if provided)\n const delay = lastError.retryAfterMs ?? calculateDelay(attempt, config);\n\n config.onRetry?.(lastError, attempt + 1, delay);\n\n await sleep(delay, config.signal);\n }\n }\n\n throw lastError ?? new SDKError(\"Max retries exceeded\", { code: \"UNKNOWN\" });\n}\n\n/** Sleep utility */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** Idempotency key generator */\nexport function generateIdempotencyKey(): string {\n return `idem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Retry decorator for class methods */\nexport function Retryable(config: RetryConfig = {}) {\n return <T>(\n _target: object,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: unknown[]) => Promise<T>>,\n ): TypedPropertyDescriptor<(...args: unknown[]) => Promise<T>> => {\n const original = descriptor.value;\n if (!original) return descriptor;\n\n descriptor.value = async function (\n this: unknown,\n ...args: unknown[]\n ): Promise<T> {\n return withRetry((_attempt) => {\n // Inject attempt count if function accepts it\n return original.apply(this, args);\n }, config);\n };\n\n return descriptor;\n };\n}\n","/**\n * Channel Pattern Matching\n *\n * Generic utility for matching channel patterns with wildcard support.\n * Used for channel subscriptions and event filtering.\n *\n * Pattern syntax:\n * - \"*\" matches all channels\n * - \"foo.*\" matches \"foo.bar\", \"foo.baz\", etc. (dot-separated)\n * - \"foo:*\" matches \"foo:bar\", \"foo:baz\", etc. (colon-separated)\n * - \"foo.bar\" matches exactly \"foo.bar\"\n * - \"session:abc\" matches exactly \"session:abc\"\n */\n\n/**\n * Check if a pattern matches a channel name.\n *\n * @param pattern - The pattern to match against (supports wildcards)\n * @param channel - The channel name to check\n * @returns true if the pattern matches the channel\n */\nexport function matchesChannel(pattern: string, channel: string): boolean {\n // Wildcard matches everything\n if (pattern === \"*\") {\n return true;\n }\n\n // Prefix wildcard with dot separator: \"foo.*\" matches \"foo.bar\", \"foo.baz\", etc.\n // Does NOT match the exact prefix (e.g., \"foo.*\" does NOT match \"foo\")\n if (pattern.endsWith(\".*\")) {\n const prefix = pattern.slice(0, -2);\n return channel.startsWith(`${prefix}.`);\n }\n\n // Prefix wildcard with colon separator: \"session:*\" matches \"session:abc\", etc.\n // Used for session/project/agent channel patterns\n // Does NOT match the exact prefix (e.g., \"session:*\" does NOT match \"session:\")\n if (pattern.endsWith(\":*\")) {\n const prefix = pattern.slice(0, -2);\n return (\n channel.startsWith(`${prefix}:`) && channel.length > prefix.length + 1\n );\n }\n\n // Exact match\n return pattern === channel;\n}\n\n/**\n * Check if any subscribed channel pattern matches the given channel.\n *\n * @param subscribedChannels - Set or array of channel patterns\n * @param channel - The channel to check\n * @returns true if any pattern matches the channel\n */\nexport function matchesAnyChannel(\n subscribedChannels: Set<string> | string[],\n channel: string,\n): boolean {\n const patterns = Array.isArray(subscribedChannels)\n ? subscribedChannels\n : Array.from(subscribedChannels);\n\n return patterns.some((pattern) => matchesChannel(pattern, channel));\n}\n","/**\n * Session ID Translator\n *\n * Generic utility for translating session IDs in event objects.\n * Used to map internal session IDs to client-facing session IDs.\n */\n\nexport interface SessionTranslation {\n /** The internal session ID to replace */\n from: string;\n /** The client-facing session ID to use */\n to: string;\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Translate session IDs in an event object.\n * Performs a deep string replacement via JSON serialization.\n *\n * @param event - The event object to translate\n * @param translation - The session ID mapping\n * @returns A new event object with translated session IDs\n */\nexport function translateSessionId<T>(\n event: T,\n translation: SessionTranslation,\n): T {\n if (!event || typeof event !== \"object\") {\n return event;\n }\n\n // Skip if from/to are the same\n if (translation.from === translation.to) {\n return event;\n }\n\n // Skip if from is empty\n if (!translation.from) {\n return event;\n }\n\n try {\n const json = JSON.stringify(event);\n\n // Use global replace to handle multiple occurrences\n const pattern = new RegExp(escapeRegex(translation.from), \"g\");\n const translated = json.replace(pattern, translation.to);\n\n // Only parse if we actually made changes\n if (translated !== json) {\n return JSON.parse(translated);\n }\n\n return event;\n } catch {\n // If serialization fails, return original\n return event;\n }\n}\n\n/**\n * Create a reusable translator function for a specific session mapping.\n * Pre-compiles the regex pattern for better performance when translating\n * many events with the same mapping.\n */\nexport function createSessionTranslator(\n translation: SessionTranslation,\n): <T>(event: T) => T {\n // Pre-compile the regex for performance\n const pattern = new RegExp(escapeRegex(translation.from), \"g\");\n\n return <T>(event: T): T => {\n if (!event || typeof event !== \"object\") {\n return event;\n }\n\n if (translation.from === translation.to || !translation.from) {\n return event;\n }\n\n try {\n const json = JSON.stringify(event);\n const translated = json.replace(pattern, translation.to);\n\n if (translated !== json) {\n return JSON.parse(translated);\n }\n\n return event;\n } catch {\n return event;\n }\n };\n}\n\n/**\n * Extract session ID from various event structures.\n * Handles different event formats that may contain session information.\n */\nexport function extractSessionId(event: unknown): string | null {\n if (!event || typeof event !== \"object\") {\n return null;\n }\n\n const obj = event as Record<string, unknown>;\n\n // Direct sessionId field\n if (typeof obj.sessionId === \"string\") {\n return obj.sessionId;\n }\n\n // Nested in properties\n if (obj.properties && typeof obj.properties === \"object\") {\n const props = obj.properties as Record<string, unknown>;\n if (typeof props.sessionId === \"string\") {\n return props.sessionId;\n }\n }\n\n // Nested in data\n if (obj.data && typeof obj.data === \"object\") {\n const data = obj.data as Record<string, unknown>;\n if (typeof data.sessionId === \"string\") {\n return data.sessionId;\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["sleep"],"sources":["../src/cache/index.ts","../src/middleware/index.ts","../src/storage/index.ts","../src/platform/index.ts","../src/retry/index.ts","../src/utils/channel-matching.ts","../src/utils/session-translator.ts"],"sourcesContent":["/**\n * Response Caching\n *\n * In-memory cache with TTL and cache-control support.\n */\n\n/** Cache entry */\ninterface CacheEntry<T> {\n data: T;\n cachedAt: number;\n expiresAt: number;\n etag?: string;\n}\n\n/** Cache configuration */\nexport interface CacheConfig {\n /** Default TTL in ms (default: 60000 = 1 minute) */\n defaultTtlMs?: number;\n /** Max entries (default: 1000) */\n maxEntries?: number;\n /** Cache key generator */\n keyGenerator?: (path: string, params?: Record<string, unknown>) => string;\n}\n\n/** Cache interface for different storage backends */\nexport interface CacheStorage<T = unknown> {\n get(key: string): T | undefined | Promise<T | undefined>;\n set(key: string, value: T, ttlMs?: number): void | Promise<void>;\n delete(key: string): void | Promise<void>;\n clear(): void | Promise<void>;\n}\n\n/** In-memory LRU cache */\nexport class MemoryCache<T = unknown> implements CacheStorage<CacheEntry<T>> {\n private cache = new Map<string, CacheEntry<T>>();\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n get(key: string): CacheEntry<T> | undefined {\n const entry = this.cache.get(key);\n if (!entry) return undefined;\n\n // Check expiration\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return undefined;\n }\n\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, entry);\n\n return entry;\n }\n\n set(key: string, value: CacheEntry<T>): void {\n // Evict oldest if at capacity\n if (this.cache.size >= this.maxEntries) {\n const oldest = this.cache.keys().next().value;\n if (oldest) this.cache.delete(oldest);\n }\n\n this.cache.set(key, value);\n }\n\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n /** Get cache stats */\n stats(): { size: number; maxEntries: number } {\n return { size: this.cache.size, maxEntries: this.maxEntries };\n }\n}\n\n/** Response cache manager */\nexport class ResponseCache<T = unknown> {\n private storage: CacheStorage<CacheEntry<T>>;\n private defaultTtlMs: number;\n private keyGenerator: (\n path: string,\n params?: Record<string, unknown>,\n ) => string;\n\n constructor(config: CacheConfig = {}) {\n this.storage = new MemoryCache<T>(config.maxEntries);\n this.defaultTtlMs = config.defaultTtlMs ?? 60000;\n this.keyGenerator = config.keyGenerator ?? this.defaultKeyGenerator;\n }\n\n private defaultKeyGenerator(\n path: string,\n params?: Record<string, unknown>,\n ): string {\n if (!params || Object.keys(params).length === 0) return path;\n const sorted = Object.keys(params).sort();\n const qs = sorted.map((k) => `${k}=${JSON.stringify(params[k])}`).join(\"&\");\n return `${path}?${qs}`;\n }\n\n /** Get cached response */\n async get(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T | undefined> {\n const key = this.keyGenerator(path, params);\n const entry = await this.storage.get(key);\n return entry?.data;\n }\n\n /** Get with stale-while-revalidate support */\n async getWithMeta(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<{ data: T; stale: boolean; etag?: string } | undefined> {\n const key = this.keyGenerator(path, params);\n const entry = await this.storage.get(key);\n\n if (!entry) return undefined;\n\n const now = Date.now();\n const stale = now > entry.expiresAt;\n\n return { data: entry.data, stale, etag: entry.etag };\n }\n\n /** Cache response */\n async set(\n path: string,\n data: T,\n options?: {\n params?: Record<string, unknown>;\n ttlMs?: number;\n etag?: string;\n },\n ): Promise<void> {\n const key = this.keyGenerator(path, options?.params);\n const now = Date.now();\n const ttl = options?.ttlMs ?? this.defaultTtlMs;\n\n await this.storage.set(key, {\n data,\n cachedAt: now,\n expiresAt: now + ttl,\n etag: options?.etag,\n });\n }\n\n /** Invalidate cache entry */\n async invalidate(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<void> {\n const key = this.keyGenerator(path, params);\n await this.storage.delete(key);\n }\n\n /** Invalidate all entries matching prefix */\n async invalidatePrefix(_prefix: string): Promise<void> {\n // Only works with MemoryCache\n if (this.storage instanceof MemoryCache) {\n // Need to iterate - not ideal but works for in-memory\n const cache = this.storage as MemoryCache<T>;\n // Can't iterate Map while modifying, so just clear for now\n cache.clear();\n }\n }\n\n /** Clear entire cache */\n async clear(): Promise<void> {\n await this.storage.clear();\n }\n\n /** Parse Cache-Control header */\n static parseCacheControl(header: string): {\n maxAge?: number;\n noCache?: boolean;\n noStore?: boolean;\n } {\n const result: { maxAge?: number; noCache?: boolean; noStore?: boolean } =\n {};\n\n const parts = header.split(\",\").map((p) => p.trim().toLowerCase());\n\n for (const part of parts) {\n if (part === \"no-cache\") result.noCache = true;\n if (part === \"no-store\") result.noStore = true;\n if (part.startsWith(\"max-age=\")) {\n const age = Number.parseInt(part.slice(8), 10);\n if (!Number.isNaN(age)) result.maxAge = age * 1000; // Convert to ms\n }\n }\n\n return result;\n }\n}\n","/**\n * Request/Response Interceptors\n *\n * Middleware for modifying requests, responses, and handling errors.\n */\n\nimport type { SDKError } from \"../errors/index.js\";\nimport type { RequestOptions } from \"../transport/types.js\";\n\n/** Request context passed through interceptor chain */\nexport interface RequestContext {\n /** Original request options */\n request: RequestOptions;\n /** Request start time */\n startedAt: number;\n /** Unique request ID */\n requestId: string;\n /** Retry attempt number (0 = first attempt) */\n attempt: number;\n /** Custom metadata */\n meta: Record<string, unknown>;\n}\n\n/** Response context */\nexport interface ResponseContext<T = unknown> {\n /** Request context */\n request: RequestContext;\n /** Response data */\n data: T;\n /** Response time in ms */\n durationMs: number;\n /** HTTP status (if available) */\n status?: number;\n}\n\n/** Error context */\nexport interface ErrorContext {\n /** Request context */\n request: RequestContext;\n /** The error */\n error: SDKError;\n /** Duration before error */\n durationMs: number;\n}\n\n/** Interceptor interface */\nexport interface Interceptor {\n /** Modify request before sending */\n onRequest?(ctx: RequestContext): RequestContext | Promise<RequestContext>;\n /** Process successful response */\n onResponse?<T>(ctx: ResponseContext<T>): T | Promise<T>;\n /** Handle error (can transform or rethrow) */\n onError?(ctx: ErrorContext): void | Promise<void>;\n}\n\n/** Interceptor chain executor */\nexport class InterceptorChain {\n private interceptors: Interceptor[] = [];\n\n /** Add interceptor to chain */\n use(interceptor: Interceptor): this {\n this.interceptors.push(interceptor);\n return this;\n }\n\n /** Remove interceptor */\n remove(interceptor: Interceptor): this {\n const idx = this.interceptors.indexOf(interceptor);\n if (idx >= 0) this.interceptors.splice(idx, 1);\n return this;\n }\n\n /** Run request through interceptors */\n async executeRequest(ctx: RequestContext): Promise<RequestContext> {\n let current = ctx;\n for (const interceptor of this.interceptors) {\n if (interceptor.onRequest) {\n current = await interceptor.onRequest(current);\n }\n }\n return current;\n }\n\n /** Run response through interceptors (reverse order) */\n async executeResponse<T>(ctx: ResponseContext<T>): Promise<T> {\n let data = ctx.data;\n for (let i = this.interceptors.length - 1; i >= 0; i--) {\n const interceptor = this.interceptors[i];\n if (interceptor.onResponse) {\n data = await interceptor.onResponse({ ...ctx, data });\n }\n }\n return data;\n }\n\n /** Notify interceptors of error */\n async executeError(ctx: ErrorContext): Promise<void> {\n for (const interceptor of this.interceptors) {\n if (interceptor.onError) {\n await interceptor.onError(ctx);\n }\n }\n }\n}\n\n/** Generate unique request ID */\nexport function generateRequestId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;\n}\n\n// Built-in interceptors\n\n/** Logging interceptor */\nexport function createLoggingInterceptor(\n logger: {\n debug?(msg: string, data?: unknown): void;\n info?(msg: string, data?: unknown): void;\n error?(msg: string, data?: unknown): void;\n } = console,\n): Interceptor {\n return {\n onRequest(ctx) {\n logger.debug?.(\n `[${ctx.requestId}] ${ctx.request.method ?? \"GET\"} ${ctx.request.path}`,\n {\n attempt: ctx.attempt,\n },\n );\n return ctx;\n },\n onResponse(ctx) {\n logger.info?.(\n `[${ctx.request.requestId}] ${ctx.request.request.method ?? \"GET\"} ${ctx.request.request.path} ${ctx.status ?? 200} (${ctx.durationMs}ms)`,\n );\n return ctx.data;\n },\n onError(ctx) {\n logger.error?.(\n `[${ctx.request.requestId}] ${ctx.request.request.method ?? \"GET\"} ${ctx.request.request.path} ${ctx.error.code} (${ctx.durationMs}ms)`,\n {\n error: ctx.error.message,\n },\n );\n },\n };\n}\n\n/** Metrics interceptor */\nexport function createMetricsInterceptor(\n onMetric: (metric: {\n path: string;\n method: string;\n status: \"success\" | \"error\";\n durationMs: number;\n errorCode?: string;\n }) => void,\n): Interceptor {\n return {\n onResponse(ctx) {\n onMetric({\n path: ctx.request.request.path,\n method: ctx.request.request.method ?? \"GET\",\n status: \"success\",\n durationMs: ctx.durationMs,\n });\n return ctx.data;\n },\n onError(ctx) {\n onMetric({\n path: ctx.request.request.path,\n method: ctx.request.request.method ?? \"GET\",\n status: \"error\",\n durationMs: ctx.durationMs,\n errorCode: ctx.error.code,\n });\n },\n };\n}\n\n/** Header injection interceptor */\nexport function createHeaderInterceptor(\n headers:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>),\n): Interceptor {\n return {\n async onRequest(ctx) {\n const h = typeof headers === \"function\" ? await headers() : headers;\n return {\n ...ctx,\n request: {\n ...ctx.request,\n headers: { ...ctx.request.headers, ...h },\n },\n };\n },\n };\n}\n","/**\n * Offline Storage Abstraction\n *\n * Platform-agnostic storage interface with implementations for different environments.\n */\n\n/** Storage interface */\nexport interface Storage {\n get<T>(key: string): Promise<T | null>;\n set<T>(key: string, value: T): Promise<void>;\n delete(key: string): Promise<void>;\n clear(): Promise<void>;\n keys(): Promise<string[]>;\n}\n\n/** In-memory storage (default fallback) */\nexport class MemoryStorage implements Storage {\n private data = new Map<string, string>();\n\n async get<T>(key: string): Promise<T | null> {\n const value = this.data.get(key);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n this.data.set(key, JSON.stringify(value));\n }\n\n async delete(key: string): Promise<void> {\n this.data.delete(key);\n }\n\n async clear(): Promise<void> {\n this.data.clear();\n }\n\n async keys(): Promise<string[]> {\n return Array.from(this.data.keys());\n }\n}\n\n/** Browser localStorage wrapper */\nexport class LocalStorage implements Storage {\n constructor(private prefix = \"sdk_\") {}\n\n private key(k: string): string {\n return `${this.prefix}${k}`;\n }\n\n async get<T>(key: string): Promise<T | null> {\n if (typeof localStorage === \"undefined\") return null;\n const value = localStorage.getItem(this.key(key));\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async set<T>(key: string, value: T): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(this.key(key), JSON.stringify(value));\n }\n\n async delete(key: string): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(this.key(key));\n }\n\n async clear(): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n const keys = await this.keys();\n for (const key of keys) {\n localStorage.removeItem(this.key(key));\n }\n }\n\n async keys(): Promise<string[]> {\n if (typeof localStorage === \"undefined\") return [];\n const result: string[] = [];\n for (let i = 0; i < localStorage.length; i++) {\n const key = localStorage.key(i);\n if (key?.startsWith(this.prefix)) {\n result.push(key.slice(this.prefix.length));\n }\n }\n return result;\n }\n}\n\n/** Offline request queue */\nexport interface QueuedRequest {\n id: string;\n path: string;\n method: string;\n body?: unknown;\n headers?: Record<string, string>;\n createdAt: number;\n attempts: number;\n idempotencyKey?: string;\n}\n\n/** Offline queue manager */\nexport class OfflineQueue {\n private readonly storageKey = \"offline_queue\";\n\n constructor(private storage: Storage) {}\n\n /** Add request to queue */\n async enqueue(\n request: Omit<QueuedRequest, \"id\" | \"createdAt\" | \"attempts\">,\n ): Promise<string> {\n const queue = await this.getQueue();\n const id = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n\n queue.push({\n ...request,\n id,\n createdAt: Date.now(),\n attempts: 0,\n });\n\n await this.storage.set(this.storageKey, queue);\n return id;\n }\n\n /** Get all queued requests */\n async getQueue(): Promise<QueuedRequest[]> {\n return (await this.storage.get<QueuedRequest[]>(this.storageKey)) ?? [];\n }\n\n /** Get next request to process */\n async peek(): Promise<QueuedRequest | null> {\n const queue = await this.getQueue();\n return queue[0] ?? null;\n }\n\n /** Remove request from queue */\n async dequeue(id: string): Promise<void> {\n const queue = await this.getQueue();\n const filtered = queue.filter((r) => r.id !== id);\n await this.storage.set(this.storageKey, filtered);\n }\n\n /** Increment attempt count */\n async incrementAttempts(id: string): Promise<void> {\n const queue = await this.getQueue();\n const request = queue.find((r) => r.id === id);\n if (request) {\n request.attempts++;\n await this.storage.set(this.storageKey, queue);\n }\n }\n\n /** Get queue size */\n async size(): Promise<number> {\n const queue = await this.getQueue();\n return queue.length;\n }\n\n /** Clear queue */\n async clear(): Promise<void> {\n await this.storage.delete(this.storageKey);\n }\n\n /** Process queue with handler */\n async process(\n handler: (request: QueuedRequest) => Promise<boolean>,\n options?: { maxAttempts?: number; batchSize?: number },\n ): Promise<{ processed: number; failed: number }> {\n const maxAttempts = options?.maxAttempts ?? 3;\n const batchSize = options?.batchSize ?? 10;\n\n const queue = await this.getQueue();\n let processed = 0;\n let failed = 0;\n\n for (let i = 0; i < Math.min(queue.length, batchSize); i++) {\n const request = queue[i];\n\n if (request.attempts >= maxAttempts) {\n await this.dequeue(request.id);\n failed++;\n continue;\n }\n\n try {\n const success = await handler(request);\n if (success) {\n await this.dequeue(request.id);\n processed++;\n } else {\n await this.incrementAttempts(request.id);\n }\n } catch {\n await this.incrementAttempts(request.id);\n }\n }\n\n return { processed, failed };\n }\n}\n\n/** Detect available storage */\nexport function detectStorage(): Storage {\n // Browser with localStorage\n if (typeof localStorage !== \"undefined\") {\n return new LocalStorage();\n }\n\n // Fallback to memory\n return new MemoryStorage();\n}\n","/**\n * Platform Abstraction Layer\n *\n * Interfaces and adapters that enable the SDK to run across\n * mobile, desktop, TUI, and web without vendor lock-in.\n *\n * Each platform provides its own implementations:\n * - Web: localStorage, navigator.onLine, fetch\n * - React Native: AsyncStorage, NetInfo, fetch polyfill\n * - Electron: electron-store, net module, node-fetch\n * - Tauri: tauri-plugin-store, tauri events, fetch\n * - Node/TUI: fs-based, always online, node-fetch\n */\n\nimport { detectStorage, type Storage } from \"../storage/index.js\";\n\n/**\n * Secure credential storage interface.\n * Implementations should use platform-specific secure storage:\n * - Web: Encrypted localStorage or IndexedDB\n * - React Native: react-native-keychain\n * - Electron: safeStorage + electron-store\n * - Tauri: tauri-plugin-keyring\n * - Node: keytar or encrypted file\n */\nexport interface SecureStorage {\n /** Store a credential securely */\n setCredential(key: string, value: string): Promise<void>;\n /** Retrieve a credential */\n getCredential(key: string): Promise<string | null>;\n /** Delete a credential */\n deleteCredential(key: string): Promise<void>;\n /** Check if secure storage is available */\n isAvailable(): Promise<boolean>;\n}\n\n/**\n * Network connectivity information.\n * Implementations should use platform-specific APIs:\n * - Web: navigator.onLine + online/offline events\n * - React Native: @react-native-community/netinfo\n * - Electron: net.online\n * - Tauri: network events\n * - Node/TUI: assume online or use dns lookup\n */\nexport interface NetworkInfo {\n /** Check if device is online */\n isOnline(): boolean;\n /** Subscribe to connectivity changes */\n onConnectivityChange(callback: (online: boolean) => void): () => void;\n /** Get connection quality hint (optional) */\n getConnectionType?(): \"wifi\" | \"cellular\" | \"ethernet\" | \"unknown\";\n}\n\n/**\n * State persistence adapter for cross-session state.\n * Handles syncing SDK state (sessions, queued requests, cache)\n * to platform-appropriate storage.\n */\nexport interface PersistenceAdapter {\n /** Save state snapshot */\n saveState<T>(namespace: string, state: T): Promise<void>;\n /** Load state snapshot */\n loadState<T>(namespace: string): Promise<T | null>;\n /** Clear namespace */\n clearState(namespace: string): Promise<void>;\n /** Subscribe to external state changes (for multi-window/tab sync) */\n onExternalChange?(\n namespace: string,\n callback: (state: unknown) => void,\n ): () => void;\n}\n\n/**\n * Platform capabilities descriptor.\n * Used to adapt SDK behavior to platform constraints.\n */\nexport interface PlatformCapabilities {\n /** Platform identifier */\n platform: \"web\" | \"react-native\" | \"electron\" | \"tauri\" | \"node\";\n /** Supports background execution */\n supportsBackground: boolean;\n /** Supports secure credential storage */\n supportsSecureStorage: boolean;\n /** Supports WebSocket */\n supportsWebSocket: boolean;\n /** Supports SSE (EventSource) */\n supportsSSE: boolean;\n /** Max concurrent connections (browser limits) */\n maxConnections?: number;\n}\n\n/**\n * Platform adapter combining all platform-specific interfaces.\n * Each platform provides one implementation of this interface.\n */\nexport interface PlatformAdapter {\n /** Platform capabilities */\n capabilities: PlatformCapabilities;\n /** General key-value storage */\n storage: Storage;\n /** Secure credential storage (optional) */\n secureStorage?: SecureStorage;\n /** Network info (optional) */\n network?: NetworkInfo;\n /** State persistence (optional) */\n persistence?: PersistenceAdapter;\n /** Fetch implementation */\n fetch: typeof fetch;\n}\n\n// ============================================================================\n// Default Implementations\n// ============================================================================\n\n/**\n * In-memory secure storage fallback.\n * NOT SECURE - use only for development/testing.\n */\nexport class MemorySecureStorage implements SecureStorage {\n private credentials = new Map<string, string>();\n\n async setCredential(key: string, value: string): Promise<void> {\n this.credentials.set(key, value);\n }\n\n async getCredential(key: string): Promise<string | null> {\n return this.credentials.get(key) ?? null;\n }\n\n async deleteCredential(key: string): Promise<void> {\n this.credentials.delete(key);\n }\n\n async isAvailable(): Promise<boolean> {\n return true;\n }\n}\n\n/**\n * Browser-based network info using navigator.onLine.\n */\nexport class BrowserNetworkInfo implements NetworkInfo {\n isOnline(): boolean {\n return typeof navigator !== \"undefined\" ? navigator.onLine : true;\n }\n\n onConnectivityChange(callback: (online: boolean) => void): () => void {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n\n const onOnline = () => callback(true);\n const onOffline = () => callback(false);\n\n window.addEventListener(\"online\", onOnline);\n window.addEventListener(\"offline\", onOffline);\n\n return () => {\n window.removeEventListener(\"online\", onOnline);\n window.removeEventListener(\"offline\", onOffline);\n };\n }\n\n getConnectionType(): \"wifi\" | \"cellular\" | \"ethernet\" | \"unknown\" {\n // Use Network Information API if available\n const nav = navigator as Navigator & {\n connection?: { effectiveType?: string; type?: string };\n };\n if (nav.connection?.type) {\n const type = nav.connection.type;\n if (type === \"wifi\") return \"wifi\";\n if (type === \"cellular\") return \"cellular\";\n if (type === \"ethernet\") return \"ethernet\";\n }\n return \"unknown\";\n }\n}\n\n/**\n * Node.js network info (assumes always online).\n */\nexport class NodeNetworkInfo implements NetworkInfo {\n isOnline(): boolean {\n return true;\n }\n\n onConnectivityChange(_callback: (online: boolean) => void): () => void {\n // Node doesn't have native connectivity events\n return () => {};\n }\n}\n\n/**\n * Storage-based persistence adapter.\n * Uses provided Storage implementation for state persistence.\n */\nexport class StoragePersistence implements PersistenceAdapter {\n constructor(private storage: Storage) {}\n\n async saveState<T>(namespace: string, state: T): Promise<void> {\n await this.storage.set(`state:${namespace}`, state);\n }\n\n async loadState<T>(namespace: string): Promise<T | null> {\n return this.storage.get<T>(`state:${namespace}`);\n }\n\n async clearState(namespace: string): Promise<void> {\n await this.storage.delete(`state:${namespace}`);\n }\n}\n\n/**\n * Browser persistence with localStorage and storage events for tab sync.\n */\nexport class BrowserPersistence implements PersistenceAdapter {\n private prefix: string;\n\n constructor(prefix = \"sdk_state:\") {\n this.prefix = prefix;\n }\n\n async saveState<T>(namespace: string, state: T): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.setItem(`${this.prefix}${namespace}`, JSON.stringify(state));\n }\n\n async loadState<T>(namespace: string): Promise<T | null> {\n if (typeof localStorage === \"undefined\") return null;\n const value = localStorage.getItem(`${this.prefix}${namespace}`);\n if (!value) return null;\n try {\n return JSON.parse(value) as T;\n } catch {\n return null;\n }\n }\n\n async clearState(namespace: string): Promise<void> {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(`${this.prefix}${namespace}`);\n }\n\n onExternalChange(\n namespace: string,\n callback: (state: unknown) => void,\n ): () => void {\n if (typeof window === \"undefined\") {\n return () => {};\n }\n\n const key = `${this.prefix}${namespace}`;\n const handler = (event: StorageEvent) => {\n if (event.key === key && event.newValue) {\n try {\n callback(JSON.parse(event.newValue));\n } catch {\n // Ignore parse errors\n }\n }\n };\n\n window.addEventListener(\"storage\", handler);\n return () => window.removeEventListener(\"storage\", handler);\n }\n}\n\n// ============================================================================\n// Platform Detection and Default Adapter\n// ============================================================================\n\n/**\n * Detect current platform.\n */\nexport function detectPlatform(): PlatformCapabilities[\"platform\"] {\n // Check for Tauri\n if (\n typeof window !== \"undefined\" &&\n \"__TAURI__\" in (window as unknown as Record<string, unknown>)\n ) {\n return \"tauri\";\n }\n\n // Check for Electron\n if (\n typeof process !== \"undefined\" &&\n process.versions &&\n \"electron\" in process.versions\n ) {\n return \"electron\";\n }\n\n // Check for React Native\n if (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") {\n return \"react-native\";\n }\n\n // Check for browser\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n return \"web\";\n }\n\n // Default to Node\n return \"node\";\n}\n\n/**\n * Create default platform adapter for current environment.\n * Override with platform-specific implementations for better integration.\n */\nexport function createDefaultPlatformAdapter(): PlatformAdapter {\n const platform = detectPlatform();\n const isBrowser = platform === \"web\" || platform === \"tauri\";\n const storage = detectStorage();\n\n const capabilities: PlatformCapabilities = {\n platform,\n supportsBackground: platform === \"node\" || platform === \"electron\",\n supportsSecureStorage: false, // Requires platform-specific impl\n supportsWebSocket: true,\n supportsSSE: true,\n maxConnections: isBrowser ? 6 : undefined,\n };\n\n return {\n capabilities,\n storage,\n secureStorage: new MemorySecureStorage(), // Fallback, not secure\n network: isBrowser ? new BrowserNetworkInfo() : new NodeNetworkInfo(),\n persistence: isBrowser\n ? new BrowserPersistence()\n : new StoragePersistence(storage),\n fetch: globalThis.fetch.bind(globalThis),\n };\n}\n\n/**\n * Type-safe platform adapter factory.\n * Use this to create platform adapters with proper typing.\n */\nexport function createPlatformAdapter(\n config: Partial<PlatformAdapter> & { capabilities: PlatformCapabilities },\n): PlatformAdapter {\n const defaults = createDefaultPlatformAdapter();\n return {\n ...defaults,\n ...config,\n };\n}\n","/**\n * Request Retry Logic\n *\n * Per-request retry with exponential backoff and idempotency.\n */\n\nimport { isRetryable, SDKError } from \"../errors/index.js\";\n\n/** Retry configuration */\nexport interface RetryConfig {\n /** Max retry attempts (default: 3) */\n maxAttempts?: number;\n /** Initial delay in ms (default: 1000) */\n initialDelayMs?: number;\n /** Max delay in ms (default: 30000) */\n maxDelayMs?: number;\n /** Backoff multiplier (default: 2) */\n multiplier?: number;\n /** Jitter factor 0-1 (default: 0.2) */\n jitter?: number;\n /** Custom retry predicate */\n shouldRetry?: (error: SDKError, attempt: number) => boolean;\n /** Callback before retry */\n onRetry?: (error: SDKError, attempt: number, delayMs: number) => void;\n /** Cancels pending backoff and prevents another attempt. */\n signal?: AbortSignal;\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<\n Omit<RetryConfig, \"shouldRetry\" | \"onRetry\" | \"signal\">\n> = {\n maxAttempts: 3,\n initialDelayMs: 1000,\n maxDelayMs: 30000,\n multiplier: 2,\n jitter: 0.2,\n};\n\n/** Calculate delay for attempt with jitter */\nexport function calculateDelay(attempt: number, config: RetryConfig): number {\n const { initialDelayMs, maxDelayMs, multiplier, jitter } = {\n ...DEFAULT_RETRY_CONFIG,\n ...config,\n };\n\n const baseDelay = Math.min(\n initialDelayMs * multiplier ** attempt,\n maxDelayMs,\n );\n\n const jitterRange = baseDelay * jitter;\n const jitterValue = Math.random() * jitterRange * 2 - jitterRange;\n\n return Math.max(0, Math.floor(baseDelay + jitterValue));\n}\n\n/** Execute function with retry */\nexport async function withRetry<T>(\n fn: (attempt: number) => Promise<T>,\n config: RetryConfig = {},\n): Promise<T> {\n const maxAttempts = config.maxAttempts ?? DEFAULT_RETRY_CONFIG.maxAttempts;\n let lastError: SDKError | null = null;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n config.signal?.throwIfAborted();\n try {\n return await fn(attempt);\n } catch (error) {\n config.signal?.throwIfAborted();\n lastError = SDKError.fromError(error);\n\n // Check if we should retry\n const shouldRetry = config.shouldRetry\n ? config.shouldRetry(lastError, attempt)\n : isRetryable(lastError);\n\n if (!shouldRetry || attempt >= maxAttempts - 1) {\n throw lastError;\n }\n\n // Calculate delay (use server's retry-after if provided)\n const delay = lastError.retryAfterMs ?? calculateDelay(attempt, config);\n\n config.onRetry?.(lastError, attempt + 1, delay);\n\n await sleep(delay, config.signal);\n }\n }\n\n throw lastError ?? new SDKError(\"Max retries exceeded\", { code: \"UNKNOWN\" });\n}\n\n/** Sleep utility */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** Idempotency key generator */\nexport function generateIdempotencyKey(): string {\n return `idem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/** Retry decorator for class methods */\nexport function Retryable(config: RetryConfig = {}) {\n return <T>(\n _target: object,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: unknown[]) => Promise<T>>,\n ): TypedPropertyDescriptor<(...args: unknown[]) => Promise<T>> => {\n const original = descriptor.value;\n if (!original) return descriptor;\n\n descriptor.value = async function (\n this: unknown,\n ...args: unknown[]\n ): Promise<T> {\n return withRetry((_attempt) => {\n // Inject attempt count if function accepts it\n return original.apply(this, args);\n }, config);\n };\n\n return descriptor;\n };\n}\n","/**\n * Channel Pattern Matching\n *\n * Generic utility for matching channel patterns with wildcard support.\n * Used for channel subscriptions and event filtering.\n *\n * Pattern syntax:\n * - \"*\" matches all channels\n * - \"foo.*\" matches \"foo.bar\", \"foo.baz\", etc. (dot-separated)\n * - \"foo:*\" matches \"foo:bar\", \"foo:baz\", etc. (colon-separated)\n * - \"foo.bar\" matches exactly \"foo.bar\"\n * - \"session:abc\" matches exactly \"session:abc\"\n */\n\n/**\n * Check if a pattern matches a channel name.\n *\n * @param pattern - The pattern to match against (supports wildcards)\n * @param channel - The channel name to check\n * @returns true if the pattern matches the channel\n */\nexport function matchesChannel(pattern: string, channel: string): boolean {\n // Wildcard matches everything\n if (pattern === \"*\") {\n return true;\n }\n\n // Prefix wildcard with dot separator: \"foo.*\" matches \"foo.bar\", \"foo.baz\", etc.\n // Does NOT match the exact prefix (e.g., \"foo.*\" does NOT match \"foo\")\n if (pattern.endsWith(\".*\")) {\n const prefix = pattern.slice(0, -2);\n return channel.startsWith(`${prefix}.`);\n }\n\n // Prefix wildcard with colon separator: \"session:*\" matches \"session:abc\", etc.\n // Used for session/project/agent channel patterns\n // Does NOT match the exact prefix (e.g., \"session:*\" does NOT match \"session:\")\n if (pattern.endsWith(\":*\")) {\n const prefix = pattern.slice(0, -2);\n return (\n channel.startsWith(`${prefix}:`) && channel.length > prefix.length + 1\n );\n }\n\n // Exact match\n return pattern === channel;\n}\n\n/**\n * Check if any subscribed channel pattern matches the given channel.\n *\n * @param subscribedChannels - Set or array of channel patterns\n * @param channel - The channel to check\n * @returns true if any pattern matches the channel\n */\nexport function matchesAnyChannel(\n subscribedChannels: Set<string> | string[],\n channel: string,\n): boolean {\n const patterns = Array.isArray(subscribedChannels)\n ? subscribedChannels\n : Array.from(subscribedChannels);\n\n return patterns.some((pattern) => matchesChannel(pattern, channel));\n}\n","/**\n * Session ID Translator\n *\n * Generic utility for translating session IDs in event objects.\n * Used to map internal session IDs to client-facing session IDs.\n */\n\nexport interface SessionTranslation {\n /** The internal session ID to replace */\n from: string;\n /** The client-facing session ID to use */\n to: string;\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Translate session IDs in an event object.\n * Performs a deep string replacement via JSON serialization.\n *\n * @param event - The event object to translate\n * @param translation - The session ID mapping\n * @returns A new event object with translated session IDs\n */\nexport function translateSessionId<T>(\n event: T,\n translation: SessionTranslation,\n): T {\n if (!event || typeof event !== \"object\") {\n return event;\n }\n\n // Skip if from/to are the same\n if (translation.from === translation.to) {\n return event;\n }\n\n // Skip if from is empty\n if (!translation.from) {\n return event;\n }\n\n try {\n const json = JSON.stringify(event);\n\n // Use global replace to handle multiple occurrences\n const pattern = new RegExp(escapeRegex(translation.from), \"g\");\n const translated = json.replace(pattern, translation.to);\n\n // Only parse if we actually made changes\n if (translated !== json) {\n return JSON.parse(translated);\n }\n\n return event;\n } catch {\n // If serialization fails, return original\n return event;\n }\n}\n\n/**\n * Create a reusable translator function for a specific session mapping.\n * Pre-compiles the regex pattern for better performance when translating\n * many events with the same mapping.\n */\nexport function createSessionTranslator(\n translation: SessionTranslation,\n): <T>(event: T) => T {\n // Pre-compile the regex for performance\n const pattern = new RegExp(escapeRegex(translation.from), \"g\");\n\n return <T>(event: T): T => {\n if (!event || typeof event !== \"object\") {\n return event;\n }\n\n if (translation.from === translation.to || !translation.from) {\n return event;\n }\n\n try {\n const json = JSON.stringify(event);\n const translated = json.replace(pattern, translation.to);\n\n if (translated !== json) {\n return JSON.parse(translated);\n }\n\n return event;\n } catch {\n return event;\n }\n };\n}\n\n/**\n * Extract session ID from various event structures.\n * Handles different event formats that may contain session information.\n */\nexport function extractSessionId(event: unknown): string | null {\n if (!event || typeof event !== \"object\") {\n return null;\n }\n\n const obj = event as Record<string, unknown>;\n\n // Direct sessionId field\n if (typeof obj.sessionId === \"string\") {\n return obj.sessionId;\n }\n\n // Nested in properties\n if (obj.properties && typeof obj.properties === \"object\") {\n const props = obj.properties as Record<string, unknown>;\n if (typeof props.sessionId === \"string\") {\n return props.sessionId;\n }\n }\n\n // Nested in data\n if (obj.data && typeof obj.data === \"object\") {\n const data = obj.data as Record<string, unknown>;\n if (typeof data.sessionId === \"string\") {\n return data.sessionId;\n }\n }\n\n return null;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { a as RequestPlanBridge, c as InteractionBroker, d as InteractionQuestionSchema, f as MAX_INTERACTION_DECISION_TIMEOUT_MS, h as interactionDataToQuestionAnswers, i as RequestPermissionBridge, l as InteractionBrokerOptions, m as interactionAnswerSpecForQuestions, n as BrokerInteractionTools, o as brokerInteractionTools, p as coercePermissionGrant, r as PermissionPromptBridge, s as DEFAULT_INTERACTION_DECISION_TIMEOUT_MS, t as AskUserBridge, u as InteractionQuestion } from "../tools-
|
|
1
|
+
import { a as RequestPlanBridge, c as InteractionBroker, d as InteractionQuestionSchema, f as MAX_INTERACTION_DECISION_TIMEOUT_MS, h as interactionDataToQuestionAnswers, i as RequestPermissionBridge, l as InteractionBrokerOptions, m as interactionAnswerSpecForQuestions, n as BrokerInteractionTools, o as brokerInteractionTools, p as coercePermissionGrant, r as PermissionPromptBridge, s as DEFAULT_INTERACTION_DECISION_TIMEOUT_MS, t as AskUserBridge, u as InteractionQuestion } from "../tools-DeZkIW3h.js";
|
|
2
2
|
import { InteractionExecutionBinding, StreamEvent } from "@tangle-network/agent-interface";
|
|
3
|
-
|
|
4
3
|
//#region src/interactions/http-bridge.d.ts
|
|
5
4
|
/**
|
|
6
5
|
* Loopback JSON bridge for runners with an extension API but no MCP support.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/interactions/http-bridge.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/interactions/http-bridge.ts"],"mappings":";;;;;;;;;cAsCa;WACF;mBACQ;mBACA;mBACA;mBACA;mBACA;UACT;UACA;EAER,YACE,QAAQ,mBACR;IACE;IACA,SAAS;IACT;IACA,QAAQ,OAAO;;MAUf;MAIA;EAIE,SAAS;EAgET,QAAQ;UAUA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as closeHttpServer, t as SerializedTransportLifecycle } from "../lifecycle-
|
|
1
|
+
import { n as closeHttpServer, t as SerializedTransportLifecycle } from "../lifecycle-BljLcnY5.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { InteractionAnswerSpecSchema, InteractionKind, InteractionRequestSchema, PERMISSION_GRANT_FIELD, interactionRequestDigest, permissionAnswerSpec, validateInteractionResponse } from "@tangle-network/agent-interface";
|
|
4
4
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
@@ -284,7 +284,7 @@ function brokerInteractionTools(broker, options) {
|
|
|
284
284
|
}
|
|
285
285
|
//#endregion
|
|
286
286
|
//#region src/interactions/http-bridge.ts
|
|
287
|
-
const MAX_HTTP_BODY_BYTES =
|
|
287
|
+
const MAX_HTTP_BODY_BYTES = 1048576;
|
|
288
288
|
const permissionBodySchema = z.strictObject({
|
|
289
289
|
tool_name: z.string().min(1),
|
|
290
290
|
input: z.record(z.string(), z.unknown()).optional()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/interactions/broker.ts","../../src/interactions/tools.ts","../../src/interactions/http-bridge.ts"],"sourcesContent":["import {\n type InteractionAnswerSpec,\n InteractionAnswerSpecSchema,\n type InteractionExecutionBinding,\n InteractionKind,\n type InteractionRequest,\n type InteractionRequestMaterial,\n InteractionRequestSchema,\n type InteractionResponseScope,\n interactionRequestDigest,\n PERMISSION_GRANT_FIELD,\n type PermissionGrant,\n permissionAnswerSpec,\n type StreamEvent,\n validateInteractionResponse,\n} from \"@tangle-network/agent-interface\";\nimport { z } from \"zod\";\n\nexport const DEFAULT_INTERACTION_DECISION_TIMEOUT_MS = 300_000;\nexport const MAX_INTERACTION_DECISION_TIMEOUT_MS = 2_147_483_647;\n\nexport interface InteractionBrokerOptions {\n /** Default wait for an operator response before the declared default applies. */\n decisionTimeoutMs?: number;\n}\n\nexport const InteractionQuestionSchema = z.object({\n question: z.string().min(1),\n options: z\n .array(\n z.object({\n label: z.string().min(1),\n description: z.string().optional(),\n }),\n )\n .optional(),\n multiSelect: z.boolean().optional(),\n});\nexport type InteractionQuestion = z.infer<typeof InteractionQuestionSchema>;\nconst InteractionQuestionsSchema = z.array(InteractionQuestionSchema).min(1);\n\nfunction checkedTimeout(timeoutMs: number): number {\n if (\n !Number.isFinite(timeoutMs) ||\n timeoutMs <= 0 ||\n timeoutMs > MAX_INTERACTION_DECISION_TIMEOUT_MS\n ) {\n throw new RangeError(\n `Interaction timeout must be between 1 and ${MAX_INTERACTION_DECISION_TIMEOUT_MS} milliseconds`,\n );\n }\n return timeoutMs;\n}\n\nfunction bindInteractionRequest(\n binding: InteractionExecutionBinding,\n request: Omit<InteractionRequestMaterial, \"binding\">,\n): InteractionRequest {\n const material: InteractionRequestMaterial = {\n ...request,\n binding: { ...binding, interactionId: request.id },\n };\n return InteractionRequestSchema.parse({\n ...material,\n requestDigest: interactionRequestDigest(material),\n });\n}\n\n/** Fail-closed coercion: anything other than a known allow grant denies. */\nexport function coercePermissionGrant(value: unknown): PermissionGrant {\n return value === \"allow_once\" ||\n value === \"allow_session\" ||\n value === \"allow_always\"\n ? value\n : \"deny\";\n}\n\n/** Convert canonical question fields (`q0`, `q1`) to positional answers. */\nexport function interactionDataToQuestionAnswers(\n data: Record<string, unknown>,\n): string[][] {\n const positional: Record<string, string[]> = {};\n for (const [key, value] of Object.entries(data)) {\n const index = /^q(\\d+)$/.exec(key)?.[1] ?? key;\n positional[index] = Array.isArray(value)\n ? value.map(String)\n : [String(value)];\n }\n return Object.entries(positional)\n .sort(([left], [right]) =>\n /^\\d+$/.test(left) && /^\\d+$/.test(right)\n ? Number(left) - Number(right)\n : 0,\n )\n .map(([, value]) => value);\n}\n\n/** Build one canonical answer field for each question. */\nexport function interactionAnswerSpecForQuestions(\n questions: InteractionQuestion[],\n): InteractionAnswerSpec {\n const validatedQuestions = InteractionQuestionsSchema.parse(questions);\n return InteractionAnswerSpecSchema.parse({\n fields: validatedQuestions.map((question, index) => {\n const name = `q${index}`;\n if (question.options?.length) {\n return {\n type: \"select\",\n name,\n label: question.question,\n required: true,\n multi: question.multiSelect === true,\n allowCustom: true,\n options: question.options.map((option) => ({\n value: option.label,\n label: option.label,\n ...(option.description === undefined\n ? {}\n : { description: option.description }),\n })),\n };\n }\n return {\n type: \"text\",\n name,\n label: question.question,\n required: true,\n };\n }),\n });\n}\n\ntype PendingPermission = {\n request: InteractionRequest;\n settle: (grant: PermissionGrant) => void;\n};\n\ntype PendingQuestion = {\n request: InteractionRequest;\n settle: (answers: string[][] | null) => void;\n};\n\ntype InteractionEventSink = (event: StreamEvent) => unknown;\n\nfunction responseId(response: unknown): string | undefined {\n if (!response || typeof response !== \"object\") return undefined;\n const id = Reflect.get(response, \"id\");\n return typeof id === \"string\" ? id : undefined;\n}\n\nfunction matchesExecution(\n request: InteractionRequest,\n binding: InteractionExecutionBinding,\n): boolean {\n const actual = request.binding;\n return (\n actual.runId === binding.runId &&\n actual.provider === binding.provider &&\n actual.environmentId === binding.environmentId &&\n actual.sessionId === binding.sessionId &&\n actual.executionId === binding.executionId\n );\n}\n\n/**\n * One interaction round-trip for every runner adapter.\n *\n * A runner emits a request and waits here. The UI returns a canonical response.\n * The first response, timeout, or session teardown settles the request.\n */\nexport class InteractionBroker {\n private readonly pendingPermissions = new Map<string, PendingPermission>();\n private readonly pendingQuestions = new Map<string, PendingQuestion>();\n private readonly decisionTimeoutMs: number;\n\n constructor(options: InteractionBrokerOptions = {}) {\n this.decisionTimeoutMs = checkedTimeout(\n options.decisionTimeoutMs ?? DEFAULT_INTERACTION_DECISION_TIMEOUT_MS,\n );\n }\n\n private hasPendingInteraction(id: string): boolean {\n return (\n this.pendingPermissions.has(id) || this.pendingQuestions.has(id)\n );\n }\n\n /** Emit a permission request and wait for its decision. */\n request(opts: {\n id: string;\n sessionId: string;\n binding: InteractionExecutionBinding;\n toolName: string;\n input?: unknown;\n allowlistGrant: PermissionGrant;\n timeoutMs?: number;\n signal?: AbortSignal;\n emit?: InteractionEventSink;\n }): Promise<PermissionGrant> {\n if (\n opts.binding.sessionId !== opts.sessionId ||\n this.hasPendingInteraction(opts.id)\n ) {\n return Promise.resolve(\"deny\");\n }\n\n const timeoutMs = checkedTimeout(\n opts.timeoutMs ?? this.decisionTimeoutMs,\n );\n const responseScopes: InteractionResponseScope[] =\n opts.allowlistGrant === \"allow_always\"\n ? [\"interaction\", \"session\", \"persistent\"]\n : opts.allowlistGrant === \"allow_session\"\n ? [\"interaction\", \"session\"]\n : [\"interaction\"];\n const request = bindInteractionRequest(opts.binding, {\n id: opts.id,\n kind: InteractionKind.Permission,\n title: `Allow tool \"${opts.toolName}\"?`,\n subject: {\n type: \"tool\",\n toolName: opts.toolName,\n ...(opts.input === undefined ? {} : { input: opts.input }),\n },\n answerSpec: permissionAnswerSpec({ responseScopes }),\n responseScopes,\n default:\n opts.allowlistGrant === \"deny\"\n ? { outcome: \"declined\" }\n : {\n outcome: \"accepted\",\n data: { [PERMISSION_GRANT_FIELD]: [opts.allowlistGrant] },\n },\n timeoutMs,\n onTimeout: \"default\",\n });\n\n return new Promise<PermissionGrant>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const abort = () => settle(\"deny\");\n const settle = (grant: PermissionGrant) => {\n if (!this.pendingPermissions.delete(opts.id)) return;\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener(\"abort\", abort);\n resolve(grant);\n };\n this.pendingPermissions.set(opts.id, {\n request,\n settle,\n });\n if (!opts.emit) {\n settle(opts.allowlistGrant);\n return;\n }\n timer = setTimeout(() => settle(opts.allowlistGrant), timeoutMs);\n if (opts.signal?.aborted) {\n settle(\"deny\");\n return;\n }\n opts.signal?.addEventListener(\"abort\", abort, { once: true });\n if (opts.signal?.aborted) {\n settle(\"deny\");\n return;\n }\n try {\n void Promise.resolve(opts.emit({ type: \"interaction\", request })).catch(\n () => settle(opts.allowlistGrant),\n );\n } catch {\n settle(opts.allowlistGrant);\n }\n });\n }\n\n /** Resolve a pending permission. Invalid or excessive grants deny. */\n respond(response: unknown): boolean {\n const id = responseId(response);\n if (!id) return false;\n const entry = this.pendingPermissions.get(id);\n if (!entry) return false;\n const validation = validateInteractionResponse(entry.request, response);\n if (!validation.ok || validation.response.outcome !== \"accepted\") {\n entry.settle(\"deny\");\n return true;\n }\n const raw = validation.response.data?.[PERMISSION_GRANT_FIELD];\n const selected =\n Array.isArray(raw) && raw.length === 1 ? raw[0] : undefined;\n entry.settle(coercePermissionGrant(selected));\n return true;\n }\n\n /** Emit a question and wait for positional answers. */\n requestQuestion(opts: {\n id: string;\n sessionId: string;\n binding: InteractionExecutionBinding;\n questions: InteractionQuestion[];\n timeoutMs?: number;\n signal?: AbortSignal;\n emit?: InteractionEventSink;\n }): Promise<string[][] | null> {\n if (\n opts.binding.sessionId !== opts.sessionId ||\n this.hasPendingInteraction(opts.id)\n ) {\n return Promise.resolve(null);\n }\n\n const timeoutMs = checkedTimeout(\n opts.timeoutMs ?? this.decisionTimeoutMs,\n );\n const request = bindInteractionRequest(opts.binding, {\n id: opts.id,\n kind: InteractionKind.Question,\n title: opts.questions[0]?.question ?? \"Question\",\n answerSpec: interactionAnswerSpecForQuestions(opts.questions),\n default: { outcome: \"cancelled\" },\n timeoutMs,\n onTimeout: \"default\",\n });\n\n return new Promise<string[][] | null>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const abort = () => settle(null);\n const settle = (answers: string[][] | null) => {\n if (!this.pendingQuestions.delete(opts.id)) return;\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener(\"abort\", abort);\n resolve(answers);\n };\n this.pendingQuestions.set(opts.id, {\n request,\n settle,\n });\n if (!opts.emit) {\n settle(null);\n return;\n }\n timer = setTimeout(() => settle(null), timeoutMs);\n if (opts.signal?.aborted) {\n settle(null);\n return;\n }\n opts.signal?.addEventListener(\"abort\", abort, { once: true });\n if (opts.signal?.aborted) {\n settle(null);\n return;\n }\n try {\n void Promise.resolve(opts.emit({ type: \"interaction\", request })).catch(\n () => settle(null),\n );\n } catch {\n settle(null);\n }\n });\n }\n\n /** Resolve a pending question. Invalid, declined, and cancelled replies return null. */\n respondQuestion(response: unknown): boolean {\n const id = responseId(response);\n if (!id) return false;\n const entry = this.pendingQuestions.get(id);\n if (!entry) return false;\n const validation = validateInteractionResponse(entry.request, response);\n if (!validation.ok) {\n entry.settle(null);\n return true;\n }\n const validatedResponse = validation.response;\n entry.settle(\n validatedResponse.outcome === \"accepted\"\n ? interactionDataToQuestionAnswers(validatedResponse.data ?? {})\n : null,\n );\n return true;\n }\n\n /** Fail closed every request that belongs to one session. */\n failSession(sessionId: string): void {\n for (const entry of this.pendingPermissions.values()) {\n if (entry.request.binding.sessionId === sessionId) entry.settle(\"deny\");\n }\n for (const entry of this.pendingQuestions.values()) {\n if (entry.request.binding.sessionId === sessionId) entry.settle(null);\n }\n }\n\n /** Fail closed only the requests from one exact provider execution. */\n failExecution(binding: InteractionExecutionBinding): void {\n for (const entry of this.pendingPermissions.values()) {\n if (matchesExecution(entry.request, binding)) entry.settle(\"deny\");\n }\n for (const entry of this.pendingQuestions.values()) {\n if (matchesExecution(entry.request, binding)) entry.settle(null);\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type {\n DurablePlan,\n InteractionExecutionBinding,\n StreamEvent,\n} from \"@tangle-network/agent-interface\";\nimport type {\n InteractionBroker,\n InteractionQuestion,\n} from \"./broker.js\";\n\n/** Claude Code permission prompt callback. */\nexport type PermissionPromptBridge = (request: {\n tool_name: string;\n input: Record<string, unknown>;\n tool_use_id: string;\n operationId: string;\n signal?: AbortSignal;\n}) => Promise<unknown>;\n\n/** Question callback. Null means that no answer was provided. */\nexport type AskUserBridge = (request: {\n questions: InteractionQuestion[];\n operationId?: string;\n signal?: AbortSignal;\n}) => Promise<string[][] | null>;\n\n/** Generic action approval callback. */\nexport type RequestPermissionBridge = (request: {\n tool_name: string;\n input: Record<string, unknown>;\n operationId?: string;\n signal?: AbortSignal;\n}) => Promise<{ allowed: boolean; message?: string }>;\n\n/** Durable plan submission callback. */\nexport type RequestPlanBridge = (request: {\n plan: string;\n sourceToolCallId: string;\n}) => Promise<DurablePlan>;\n\nexport interface BrokerInteractionTools {\n askUser: AskUserBridge;\n requestPermission: RequestPermissionBridge;\n onStop: () => void;\n}\n\n/** Bind generic interaction tools to one broker session. */\nexport function brokerInteractionTools(\n broker: InteractionBroker,\n options: {\n sessionId: string;\n binding: InteractionExecutionBinding;\n timeoutMs?: number;\n emit?: (event: StreamEvent) => unknown;\n },\n): BrokerInteractionTools {\n return {\n askUser: (request) =>\n broker.requestQuestion({\n id: request.operationId ?? randomUUID(),\n sessionId: options.sessionId,\n binding: options.binding,\n questions: request.questions,\n timeoutMs: options.timeoutMs,\n signal: request.signal,\n emit: options.emit,\n }),\n requestPermission: async (request) => {\n const grant = await broker.request({\n id: request.operationId ?? randomUUID(),\n sessionId: options.sessionId,\n binding: options.binding,\n toolName: request.tool_name,\n input: request.input,\n allowlistGrant: \"deny\",\n timeoutMs: options.timeoutMs,\n signal: request.signal,\n emit: options.emit,\n });\n return { allowed: grant !== \"deny\" };\n },\n onStop: () => broker.failExecution(options.binding),\n };\n}\n","import { randomBytes } from \"node:crypto\";\nimport { createServer, type Server } from \"node:http\";\nimport type {\n InteractionExecutionBinding,\n StreamEvent,\n} from \"@tangle-network/agent-interface\";\nimport { z } from \"zod\";\nimport {\n type InteractionBroker,\n InteractionQuestionSchema,\n} from \"./broker.js\";\nimport {\n closeHttpServer,\n SerializedTransportLifecycle,\n} from \"./lifecycle.js\";\nimport {\n type AskUserBridge,\n brokerInteractionTools,\n type RequestPermissionBridge,\n} from \"./tools.js\";\n\nconst MAX_HTTP_BODY_BYTES = 1024 * 1024;\n\nconst permissionBodySchema = z.strictObject({\n tool_name: z.string().min(1),\n input: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst questionBodySchema = z.strictObject({\n questions: z.array(InteractionQuestionSchema).min(1),\n});\n\n/**\n * Loopback JSON bridge for runners with an extension API but no MCP support.\n *\n * Extensions call `/permission` or `/question`. The bridge blocks until the\n * shared broker receives an operator response.\n */\nexport class InteractionHttpBridge {\n readonly token = randomBytes(24).toString(\"hex\");\n private readonly requestPermission: RequestPermissionBridge;\n private readonly askUser: AskUserBridge;\n private readonly broker: InteractionBroker;\n private readonly binding: InteractionExecutionBinding;\n private readonly lifecycle = new SerializedTransportLifecycle();\n private httpServer?: Server;\n private portValue = 0;\n\n constructor(\n broker: InteractionBroker,\n options: {\n sessionId: string;\n binding: InteractionExecutionBinding;\n timeoutMs?: number;\n emit?: (event: StreamEvent) => unknown;\n },\n ) {\n this.broker = broker;\n this.binding = options.binding;\n const tools = brokerInteractionTools(broker, options);\n this.requestPermission = tools.requestPermission;\n this.askUser = tools.askUser;\n }\n\n get port(): number {\n return this.portValue;\n }\n\n get baseUrl(): string {\n return `http://127.0.0.1:${this.portValue}`;\n }\n\n async start(): Promise<void> {\n return this.lifecycle.start(async () => {\n const httpServer = createServer((request, response) => {\n const send = (status: number, body?: unknown) => {\n if (response.writableEnded) return;\n const text = body === undefined ? \"\" : JSON.stringify(body);\n response\n .writeHead(status, { \"content-type\": \"application/json\" })\n .end(text);\n };\n\n if (request.headers.authorization !== `Bearer ${this.token}`) {\n send(401);\n return;\n }\n if (request.method !== \"POST\") {\n send(405);\n return;\n }\n\n const chunks: Buffer[] = [];\n let size = 0;\n request.on(\"error\", () => send(400));\n request.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_HTTP_BODY_BYTES) {\n send(413);\n request.destroy();\n return;\n }\n chunks.push(chunk);\n });\n request.on(\"end\", () => {\n if (response.writableEnded) return;\n let body: unknown;\n try {\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n body = raw ? JSON.parse(raw) : {};\n } catch {\n send(400, { error: \"invalid json\" });\n return;\n }\n this.route(request.url ?? \"\", body)\n .then((result) => send(result.status, result.body))\n .catch(() => send(500, { error: \"interaction bridge failed\" }));\n });\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n httpServer.once(\"error\", reject);\n httpServer.listen(0, \"127.0.0.1\", resolve);\n });\n } catch (error) {\n httpServer.closeAllConnections?.();\n throw error;\n }\n const address = httpServer.address();\n this.portValue =\n address && typeof address === \"object\" ? address.port : 0;\n this.httpServer = httpServer;\n });\n }\n\n async stop(): Promise<void> {\n return this.lifecycle.stop(async () => {\n this.broker.failExecution(this.binding);\n const httpServer = this.httpServer;\n this.httpServer = undefined;\n this.portValue = 0;\n if (httpServer) await closeHttpServer(httpServer);\n });\n }\n\n private async route(\n url: string,\n body: unknown,\n ): Promise<{ status: number; body: unknown }> {\n const path = new URL(url, \"http://127.0.0.1\").pathname.replace(/\\/+$/, \"\");\n if (path === \"/permission\") {\n const parsed = permissionBodySchema.safeParse(body);\n if (!parsed.success) {\n return { status: 400, body: { error: \"invalid permission request\" } };\n }\n const result = await this.requestPermission({\n tool_name: parsed.data.tool_name,\n input: parsed.data.input ?? {},\n });\n return {\n status: 200,\n body: {\n allowed: result.allowed,\n ...(result.message ? { reason: result.message } : {}),\n },\n };\n }\n if (path === \"/question\") {\n const parsed = questionBodySchema.safeParse(body);\n if (!parsed.success) {\n return { status: 400, body: { error: \"invalid question request\" } };\n }\n const answers = await this.askUser({ questions: parsed.data.questions });\n return { status: 200, body: { answers } };\n }\n return { status: 404, body: { error: \"unknown route\" } };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/interactions/broker.ts","../../src/interactions/tools.ts","../../src/interactions/http-bridge.ts"],"sourcesContent":["import {\n type InteractionAnswerSpec,\n InteractionAnswerSpecSchema,\n type InteractionExecutionBinding,\n InteractionKind,\n type InteractionRequest,\n type InteractionRequestMaterial,\n InteractionRequestSchema,\n type InteractionResponseScope,\n interactionRequestDigest,\n PERMISSION_GRANT_FIELD,\n type PermissionGrant,\n permissionAnswerSpec,\n type StreamEvent,\n validateInteractionResponse,\n} from \"@tangle-network/agent-interface\";\nimport { z } from \"zod\";\n\nexport const DEFAULT_INTERACTION_DECISION_TIMEOUT_MS = 300_000;\nexport const MAX_INTERACTION_DECISION_TIMEOUT_MS = 2_147_483_647;\n\nexport interface InteractionBrokerOptions {\n /** Default wait for an operator response before the declared default applies. */\n decisionTimeoutMs?: number;\n}\n\nexport const InteractionQuestionSchema = z.object({\n question: z.string().min(1),\n options: z\n .array(\n z.object({\n label: z.string().min(1),\n description: z.string().optional(),\n }),\n )\n .optional(),\n multiSelect: z.boolean().optional(),\n});\nexport type InteractionQuestion = z.infer<typeof InteractionQuestionSchema>;\nconst InteractionQuestionsSchema = z.array(InteractionQuestionSchema).min(1);\n\nfunction checkedTimeout(timeoutMs: number): number {\n if (\n !Number.isFinite(timeoutMs) ||\n timeoutMs <= 0 ||\n timeoutMs > MAX_INTERACTION_DECISION_TIMEOUT_MS\n ) {\n throw new RangeError(\n `Interaction timeout must be between 1 and ${MAX_INTERACTION_DECISION_TIMEOUT_MS} milliseconds`,\n );\n }\n return timeoutMs;\n}\n\nfunction bindInteractionRequest(\n binding: InteractionExecutionBinding,\n request: Omit<InteractionRequestMaterial, \"binding\">,\n): InteractionRequest {\n const material: InteractionRequestMaterial = {\n ...request,\n binding: { ...binding, interactionId: request.id },\n };\n return InteractionRequestSchema.parse({\n ...material,\n requestDigest: interactionRequestDigest(material),\n });\n}\n\n/** Fail-closed coercion: anything other than a known allow grant denies. */\nexport function coercePermissionGrant(value: unknown): PermissionGrant {\n return value === \"allow_once\" ||\n value === \"allow_session\" ||\n value === \"allow_always\"\n ? value\n : \"deny\";\n}\n\n/** Convert canonical question fields (`q0`, `q1`) to positional answers. */\nexport function interactionDataToQuestionAnswers(\n data: Record<string, unknown>,\n): string[][] {\n const positional: Record<string, string[]> = {};\n for (const [key, value] of Object.entries(data)) {\n const index = /^q(\\d+)$/.exec(key)?.[1] ?? key;\n positional[index] = Array.isArray(value)\n ? value.map(String)\n : [String(value)];\n }\n return Object.entries(positional)\n .sort(([left], [right]) =>\n /^\\d+$/.test(left) && /^\\d+$/.test(right)\n ? Number(left) - Number(right)\n : 0,\n )\n .map(([, value]) => value);\n}\n\n/** Build one canonical answer field for each question. */\nexport function interactionAnswerSpecForQuestions(\n questions: InteractionQuestion[],\n): InteractionAnswerSpec {\n const validatedQuestions = InteractionQuestionsSchema.parse(questions);\n return InteractionAnswerSpecSchema.parse({\n fields: validatedQuestions.map((question, index) => {\n const name = `q${index}`;\n if (question.options?.length) {\n return {\n type: \"select\",\n name,\n label: question.question,\n required: true,\n multi: question.multiSelect === true,\n allowCustom: true,\n options: question.options.map((option) => ({\n value: option.label,\n label: option.label,\n ...(option.description === undefined\n ? {}\n : { description: option.description }),\n })),\n };\n }\n return {\n type: \"text\",\n name,\n label: question.question,\n required: true,\n };\n }),\n });\n}\n\ntype PendingPermission = {\n request: InteractionRequest;\n settle: (grant: PermissionGrant) => void;\n};\n\ntype PendingQuestion = {\n request: InteractionRequest;\n settle: (answers: string[][] | null) => void;\n};\n\ntype InteractionEventSink = (event: StreamEvent) => unknown;\n\nfunction responseId(response: unknown): string | undefined {\n if (!response || typeof response !== \"object\") return undefined;\n const id = Reflect.get(response, \"id\");\n return typeof id === \"string\" ? id : undefined;\n}\n\nfunction matchesExecution(\n request: InteractionRequest,\n binding: InteractionExecutionBinding,\n): boolean {\n const actual = request.binding;\n return (\n actual.runId === binding.runId &&\n actual.provider === binding.provider &&\n actual.environmentId === binding.environmentId &&\n actual.sessionId === binding.sessionId &&\n actual.executionId === binding.executionId\n );\n}\n\n/**\n * One interaction round-trip for every runner adapter.\n *\n * A runner emits a request and waits here. The UI returns a canonical response.\n * The first response, timeout, or session teardown settles the request.\n */\nexport class InteractionBroker {\n private readonly pendingPermissions = new Map<string, PendingPermission>();\n private readonly pendingQuestions = new Map<string, PendingQuestion>();\n private readonly decisionTimeoutMs: number;\n\n constructor(options: InteractionBrokerOptions = {}) {\n this.decisionTimeoutMs = checkedTimeout(\n options.decisionTimeoutMs ?? DEFAULT_INTERACTION_DECISION_TIMEOUT_MS,\n );\n }\n\n private hasPendingInteraction(id: string): boolean {\n return (\n this.pendingPermissions.has(id) || this.pendingQuestions.has(id)\n );\n }\n\n /** Emit a permission request and wait for its decision. */\n request(opts: {\n id: string;\n sessionId: string;\n binding: InteractionExecutionBinding;\n toolName: string;\n input?: unknown;\n allowlistGrant: PermissionGrant;\n timeoutMs?: number;\n signal?: AbortSignal;\n emit?: InteractionEventSink;\n }): Promise<PermissionGrant> {\n if (\n opts.binding.sessionId !== opts.sessionId ||\n this.hasPendingInteraction(opts.id)\n ) {\n return Promise.resolve(\"deny\");\n }\n\n const timeoutMs = checkedTimeout(\n opts.timeoutMs ?? this.decisionTimeoutMs,\n );\n const responseScopes: InteractionResponseScope[] =\n opts.allowlistGrant === \"allow_always\"\n ? [\"interaction\", \"session\", \"persistent\"]\n : opts.allowlistGrant === \"allow_session\"\n ? [\"interaction\", \"session\"]\n : [\"interaction\"];\n const request = bindInteractionRequest(opts.binding, {\n id: opts.id,\n kind: InteractionKind.Permission,\n title: `Allow tool \"${opts.toolName}\"?`,\n subject: {\n type: \"tool\",\n toolName: opts.toolName,\n ...(opts.input === undefined ? {} : { input: opts.input }),\n },\n answerSpec: permissionAnswerSpec({ responseScopes }),\n responseScopes,\n default:\n opts.allowlistGrant === \"deny\"\n ? { outcome: \"declined\" }\n : {\n outcome: \"accepted\",\n data: { [PERMISSION_GRANT_FIELD]: [opts.allowlistGrant] },\n },\n timeoutMs,\n onTimeout: \"default\",\n });\n\n return new Promise<PermissionGrant>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const abort = () => settle(\"deny\");\n const settle = (grant: PermissionGrant) => {\n if (!this.pendingPermissions.delete(opts.id)) return;\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener(\"abort\", abort);\n resolve(grant);\n };\n this.pendingPermissions.set(opts.id, {\n request,\n settle,\n });\n if (!opts.emit) {\n settle(opts.allowlistGrant);\n return;\n }\n timer = setTimeout(() => settle(opts.allowlistGrant), timeoutMs);\n if (opts.signal?.aborted) {\n settle(\"deny\");\n return;\n }\n opts.signal?.addEventListener(\"abort\", abort, { once: true });\n if (opts.signal?.aborted) {\n settle(\"deny\");\n return;\n }\n try {\n void Promise.resolve(opts.emit({ type: \"interaction\", request })).catch(\n () => settle(opts.allowlistGrant),\n );\n } catch {\n settle(opts.allowlistGrant);\n }\n });\n }\n\n /** Resolve a pending permission. Invalid or excessive grants deny. */\n respond(response: unknown): boolean {\n const id = responseId(response);\n if (!id) return false;\n const entry = this.pendingPermissions.get(id);\n if (!entry) return false;\n const validation = validateInteractionResponse(entry.request, response);\n if (!validation.ok || validation.response.outcome !== \"accepted\") {\n entry.settle(\"deny\");\n return true;\n }\n const raw = validation.response.data?.[PERMISSION_GRANT_FIELD];\n const selected =\n Array.isArray(raw) && raw.length === 1 ? raw[0] : undefined;\n entry.settle(coercePermissionGrant(selected));\n return true;\n }\n\n /** Emit a question and wait for positional answers. */\n requestQuestion(opts: {\n id: string;\n sessionId: string;\n binding: InteractionExecutionBinding;\n questions: InteractionQuestion[];\n timeoutMs?: number;\n signal?: AbortSignal;\n emit?: InteractionEventSink;\n }): Promise<string[][] | null> {\n if (\n opts.binding.sessionId !== opts.sessionId ||\n this.hasPendingInteraction(opts.id)\n ) {\n return Promise.resolve(null);\n }\n\n const timeoutMs = checkedTimeout(\n opts.timeoutMs ?? this.decisionTimeoutMs,\n );\n const request = bindInteractionRequest(opts.binding, {\n id: opts.id,\n kind: InteractionKind.Question,\n title: opts.questions[0]?.question ?? \"Question\",\n answerSpec: interactionAnswerSpecForQuestions(opts.questions),\n default: { outcome: \"cancelled\" },\n timeoutMs,\n onTimeout: \"default\",\n });\n\n return new Promise<string[][] | null>((resolve) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const abort = () => settle(null);\n const settle = (answers: string[][] | null) => {\n if (!this.pendingQuestions.delete(opts.id)) return;\n if (timer) clearTimeout(timer);\n opts.signal?.removeEventListener(\"abort\", abort);\n resolve(answers);\n };\n this.pendingQuestions.set(opts.id, {\n request,\n settle,\n });\n if (!opts.emit) {\n settle(null);\n return;\n }\n timer = setTimeout(() => settle(null), timeoutMs);\n if (opts.signal?.aborted) {\n settle(null);\n return;\n }\n opts.signal?.addEventListener(\"abort\", abort, { once: true });\n if (opts.signal?.aborted) {\n settle(null);\n return;\n }\n try {\n void Promise.resolve(opts.emit({ type: \"interaction\", request })).catch(\n () => settle(null),\n );\n } catch {\n settle(null);\n }\n });\n }\n\n /** Resolve a pending question. Invalid, declined, and cancelled replies return null. */\n respondQuestion(response: unknown): boolean {\n const id = responseId(response);\n if (!id) return false;\n const entry = this.pendingQuestions.get(id);\n if (!entry) return false;\n const validation = validateInteractionResponse(entry.request, response);\n if (!validation.ok) {\n entry.settle(null);\n return true;\n }\n const validatedResponse = validation.response;\n entry.settle(\n validatedResponse.outcome === \"accepted\"\n ? interactionDataToQuestionAnswers(validatedResponse.data ?? {})\n : null,\n );\n return true;\n }\n\n /** Fail closed every request that belongs to one session. */\n failSession(sessionId: string): void {\n for (const entry of this.pendingPermissions.values()) {\n if (entry.request.binding.sessionId === sessionId) entry.settle(\"deny\");\n }\n for (const entry of this.pendingQuestions.values()) {\n if (entry.request.binding.sessionId === sessionId) entry.settle(null);\n }\n }\n\n /** Fail closed only the requests from one exact provider execution. */\n failExecution(binding: InteractionExecutionBinding): void {\n for (const entry of this.pendingPermissions.values()) {\n if (matchesExecution(entry.request, binding)) entry.settle(\"deny\");\n }\n for (const entry of this.pendingQuestions.values()) {\n if (matchesExecution(entry.request, binding)) entry.settle(null);\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport type {\n DurablePlan,\n InteractionExecutionBinding,\n StreamEvent,\n} from \"@tangle-network/agent-interface\";\nimport type {\n InteractionBroker,\n InteractionQuestion,\n} from \"./broker.js\";\n\n/** Claude Code permission prompt callback. */\nexport type PermissionPromptBridge = (request: {\n tool_name: string;\n input: Record<string, unknown>;\n tool_use_id: string;\n operationId: string;\n signal?: AbortSignal;\n}) => Promise<unknown>;\n\n/** Question callback. Null means that no answer was provided. */\nexport type AskUserBridge = (request: {\n questions: InteractionQuestion[];\n operationId?: string;\n signal?: AbortSignal;\n}) => Promise<string[][] | null>;\n\n/** Generic action approval callback. */\nexport type RequestPermissionBridge = (request: {\n tool_name: string;\n input: Record<string, unknown>;\n operationId?: string;\n signal?: AbortSignal;\n}) => Promise<{ allowed: boolean; message?: string }>;\n\n/** Durable plan submission callback. */\nexport type RequestPlanBridge = (request: {\n plan: string;\n sourceToolCallId: string;\n}) => Promise<DurablePlan>;\n\nexport interface BrokerInteractionTools {\n askUser: AskUserBridge;\n requestPermission: RequestPermissionBridge;\n onStop: () => void;\n}\n\n/** Bind generic interaction tools to one broker session. */\nexport function brokerInteractionTools(\n broker: InteractionBroker,\n options: {\n sessionId: string;\n binding: InteractionExecutionBinding;\n timeoutMs?: number;\n emit?: (event: StreamEvent) => unknown;\n },\n): BrokerInteractionTools {\n return {\n askUser: (request) =>\n broker.requestQuestion({\n id: request.operationId ?? randomUUID(),\n sessionId: options.sessionId,\n binding: options.binding,\n questions: request.questions,\n timeoutMs: options.timeoutMs,\n signal: request.signal,\n emit: options.emit,\n }),\n requestPermission: async (request) => {\n const grant = await broker.request({\n id: request.operationId ?? randomUUID(),\n sessionId: options.sessionId,\n binding: options.binding,\n toolName: request.tool_name,\n input: request.input,\n allowlistGrant: \"deny\",\n timeoutMs: options.timeoutMs,\n signal: request.signal,\n emit: options.emit,\n });\n return { allowed: grant !== \"deny\" };\n },\n onStop: () => broker.failExecution(options.binding),\n };\n}\n","import { randomBytes } from \"node:crypto\";\nimport { createServer, type Server } from \"node:http\";\nimport type {\n InteractionExecutionBinding,\n StreamEvent,\n} from \"@tangle-network/agent-interface\";\nimport { z } from \"zod\";\nimport {\n type InteractionBroker,\n InteractionQuestionSchema,\n} from \"./broker.js\";\nimport {\n closeHttpServer,\n SerializedTransportLifecycle,\n} from \"./lifecycle.js\";\nimport {\n type AskUserBridge,\n brokerInteractionTools,\n type RequestPermissionBridge,\n} from \"./tools.js\";\n\nconst MAX_HTTP_BODY_BYTES = 1024 * 1024;\n\nconst permissionBodySchema = z.strictObject({\n tool_name: z.string().min(1),\n input: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst questionBodySchema = z.strictObject({\n questions: z.array(InteractionQuestionSchema).min(1),\n});\n\n/**\n * Loopback JSON bridge for runners with an extension API but no MCP support.\n *\n * Extensions call `/permission` or `/question`. The bridge blocks until the\n * shared broker receives an operator response.\n */\nexport class InteractionHttpBridge {\n readonly token = randomBytes(24).toString(\"hex\");\n private readonly requestPermission: RequestPermissionBridge;\n private readonly askUser: AskUserBridge;\n private readonly broker: InteractionBroker;\n private readonly binding: InteractionExecutionBinding;\n private readonly lifecycle = new SerializedTransportLifecycle();\n private httpServer?: Server;\n private portValue = 0;\n\n constructor(\n broker: InteractionBroker,\n options: {\n sessionId: string;\n binding: InteractionExecutionBinding;\n timeoutMs?: number;\n emit?: (event: StreamEvent) => unknown;\n },\n ) {\n this.broker = broker;\n this.binding = options.binding;\n const tools = brokerInteractionTools(broker, options);\n this.requestPermission = tools.requestPermission;\n this.askUser = tools.askUser;\n }\n\n get port(): number {\n return this.portValue;\n }\n\n get baseUrl(): string {\n return `http://127.0.0.1:${this.portValue}`;\n }\n\n async start(): Promise<void> {\n return this.lifecycle.start(async () => {\n const httpServer = createServer((request, response) => {\n const send = (status: number, body?: unknown) => {\n if (response.writableEnded) return;\n const text = body === undefined ? \"\" : JSON.stringify(body);\n response\n .writeHead(status, { \"content-type\": \"application/json\" })\n .end(text);\n };\n\n if (request.headers.authorization !== `Bearer ${this.token}`) {\n send(401);\n return;\n }\n if (request.method !== \"POST\") {\n send(405);\n return;\n }\n\n const chunks: Buffer[] = [];\n let size = 0;\n request.on(\"error\", () => send(400));\n request.on(\"data\", (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_HTTP_BODY_BYTES) {\n send(413);\n request.destroy();\n return;\n }\n chunks.push(chunk);\n });\n request.on(\"end\", () => {\n if (response.writableEnded) return;\n let body: unknown;\n try {\n const raw = Buffer.concat(chunks).toString(\"utf8\");\n body = raw ? JSON.parse(raw) : {};\n } catch {\n send(400, { error: \"invalid json\" });\n return;\n }\n this.route(request.url ?? \"\", body)\n .then((result) => send(result.status, result.body))\n .catch(() => send(500, { error: \"interaction bridge failed\" }));\n });\n });\n\n try {\n await new Promise<void>((resolve, reject) => {\n httpServer.once(\"error\", reject);\n httpServer.listen(0, \"127.0.0.1\", resolve);\n });\n } catch (error) {\n httpServer.closeAllConnections?.();\n throw error;\n }\n const address = httpServer.address();\n this.portValue =\n address && typeof address === \"object\" ? address.port : 0;\n this.httpServer = httpServer;\n });\n }\n\n async stop(): Promise<void> {\n return this.lifecycle.stop(async () => {\n this.broker.failExecution(this.binding);\n const httpServer = this.httpServer;\n this.httpServer = undefined;\n this.portValue = 0;\n if (httpServer) await closeHttpServer(httpServer);\n });\n }\n\n private async route(\n url: string,\n body: unknown,\n ): Promise<{ status: number; body: unknown }> {\n const path = new URL(url, \"http://127.0.0.1\").pathname.replace(/\\/+$/, \"\");\n if (path === \"/permission\") {\n const parsed = permissionBodySchema.safeParse(body);\n if (!parsed.success) {\n return { status: 400, body: { error: \"invalid permission request\" } };\n }\n const result = await this.requestPermission({\n tool_name: parsed.data.tool_name,\n input: parsed.data.input ?? {},\n });\n return {\n status: 200,\n body: {\n allowed: result.allowed,\n ...(result.message ? { reason: result.message } : {}),\n },\n };\n }\n if (path === \"/question\") {\n const parsed = questionBodySchema.safeParse(body);\n if (!parsed.success) {\n return { status: 400, body: { error: \"invalid question request\" } };\n }\n const answers = await this.askUser({ questions: parsed.data.questions });\n return { status: 200, body: { answers } };\n }\n return { status: 404, body: { error: \"unknown route\" } };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { a as RequestPlanBridge, i as RequestPermissionBridge, r as PermissionPromptBridge, t as AskUserBridge } from "../tools-
|
|
2
|
-
|
|
1
|
+
import { a as RequestPlanBridge, i as RequestPermissionBridge, r as PermissionPromptBridge, t as AskUserBridge } from "../tools-DeZkIW3h.js";
|
|
3
2
|
//#region src/interactions/mcp-server.d.ts
|
|
4
3
|
declare const DEFAULT_INTERACTION_MCP_SERVER_NAME = "tangle-interaction";
|
|
5
4
|
/** Build the full tool name that a runner uses for an MCP tool. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-server.d.ts","names":[],"sources":["../../src/interactions/mcp-server.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","names":[],"sources":["../../src/interactions/mcp-server.ts"],"mappings":";;cA6Ba;;iBAqMG,uBACd,oBACA;UAKe;EACf;EACA,qBAAqB;EACrB,aAAa;EACb,UAAU;EACV,oBAAoB;EACpB,cAAc;;;;;;;cA+BH;mBACM;mBACA;mBACA;mBACA;mBACA;mBACA;UACT;UACA;WACC;WACA;EAET,YAAY,QAAQ;MAiJhB;MAIA;EAIE,SAAS;EAiGT,QAAQ;UAYN;UAOA;UAcA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as closeHttpServer, r as waitForSettled, t as SerializedTransportLifecycle } from "../lifecycle-
|
|
1
|
+
import { n as closeHttpServer, r as waitForSettled, t as SerializedTransportLifecycle } from "../lifecycle-BljLcnY5.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
4
4
|
import { createServer } from "node:http";
|
|
@@ -8,7 +8,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
8
8
|
import { isJSONRPCErrorResponse, isJSONRPCRequest, isJSONRPCResultResponse } from "@modelcontextprotocol/sdk/types.js";
|
|
9
9
|
//#region src/interactions/mcp-server.ts
|
|
10
10
|
const DEFAULT_INTERACTION_MCP_SERVER_NAME = "tangle-interaction";
|
|
11
|
-
const MAX_MCP_BODY_BYTES =
|
|
11
|
+
const MAX_MCP_BODY_BYTES = 4194304;
|
|
12
12
|
const MAX_MCP_REPLAY_EVENTS = 1024;
|
|
13
13
|
var BoundedMcpEventStore = class {
|
|
14
14
|
events = [];
|
|
@@ -42,6 +42,7 @@ var BoundedMcpEventStore = class {
|
|
|
42
42
|
* response keeps this async context, so stale responses can be discarded.
|
|
43
43
|
*/
|
|
44
44
|
var RetrySafeStreamableHttpTransport = class extends StreamableHTTPServerTransport {
|
|
45
|
+
currentRequestSignal;
|
|
45
46
|
responseContext = new AsyncLocalStorage();
|
|
46
47
|
currentGeneration = /* @__PURE__ */ new Map();
|
|
47
48
|
activeGenerations = /* @__PURE__ */ new Set();
|