@agentick/client
Advanced tools
+7
-2
| { | ||
| "name": "@agentick/client", | ||
| "version": "0.0.1", | ||
| "version": "0.1.9", | ||
| "description": "Client SDK for Agentick - multiplexed sessions over SSE", | ||
@@ -30,3 +30,3 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@agentick/shared": "0.0.1" | ||
| "@agentick/shared": "0.1.9" | ||
| }, | ||
@@ -36,2 +36,7 @@ "devDependencies": { | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/agenticklabs/agentick.git", | ||
| "directory": "packages/client" | ||
| }, | ||
| "scripts": { | ||
@@ -38,0 +43,0 @@ "build": "tsc -p tsconfig.build.json", |
| /** | ||
| * HTTP/SSE Transport - Default transport implementation | ||
| * | ||
| * - Server → Client: Server-Sent Events (SSE) | ||
| * - Client → Server: HTTP POST | ||
| * | ||
| * @module @tentickle/client/transports/http | ||
| */ | ||
| import type { Transport, ClientConfig, ConnectionState, ConnectionMetadata, ChannelEvent } from "../types.js"; | ||
| /** | ||
| * Custom fetch function signature. | ||
| * Allows replacing the default fetch with axios, ky, or a custom wrapper. | ||
| */ | ||
| export type FetchFn = typeof fetch; | ||
| /** | ||
| * EventSource constructor signature. | ||
| * Allows replacing the default EventSource (e.g., for polyfills or custom implementations). | ||
| */ | ||
| export interface EventSourceConstructor { | ||
| new (url: string | URL, init?: { | ||
| withCredentials?: boolean; | ||
| }): EventSource; | ||
| } | ||
| /** | ||
| * HTTP transport configuration. | ||
| */ | ||
| export interface HTTPTransportConfig extends ClientConfig { | ||
| /** | ||
| * Custom headers to include in all requests. | ||
| * These are merged with defaults (Content-Type: application/json). | ||
| * User-provided headers take precedence over defaults. | ||
| * | ||
| * Use this for custom auth schemes, API keys, or any other headers. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Basic auth | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { Authorization: 'Basic ' + btoa('user:pass') }, | ||
| * }); | ||
| * | ||
| * // API key | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { 'X-API-Key': 'my-api-key' }, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| headers?: Record<string, string>; | ||
| /** | ||
| * Send cookies with requests and SSE (EventSource withCredentials). | ||
| * Defaults to false. | ||
| */ | ||
| withCredentials?: boolean; | ||
| /** | ||
| * Include auth token in SSE query params (EventSource lacks headers). | ||
| * Defaults to false to avoid token leakage in logs. | ||
| */ | ||
| authTokenInQuery?: boolean; | ||
| /** | ||
| * Custom fetch implementation. | ||
| * Use this to inject axios, ky, or a fetch wrapper with custom credentials/interceptors. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import ky from 'ky'; | ||
| * | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * fetch: ky as unknown as FetchFn, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| fetch?: FetchFn; | ||
| /** | ||
| * Custom EventSource constructor. | ||
| * Use this for polyfills (e.g., eventsource package in Node.js) or custom implementations. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import EventSource from 'eventsource'; | ||
| * | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * EventSource: EventSource, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| EventSource?: EventSourceConstructor; | ||
| } | ||
| /** | ||
| * HTTP/SSE Transport implementation. | ||
| * | ||
| * This is the default transport for Tentickle clients. | ||
| * Uses SSE for server-to-client streaming and HTTP POST for client-to-server messages. | ||
| * | ||
| * Supports custom fetch and EventSource implementations for: | ||
| * - Server-side (Node.js) usage with polyfills | ||
| * - Custom HTTP clients (axios, ky, got) | ||
| * - Credentials/interceptors | ||
| * - Testing with mocks | ||
| */ | ||
| export declare class HTTPTransport implements Transport { | ||
| readonly name = "http"; | ||
| private _state; | ||
| private sessionId?; | ||
| private metadata?; | ||
| private eventSource?; | ||
| private reconnectAttempts; | ||
| private reconnectTimer?; | ||
| private receiveHandlers; | ||
| private stateHandlers; | ||
| private readonly baseUrl; | ||
| private readonly eventsPath; | ||
| private readonly timeout; | ||
| private readonly reconnectDelay; | ||
| private readonly maxReconnectAttempts; | ||
| private readonly withCredentials; | ||
| private readonly authTokenInQuery; | ||
| /** Token for SSE query param auth (EventSource doesn't support headers) */ | ||
| private readonly token?; | ||
| /** Custom headers to merge with defaults for fetch requests */ | ||
| private readonly customHeaders; | ||
| /** Custom fetch implementation (defaults to global fetch) */ | ||
| private readonly fetchFn; | ||
| /** Custom EventSource constructor (defaults to global EventSource) */ | ||
| private readonly EventSourceCtor; | ||
| constructor(config: HTTPTransportConfig); | ||
| get state(): ConnectionState; | ||
| private setState; | ||
| /** | ||
| * Connect to the SSE stream. | ||
| */ | ||
| connect(sessionId: string, metadata?: ConnectionMetadata): Promise<void>; | ||
| private connectSSE; | ||
| private handleReconnect; | ||
| private closeEventSource; | ||
| /** | ||
| * Disconnect from the server. | ||
| */ | ||
| disconnect(): Promise<void>; | ||
| /** | ||
| * Send event via HTTP POST. | ||
| */ | ||
| send(event: ChannelEvent): Promise<void>; | ||
| /** | ||
| * Register receive handler. | ||
| */ | ||
| onReceive(handler: (event: ChannelEvent) => void): () => void; | ||
| /** | ||
| * Register state change handler. | ||
| */ | ||
| onStateChange(handler: (state: ConnectionState) => void): () => void; | ||
| private notifyReceive; | ||
| } | ||
| /** | ||
| * Create HTTP/SSE transport. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Default usage | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * }); | ||
| * | ||
| * // With custom headers (API key, Basic auth, etc.) | ||
| * const transportWithApiKey = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { 'X-API-Key': 'my-api-key' }, | ||
| * }); | ||
| * | ||
| * const transportWithBasicAuth = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { Authorization: 'Basic ' + btoa('user:pass') }, | ||
| * }); | ||
| * | ||
| * // With Bearer token (convenience - same as headers: { Authorization: 'Bearer ...' }) | ||
| * const transportWithToken = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * token: 'my-jwt-token', | ||
| * }); | ||
| * | ||
| * // With custom fetch (e.g., for credentials) | ||
| * const transportWithCredentials = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * fetch: (url, init) => fetch(url, { ...init, credentials: 'include' }), | ||
| * }); | ||
| * | ||
| * // With cookie-based auth for SSE + POST | ||
| * const transportWithCookies = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * withCredentials: true, | ||
| * }); | ||
| * | ||
| * // If you must pass auth token to SSE via query params | ||
| * const transportWithQueryToken = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * token: 'my-jwt-token', | ||
| * authTokenInQuery: true, | ||
| * }); | ||
| * | ||
| * // Node.js with polyfills | ||
| * import EventSource from 'eventsource'; | ||
| * | ||
| * const nodeTransport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * EventSource, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export declare function createHTTPTransport(config: HTTPTransportConfig): Transport; | ||
| //# sourceMappingURL=http.d.ts.map |
| {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"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"} |
| /** | ||
| * HTTP/SSE Transport - Default transport implementation | ||
| * | ||
| * - Server → Client: Server-Sent Events (SSE) | ||
| * - Client → Server: HTTP POST | ||
| * | ||
| * @module @tentickle/client/transports/http | ||
| */ | ||
| /** | ||
| * HTTP/SSE Transport implementation. | ||
| * | ||
| * This is the default transport for Tentickle clients. | ||
| * Uses SSE for server-to-client streaming and HTTP POST for client-to-server messages. | ||
| * | ||
| * Supports custom fetch and EventSource implementations for: | ||
| * - Server-side (Node.js) usage with polyfills | ||
| * - Custom HTTP clients (axios, ky, got) | ||
| * - Credentials/interceptors | ||
| * - Testing with mocks | ||
| */ | ||
| export class HTTPTransport { | ||
| name = "http"; | ||
| _state = "disconnected"; | ||
| sessionId; | ||
| metadata; | ||
| eventSource; | ||
| reconnectAttempts = 0; | ||
| reconnectTimer; | ||
| receiveHandlers = new Set(); | ||
| stateHandlers = new Set(); | ||
| baseUrl; | ||
| eventsPath; | ||
| timeout; | ||
| reconnectDelay; | ||
| maxReconnectAttempts; | ||
| withCredentials; | ||
| authTokenInQuery; | ||
| /** Token for SSE query param auth (EventSource doesn't support headers) */ | ||
| token; | ||
| /** Custom headers to merge with defaults for fetch requests */ | ||
| customHeaders; | ||
| /** Custom fetch implementation (defaults to global fetch) */ | ||
| fetchFn; | ||
| /** Custom EventSource constructor (defaults to global EventSource) */ | ||
| EventSourceCtor; | ||
| constructor(config) { | ||
| this.baseUrl = config.baseUrl.replace(/\/$/, ""); // Remove trailing slash | ||
| this.eventsPath = config.paths?.events ?? "/events"; | ||
| this.timeout = config.timeout ?? 30000; | ||
| this.reconnectDelay = config.reconnectDelay ?? 1000; | ||
| this.maxReconnectAttempts = config.maxReconnectAttempts ?? 10; | ||
| this.withCredentials = config.withCredentials ?? false; | ||
| this.authTokenInQuery = config.authTokenInQuery ?? false; | ||
| // Token is used for SSE query param (EventSource doesn't support custom headers) | ||
| this.token = config.token; | ||
| // Build custom headers for fetch requests - token adds Bearer auth if no custom Authorization | ||
| this.customHeaders = { ...config.headers }; | ||
| if (config.token && !this.customHeaders["Authorization"]) { | ||
| this.customHeaders["Authorization"] = `Bearer ${config.token}`; | ||
| } | ||
| // Use custom implementations or fall back to globals | ||
| this.fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis); | ||
| this.EventSourceCtor = config.EventSource ?? globalThis.EventSource; | ||
| } | ||
| get state() { | ||
| return this._state; | ||
| } | ||
| setState(state) { | ||
| if (this._state === state) | ||
| return; | ||
| this._state = state; | ||
| for (const handler of this.stateHandlers) { | ||
| try { | ||
| handler(state); | ||
| } | ||
| catch (error) { | ||
| console.error("Error in state handler:", error); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Connect to the SSE stream. | ||
| */ | ||
| async connect(sessionId, metadata) { | ||
| if (this._state === "connected") { | ||
| throw new Error("Already connected"); | ||
| } | ||
| this.sessionId = sessionId; | ||
| this.metadata = metadata; | ||
| this.reconnectAttempts = 0; | ||
| this.setState("connecting"); | ||
| try { | ||
| await this.connectSSE(); | ||
| this.setState("connected"); | ||
| } | ||
| catch (error) { | ||
| this.setState("error"); | ||
| throw error; | ||
| } | ||
| } | ||
| async connectSSE() { | ||
| if (!this.sessionId) { | ||
| throw new Error("Session ID required"); | ||
| } | ||
| // Close existing connection | ||
| this.closeEventSource(); | ||
| // Build SSE URL with query params | ||
| const url = new URL(`${this.baseUrl}${this.eventsPath}`); | ||
| url.searchParams.set("sessionId", this.sessionId); | ||
| if (this.metadata?.userId) { | ||
| url.searchParams.set("userId", String(this.metadata.userId)); | ||
| } | ||
| if (this.token && this.authTokenInQuery) { | ||
| url.searchParams.set("token", this.token); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| try { | ||
| this.eventSource = new this.EventSourceCtor(url.toString(), { | ||
| withCredentials: this.withCredentials, | ||
| }); | ||
| const onOpen = () => { | ||
| this.reconnectAttempts = 0; | ||
| resolve(); | ||
| }; | ||
| const onMessage = (event) => { | ||
| try { | ||
| const channelEvent = JSON.parse(event.data); | ||
| this.notifyReceive(channelEvent); | ||
| } | ||
| catch (error) { | ||
| console.error("Failed to parse SSE event:", error); | ||
| } | ||
| }; | ||
| const onError = () => { | ||
| if (this._state === "connecting") { | ||
| this.closeEventSource(); | ||
| reject(new Error("SSE connection failed")); | ||
| } | ||
| else { | ||
| this.handleReconnect(); | ||
| } | ||
| }; | ||
| this.eventSource.addEventListener("open", onOpen); | ||
| this.eventSource.addEventListener("message", onMessage); | ||
| this.eventSource.addEventListener("error", onError); | ||
| } | ||
| catch (error) { | ||
| reject(error); | ||
| } | ||
| }); | ||
| } | ||
| handleReconnect() { | ||
| if (this.reconnectAttempts >= this.maxReconnectAttempts) { | ||
| console.error("Max reconnection attempts reached"); | ||
| this.setState("error"); | ||
| return; | ||
| } | ||
| this.reconnectAttempts++; | ||
| const delay = this.reconnectDelay * Math.min(this.reconnectAttempts, 5); // Cap backoff | ||
| this.reconnectTimer = setTimeout(() => { | ||
| if (this.sessionId && this._state !== "disconnected") { | ||
| this.connectSSE() | ||
| .then(() => this.setState("connected")) | ||
| .catch((error) => { | ||
| console.error("Reconnection failed:", error); | ||
| }); | ||
| } | ||
| }, delay); | ||
| } | ||
| closeEventSource() { | ||
| if (this.eventSource) { | ||
| this.eventSource.close(); | ||
| this.eventSource = undefined; | ||
| } | ||
| } | ||
| /** | ||
| * Disconnect from the server. | ||
| */ | ||
| async disconnect() { | ||
| if (this.reconnectTimer) { | ||
| clearTimeout(this.reconnectTimer); | ||
| this.reconnectTimer = undefined; | ||
| } | ||
| this.closeEventSource(); | ||
| this.sessionId = undefined; | ||
| this.metadata = undefined; | ||
| this.reconnectAttempts = 0; | ||
| this.setState("disconnected"); | ||
| } | ||
| /** | ||
| * Send event via HTTP POST. | ||
| */ | ||
| async send(event) { | ||
| if (!this.sessionId) { | ||
| throw new Error("Not connected"); | ||
| } | ||
| // Merge default headers with custom headers (custom takes precedence) | ||
| const headers = { | ||
| "Content-Type": "application/json", | ||
| ...this.customHeaders, | ||
| }; | ||
| const response = await this.fetchFn(`${this.baseUrl}${this.eventsPath}`, { | ||
| method: "POST", | ||
| headers, | ||
| credentials: this.withCredentials ? "include" : "same-origin", | ||
| body: JSON.stringify({ | ||
| ...event, | ||
| metadata: { | ||
| ...event.metadata, | ||
| sessionId: this.sessionId, | ||
| userId: this.metadata?.userId, | ||
| timestamp: Date.now(), | ||
| }, | ||
| }), | ||
| signal: AbortSignal.timeout(this.timeout), | ||
| }); | ||
| if (!response.ok) { | ||
| const text = await response.text(); | ||
| throw new Error(`Failed to send event: ${response.status} ${text}`); | ||
| } | ||
| } | ||
| /** | ||
| * Register receive handler. | ||
| */ | ||
| onReceive(handler) { | ||
| this.receiveHandlers.add(handler); | ||
| return () => { | ||
| this.receiveHandlers.delete(handler); | ||
| }; | ||
| } | ||
| /** | ||
| * Register state change handler. | ||
| */ | ||
| onStateChange(handler) { | ||
| this.stateHandlers.add(handler); | ||
| return () => { | ||
| this.stateHandlers.delete(handler); | ||
| }; | ||
| } | ||
| notifyReceive(event) { | ||
| for (const handler of this.receiveHandlers) { | ||
| try { | ||
| handler(event); | ||
| } | ||
| catch (error) { | ||
| console.error("Error in receive handler:", error); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Create HTTP/SSE transport. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Default usage | ||
| * const transport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * }); | ||
| * | ||
| * // With custom headers (API key, Basic auth, etc.) | ||
| * const transportWithApiKey = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { 'X-API-Key': 'my-api-key' }, | ||
| * }); | ||
| * | ||
| * const transportWithBasicAuth = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * headers: { Authorization: 'Basic ' + btoa('user:pass') }, | ||
| * }); | ||
| * | ||
| * // With Bearer token (convenience - same as headers: { Authorization: 'Bearer ...' }) | ||
| * const transportWithToken = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * token: 'my-jwt-token', | ||
| * }); | ||
| * | ||
| * // With custom fetch (e.g., for credentials) | ||
| * const transportWithCredentials = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * fetch: (url, init) => fetch(url, { ...init, credentials: 'include' }), | ||
| * }); | ||
| * | ||
| * // With cookie-based auth for SSE + POST | ||
| * const transportWithCookies = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * withCredentials: true, | ||
| * }); | ||
| * | ||
| * // If you must pass auth token to SSE via query params | ||
| * const transportWithQueryToken = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * token: 'my-jwt-token', | ||
| * authTokenInQuery: true, | ||
| * }); | ||
| * | ||
| * // Node.js with polyfills | ||
| * import EventSource from 'eventsource'; | ||
| * | ||
| * const nodeTransport = createHTTPTransport({ | ||
| * baseUrl: 'https://api.example.com', | ||
| * EventSource, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export function createHTTPTransport(config) { | ||
| return new HTTPTransport(config); | ||
| } | ||
| //# sourceMappingURL=http.js.map |
| {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"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"} |
| /** | ||
| * Transport implementations for @tentickle/client | ||
| * | ||
| * Default: HTTP/SSE transport | ||
| * Alternative: WebSocket transport | ||
| * | ||
| * Both transports support custom implementations for: | ||
| * - Server-side (Node.js) usage with polyfills | ||
| * - Custom HTTP clients (axios, ky, got) | ||
| * - Testing with mocks | ||
| * | ||
| * @module @tentickle/client/transports | ||
| */ | ||
| export { HTTPTransport, createHTTPTransport, type HTTPTransportConfig, type FetchFn, type EventSourceConstructor, } from "./http.js"; | ||
| export { WebSocketTransport, createWebSocketTransport, type WebSocketConfig, type WebSocketConstructor, } from "./websocket.js"; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,OAAO,EACZ,KAAK,sBAAsB,GAC5B,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,oBAAoB,GAC1B,MAAM,gBAAgB,CAAC"} |
| /** | ||
| * Transport implementations for @tentickle/client | ||
| * | ||
| * Default: HTTP/SSE transport | ||
| * Alternative: WebSocket transport | ||
| * | ||
| * Both transports support custom implementations for: | ||
| * - Server-side (Node.js) usage with polyfills | ||
| * - Custom HTTP clients (axios, ky, got) | ||
| * - Testing with mocks | ||
| * | ||
| * @module @tentickle/client/transports | ||
| */ | ||
| // Default HTTP/SSE transport | ||
| export { HTTPTransport, createHTTPTransport, } from "./http.js"; | ||
| // Alternative WebSocket transport | ||
| export { WebSocketTransport, createWebSocketTransport, } from "./websocket.js"; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,6BAA6B;AAC7B,OAAO,EACL,aAAa,EACb,mBAAmB,GAIpB,MAAM,WAAW,CAAC;AAEnB,kCAAkC;AAClC,OAAO,EACL,kBAAkB,EAClB,wBAAwB,GAGzB,MAAM,gBAAgB,CAAC"} |
| /** | ||
| * WebSocket Transport - Alternative transport implementation | ||
| * | ||
| * Bidirectional communication over WebSocket. | ||
| * Use when you need lower latency or when SSE is not available. | ||
| * | ||
| * @module @tentickle/client/transports/websocket | ||
| */ | ||
| import type { Transport, ClientConfig, ConnectionState, ConnectionMetadata, ChannelEvent } from "../types.js"; | ||
| /** | ||
| * WebSocket constructor signature. | ||
| * Allows replacing the default WebSocket (e.g., with 'ws' package in Node.js). | ||
| */ | ||
| export interface WebSocketConstructor { | ||
| new (url: string | URL, protocols?: string | string[]): WebSocket; | ||
| } | ||
| /** | ||
| * WebSocket transport configuration. | ||
| */ | ||
| export interface WebSocketConfig extends ClientConfig { | ||
| /** WebSocket URL (ws:// or wss://) - overrides baseUrl */ | ||
| wsUrl?: string; | ||
| /** WebSocket protocols */ | ||
| protocols?: string[]; | ||
| /** | ||
| * Custom WebSocket constructor. | ||
| * Use this for Node.js (ws package) or custom implementations. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * import WebSocket from 'ws'; | ||
| * | ||
| * const transport = createWebSocketTransport({ | ||
| * baseUrl: 'wss://api.example.com', | ||
| * WebSocket: WebSocket as unknown as WebSocketConstructor, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| WebSocket?: WebSocketConstructor; | ||
| } | ||
| /** | ||
| * WebSocket Transport implementation. | ||
| * | ||
| * Use this when: | ||
| * - You need bidirectional real-time communication | ||
| * - SSE is blocked or unavailable | ||
| * - You want lower latency | ||
| */ | ||
| export declare class WebSocketTransport implements Transport { | ||
| readonly name = "websocket"; | ||
| private _state; | ||
| private sessionId?; | ||
| private metadata?; | ||
| private ws?; | ||
| private reconnectAttempts; | ||
| private reconnectTimer?; | ||
| private receiveHandlers; | ||
| private stateHandlers; | ||
| private readonly wsUrl; | ||
| private readonly protocols?; | ||
| private readonly token?; | ||
| private readonly reconnectDelay; | ||
| private readonly maxReconnectAttempts; | ||
| /** Custom WebSocket constructor (defaults to global WebSocket) */ | ||
| private readonly WebSocketCtor; | ||
| constructor(config: WebSocketConfig); | ||
| get state(): ConnectionState; | ||
| private setState; | ||
| /** | ||
| * Connect to WebSocket server. | ||
| */ | ||
| connect(sessionId: string, metadata?: ConnectionMetadata): Promise<void>; | ||
| private connectWebSocket; | ||
| private handleReconnect; | ||
| private closeWebSocket; | ||
| /** | ||
| * Disconnect from server. | ||
| */ | ||
| disconnect(): Promise<void>; | ||
| /** | ||
| * Send event via WebSocket. | ||
| */ | ||
| send(event: ChannelEvent): Promise<void>; | ||
| /** | ||
| * Register receive handler. | ||
| */ | ||
| onReceive(handler: (event: ChannelEvent) => void): () => void; | ||
| /** | ||
| * Register state change handler. | ||
| */ | ||
| onStateChange(handler: (state: ConnectionState) => void): () => void; | ||
| private notifyReceive; | ||
| } | ||
| /** | ||
| * Create WebSocket transport. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Browser usage | ||
| * const transport = createWebSocketTransport({ | ||
| * baseUrl: 'wss://api.example.com', | ||
| * }); | ||
| * | ||
| * // Node.js with ws package | ||
| * import WebSocket from 'ws'; | ||
| * | ||
| * const nodeTransport = createWebSocketTransport({ | ||
| * baseUrl: 'wss://api.example.com', | ||
| * WebSocket: WebSocket as unknown as WebSocketConstructor, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export declare function createWebSocketTransport(config: WebSocketConfig): Transport; | ||
| //# sourceMappingURL=websocket.d.ts.map |
| {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../src/transports/websocket.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,YAAY,EACb,MAAM,aAAa,CAAC;AAMrB;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;CACnE;AAED;;GAEG;AACH,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,EAAE,oBAAoB,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAClD,QAAQ,CAAC,IAAI,eAAe;IAE5B,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAC,CAAqB;IACtC,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAC,CAAgC;IACvD,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,aAAa,CAA+C;IAEpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAW;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAE9C,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuB;gBAEzC,MAAM,EAAE,eAAe;IAiBnC,IAAI,KAAK,IAAI,eAAe,CAE3B;IAED,OAAO,CAAC,QAAQ;IAYhB;;OAEG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAmBhE,gBAAgB;IAuD9B,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAajC;;OAEG;IACG,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAOpE,OAAO,CAAC,aAAa;CAStB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAE3E"} |
| /** | ||
| * WebSocket Transport - Alternative transport implementation | ||
| * | ||
| * Bidirectional communication over WebSocket. | ||
| * Use when you need lower latency or when SSE is not available. | ||
| * | ||
| * @module @tentickle/client/transports/websocket | ||
| */ | ||
| /** | ||
| * WebSocket Transport implementation. | ||
| * | ||
| * Use this when: | ||
| * - You need bidirectional real-time communication | ||
| * - SSE is blocked or unavailable | ||
| * - You want lower latency | ||
| */ | ||
| export class WebSocketTransport { | ||
| name = "websocket"; | ||
| _state = "disconnected"; | ||
| sessionId; | ||
| metadata; | ||
| ws; | ||
| reconnectAttempts = 0; | ||
| reconnectTimer; | ||
| receiveHandlers = new Set(); | ||
| stateHandlers = new Set(); | ||
| wsUrl; | ||
| protocols; | ||
| token; | ||
| reconnectDelay; | ||
| maxReconnectAttempts; | ||
| /** Custom WebSocket constructor (defaults to global WebSocket) */ | ||
| WebSocketCtor; | ||
| constructor(config) { | ||
| // Convert HTTP URL to WebSocket URL if needed | ||
| const baseUrl = config.wsUrl ?? config.baseUrl; | ||
| this.wsUrl = baseUrl | ||
| .replace(/^http:/, "ws:") | ||
| .replace(/^https:/, "wss:") | ||
| .replace(/\/$/, ""); | ||
| this.protocols = config.protocols; | ||
| this.token = config.token; | ||
| this.reconnectDelay = config.reconnectDelay ?? 1000; | ||
| this.maxReconnectAttempts = config.maxReconnectAttempts ?? 10; | ||
| // Use custom implementation or fall back to global | ||
| this.WebSocketCtor = config.WebSocket ?? globalThis.WebSocket; | ||
| } | ||
| get state() { | ||
| return this._state; | ||
| } | ||
| setState(state) { | ||
| if (this._state === state) | ||
| return; | ||
| this._state = state; | ||
| for (const handler of this.stateHandlers) { | ||
| try { | ||
| handler(state); | ||
| } | ||
| catch (error) { | ||
| console.error("Error in state handler:", error); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Connect to WebSocket server. | ||
| */ | ||
| async connect(sessionId, metadata) { | ||
| if (this._state === "connected") { | ||
| throw new Error("Already connected"); | ||
| } | ||
| this.sessionId = sessionId; | ||
| this.metadata = metadata; | ||
| this.reconnectAttempts = 0; | ||
| this.setState("connecting"); | ||
| try { | ||
| await this.connectWebSocket(); | ||
| this.setState("connected"); | ||
| } | ||
| catch (error) { | ||
| this.setState("error"); | ||
| throw error; | ||
| } | ||
| } | ||
| async connectWebSocket() { | ||
| if (!this.sessionId) { | ||
| throw new Error("Session ID required"); | ||
| } | ||
| // Close existing connection | ||
| this.closeWebSocket(); | ||
| // Build WebSocket URL with query params | ||
| const url = new URL(this.wsUrl); | ||
| url.searchParams.set("sessionId", this.sessionId); | ||
| if (this.metadata?.userId) { | ||
| url.searchParams.set("userId", String(this.metadata.userId)); | ||
| } | ||
| if (this.token) { | ||
| url.searchParams.set("token", this.token); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| try { | ||
| this.ws = new this.WebSocketCtor(url.toString(), this.protocols); | ||
| this.ws.onopen = () => { | ||
| this.reconnectAttempts = 0; | ||
| resolve(); | ||
| }; | ||
| this.ws.onmessage = (event) => { | ||
| try { | ||
| const channelEvent = JSON.parse(event.data); | ||
| this.notifyReceive(channelEvent); | ||
| } | ||
| catch (error) { | ||
| console.error("Failed to parse WebSocket message:", error); | ||
| } | ||
| }; | ||
| this.ws.onerror = () => { | ||
| if (this._state === "connecting") { | ||
| reject(new Error("WebSocket connection failed")); | ||
| } | ||
| }; | ||
| this.ws.onclose = () => { | ||
| if (this._state === "disconnected") { | ||
| // Intentional disconnect | ||
| return; | ||
| } | ||
| this.handleReconnect(); | ||
| }; | ||
| } | ||
| catch (error) { | ||
| reject(error); | ||
| } | ||
| }); | ||
| } | ||
| handleReconnect() { | ||
| if (this.reconnectAttempts >= this.maxReconnectAttempts) { | ||
| console.error("Max reconnection attempts reached"); | ||
| this.setState("error"); | ||
| return; | ||
| } | ||
| this.reconnectAttempts++; | ||
| const delay = this.reconnectDelay * Math.min(this.reconnectAttempts, 5); | ||
| this.reconnectTimer = setTimeout(() => { | ||
| if (this.sessionId && this._state !== "disconnected") { | ||
| this.connectWebSocket() | ||
| .then(() => this.setState("connected")) | ||
| .catch((error) => { | ||
| console.error("Reconnection failed:", error); | ||
| }); | ||
| } | ||
| }, delay); | ||
| } | ||
| closeWebSocket() { | ||
| if (this.ws) { | ||
| this.ws.close(); | ||
| this.ws = undefined; | ||
| } | ||
| } | ||
| /** | ||
| * Disconnect from server. | ||
| */ | ||
| async disconnect() { | ||
| if (this.reconnectTimer) { | ||
| clearTimeout(this.reconnectTimer); | ||
| this.reconnectTimer = undefined; | ||
| } | ||
| this.setState("disconnected"); // Set before close to prevent reconnect | ||
| this.closeWebSocket(); | ||
| this.sessionId = undefined; | ||
| this.metadata = undefined; | ||
| this.reconnectAttempts = 0; | ||
| } | ||
| /** | ||
| * Send event via WebSocket. | ||
| */ | ||
| async send(event) { | ||
| if (!this.ws || this._state !== "connected") { | ||
| throw new Error("Not connected"); | ||
| } | ||
| this.ws.send(JSON.stringify({ | ||
| ...event, | ||
| metadata: { | ||
| ...event.metadata, | ||
| sessionId: this.sessionId, | ||
| userId: this.metadata?.userId, | ||
| timestamp: Date.now(), | ||
| }, | ||
| })); | ||
| } | ||
| /** | ||
| * Register receive handler. | ||
| */ | ||
| onReceive(handler) { | ||
| this.receiveHandlers.add(handler); | ||
| return () => { | ||
| this.receiveHandlers.delete(handler); | ||
| }; | ||
| } | ||
| /** | ||
| * Register state change handler. | ||
| */ | ||
| onStateChange(handler) { | ||
| this.stateHandlers.add(handler); | ||
| return () => { | ||
| this.stateHandlers.delete(handler); | ||
| }; | ||
| } | ||
| notifyReceive(event) { | ||
| for (const handler of this.receiveHandlers) { | ||
| try { | ||
| handler(event); | ||
| } | ||
| catch (error) { | ||
| console.error("Error in receive handler:", error); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * Create WebSocket transport. | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * // Browser usage | ||
| * const transport = createWebSocketTransport({ | ||
| * baseUrl: 'wss://api.example.com', | ||
| * }); | ||
| * | ||
| * // Node.js with ws package | ||
| * import WebSocket from 'ws'; | ||
| * | ||
| * const nodeTransport = createWebSocketTransport({ | ||
| * baseUrl: 'wss://api.example.com', | ||
| * WebSocket: WebSocket as unknown as WebSocketConstructor, | ||
| * }); | ||
| * ``` | ||
| */ | ||
| export function createWebSocketTransport(config) { | ||
| return new WebSocketTransport(config); | ||
| } | ||
| //# sourceMappingURL=websocket.js.map |
| {"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../src/transports/websocket.ts"],"names":[],"mappings":"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"} |
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
0
-100%8
-33.33%202026
-18.49%27
-30.77%3074
-22.71%+ Added
- Removed
Updated