@debros/network-ts-sdk 0.1.4

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/core/http.ts","../src/auth/types.ts","../src/auth/client.ts","../src/db/qb.ts","../src/db/repository.ts","../src/db/client.ts","../src/core/ws.ts","../src/pubsub/client.ts","../src/network/client.ts","../src/index.ts"],"sourcesContent":["export class SDKError extends Error {\n public readonly httpStatus: number;\n public readonly code: string;\n public readonly details: Record<string, any>;\n\n constructor(\n message: string,\n httpStatus: number = 500,\n code: string = \"SDK_ERROR\",\n details: Record<string, any> = {}\n ) {\n super(message);\n this.name = \"SDKError\";\n this.httpStatus = httpStatus;\n this.code = code;\n this.details = details;\n }\n\n static fromResponse(\n status: number,\n body: any,\n message?: string\n ): SDKError {\n const errorMsg = message || body?.error || `HTTP ${status}`;\n const code = body?.code || `HTTP_${status}`;\n return new SDKError(errorMsg, status, code, body);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n httpStatus: this.httpStatus,\n code: this.code,\n details: this.details,\n };\n }\n}\n","import { SDKError } from \"../errors\";\n\nexport interface HttpClientConfig {\n baseURL: string;\n timeout?: number;\n maxRetries?: number;\n retryDelayMs?: number;\n fetch?: typeof fetch;\n}\n\nexport class HttpClient {\n private baseURL: string;\n private timeout: number;\n private maxRetries: number;\n private retryDelayMs: number;\n private fetch: typeof fetch;\n private apiKey?: string;\n private jwt?: string;\n\n constructor(config: HttpClientConfig) {\n this.baseURL = config.baseURL.replace(/\\/$/, \"\");\n this.timeout = config.timeout ?? 30000;\n this.maxRetries = config.maxRetries ?? 3;\n this.retryDelayMs = config.retryDelayMs ?? 1000;\n this.fetch = config.fetch ?? globalThis.fetch;\n }\n\n setApiKey(apiKey?: string) {\n this.apiKey = apiKey;\n this.jwt = undefined;\n }\n\n setJwt(jwt?: string) {\n this.jwt = jwt;\n this.apiKey = undefined;\n }\n\n private getAuthHeaders(): Record<string, string> {\n const headers: Record<string, string> = {};\n if (this.jwt) {\n headers[\"Authorization\"] = `Bearer ${this.jwt}`;\n } else if (this.apiKey) {\n headers[\"X-API-Key\"] = this.apiKey;\n }\n return headers;\n }\n\n private getAuthToken(): string | undefined {\n return this.jwt || this.apiKey;\n }\n\n async request<T = any>(\n method: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\",\n path: string,\n options: {\n body?: any;\n headers?: Record<string, string>;\n query?: Record<string, string | number | boolean>;\n } = {}\n ): Promise<T> {\n const url = new URL(this.baseURL + path);\n if (options.query) {\n Object.entries(options.query).forEach(([key, value]) => {\n url.searchParams.append(key, String(value));\n });\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...this.getAuthHeaders(),\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: AbortSignal.timeout(this.timeout),\n };\n\n if (options.body !== undefined) {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n return this.requestWithRetry(url.toString(), fetchOptions);\n }\n\n private async requestWithRetry(\n url: string,\n options: RequestInit,\n attempt: number = 0\n ): Promise<any> {\n try {\n const response = await this.fetch(url, options);\n\n if (!response.ok) {\n let body: any;\n try {\n body = await response.json();\n } catch {\n body = { error: response.statusText };\n }\n throw SDKError.fromResponse(response.status, body);\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n return response.json();\n }\n return response.text();\n } catch (error) {\n if (\n error instanceof SDKError &&\n attempt < this.maxRetries &&\n [408, 429, 500, 502, 503, 504].includes(error.httpStatus)\n ) {\n await new Promise((resolve) =>\n setTimeout(resolve, this.retryDelayMs * (attempt + 1))\n );\n return this.requestWithRetry(url, options, attempt + 1);\n }\n throw error;\n }\n }\n\n async get<T = any>(\n path: string,\n options?: Omit<Parameters<typeof this.request>[2], \"body\">\n ): Promise<T> {\n return this.request<T>(\"GET\", path, options);\n }\n\n async post<T = any>(\n path: string,\n body?: any,\n options?: Omit<Parameters<typeof this.request>[2], \"body\">\n ): Promise<T> {\n return this.request<T>(\"POST\", path, { ...options, body });\n }\n\n async put<T = any>(\n path: string,\n body?: any,\n options?: Omit<Parameters<typeof this.request>[2], \"body\">\n ): Promise<T> {\n return this.request<T>(\"PUT\", path, { ...options, body });\n }\n\n async delete<T = any>(\n path: string,\n options?: Omit<Parameters<typeof this.request>[2], \"body\">\n ): Promise<T> {\n return this.request<T>(\"DELETE\", path, options);\n }\n\n getToken(): string | undefined {\n return this.getAuthToken();\n }\n}\n","export interface AuthConfig {\n apiKey?: string;\n jwt?: string;\n}\n\nexport interface WhoAmI {\n address?: string;\n namespace?: string;\n authenticated: boolean;\n}\n\nexport interface StorageAdapter {\n get(key: string): Promise<string | null>;\n set(key: string, value: string): Promise<void>;\n clear(): Promise<void>;\n}\n\nexport class MemoryStorage implements StorageAdapter {\n private storage: Map<string, string> = new Map();\n\n async get(key: string): Promise<string | null> {\n return this.storage.get(key) ?? null;\n }\n\n async set(key: string, value: string): Promise<void> {\n this.storage.set(key, value);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n}\n\nexport class LocalStorageAdapter implements StorageAdapter {\n private prefix = \"@network/sdk:\";\n\n async get(key: string): Promise<string | null> {\n if (typeof globalThis !== \"undefined\" && globalThis.localStorage) {\n return globalThis.localStorage.getItem(this.prefix + key);\n }\n return null;\n }\n\n async set(key: string, value: string): Promise<void> {\n if (typeof globalThis !== \"undefined\" && globalThis.localStorage) {\n globalThis.localStorage.setItem(this.prefix + key, value);\n }\n }\n\n async clear(): Promise<void> {\n if (typeof globalThis !== \"undefined\" && globalThis.localStorage) {\n const keysToDelete: string[] = [];\n for (let i = 0; i < globalThis.localStorage.length; i++) {\n const key = globalThis.localStorage.key(i);\n if (key?.startsWith(this.prefix)) {\n keysToDelete.push(key);\n }\n }\n keysToDelete.forEach((key) => globalThis.localStorage.removeItem(key));\n }\n }\n}\n","import { HttpClient } from \"../core/http\";\nimport {\n AuthConfig,\n WhoAmI,\n StorageAdapter,\n MemoryStorage,\n} from \"./types\";\n\nexport class AuthClient {\n private httpClient: HttpClient;\n private storage: StorageAdapter;\n private currentApiKey?: string;\n private currentJwt?: string;\n\n constructor(config: {\n httpClient: HttpClient;\n storage?: StorageAdapter;\n apiKey?: string;\n jwt?: string;\n }) {\n this.httpClient = config.httpClient;\n this.storage = config.storage ?? new MemoryStorage();\n this.currentApiKey = config.apiKey;\n this.currentJwt = config.jwt;\n\n if (this.currentApiKey) {\n this.httpClient.setApiKey(this.currentApiKey);\n }\n if (this.currentJwt) {\n this.httpClient.setJwt(this.currentJwt);\n }\n }\n\n setApiKey(apiKey: string) {\n this.currentApiKey = apiKey;\n this.currentJwt = undefined;\n this.httpClient.setApiKey(apiKey);\n this.storage.set(\"apiKey\", apiKey);\n }\n\n setJwt(jwt: string) {\n this.currentJwt = jwt;\n this.currentApiKey = undefined;\n this.httpClient.setJwt(jwt);\n this.storage.set(\"jwt\", jwt);\n }\n\n getToken(): string | undefined {\n return this.httpClient.getToken();\n }\n\n async whoami(): Promise<WhoAmI> {\n try {\n const response = await this.httpClient.get<WhoAmI>(\"/v1/auth/whoami\");\n return response;\n } catch {\n return { authenticated: false };\n }\n }\n\n async refresh(): Promise<string> {\n const response = await this.httpClient.post<{ token: string }>(\n \"/v1/auth/refresh\"\n );\n const token = response.token;\n this.setJwt(token);\n return token;\n }\n\n async logout(): Promise<void> {\n // Only attempt server-side logout if using JWT\n // API keys don't support server-side logout with all=true\n if (this.currentJwt) {\n try {\n await this.httpClient.post(\"/v1/auth/logout\", { all: true });\n } catch (error) {\n // Log warning but don't fail - local cleanup is more important\n console.warn('Server-side logout failed, continuing with local cleanup:', error);\n }\n }\n \n // Always clear local state\n this.currentApiKey = undefined;\n this.currentJwt = undefined;\n this.httpClient.setApiKey(undefined);\n this.httpClient.setJwt(undefined);\n await this.storage.clear();\n }\n\n async clear(): Promise<void> {\n this.currentApiKey = undefined;\n this.currentJwt = undefined;\n this.httpClient.setApiKey(undefined);\n this.httpClient.setJwt(undefined);\n await this.storage.clear();\n }\n}\n","import { HttpClient } from \"../core/http\";\nimport { SelectOptions, QueryResponse } from \"./types\";\n\nexport class QueryBuilder {\n private httpClient: HttpClient;\n private table: string;\n private options: SelectOptions = {};\n\n constructor(httpClient: HttpClient, table: string) {\n this.httpClient = httpClient;\n this.table = table;\n }\n\n select(...columns: string[]): this {\n this.options.select = columns;\n return this;\n }\n\n innerJoin(table: string, on: string): this {\n if (!this.options.joins) this.options.joins = [];\n this.options.joins.push({ kind: \"INNER\", table, on });\n return this;\n }\n\n leftJoin(table: string, on: string): this {\n if (!this.options.joins) this.options.joins = [];\n this.options.joins.push({ kind: \"LEFT\", table, on });\n return this;\n }\n\n rightJoin(table: string, on: string): this {\n if (!this.options.joins) this.options.joins = [];\n this.options.joins.push({ kind: \"RIGHT\", table, on });\n return this;\n }\n\n where(expr: string, args?: any[]): this {\n if (!this.options.where) this.options.where = [];\n this.options.where.push({ conj: \"AND\", expr, args });\n return this;\n }\n\n andWhere(expr: string, args?: any[]): this {\n return this.where(expr, args);\n }\n\n orWhere(expr: string, args?: any[]): this {\n if (!this.options.where) this.options.where = [];\n this.options.where.push({ conj: \"OR\", expr, args });\n return this;\n }\n\n groupBy(...columns: string[]): this {\n this.options.group_by = columns;\n return this;\n }\n\n orderBy(...columns: string[]): this {\n this.options.order_by = columns;\n return this;\n }\n\n limit(n: number): this {\n this.options.limit = n;\n return this;\n }\n\n offset(n: number): this {\n this.options.offset = n;\n return this;\n }\n\n async getMany<T = any>(ctx?: any): Promise<T[]> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/select\",\n {\n table: this.table,\n ...this.options,\n }\n );\n return response.items || [];\n }\n\n async getOne<T = any>(ctx?: any): Promise<T | null> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/select\",\n {\n table: this.table,\n ...this.options,\n one: true,\n limit: 1,\n }\n );\n const items = response.items || [];\n return items.length > 0 ? items[0] : null;\n }\n\n async count(): Promise<number> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/select\",\n {\n table: this.table,\n select: [\"COUNT(*) AS count\"],\n where: this.options.where,\n one: true,\n }\n );\n const items = response.items || [];\n return items.length > 0 ? items[0].count : 0;\n }\n}\n","import { HttpClient } from \"../core/http\";\nimport { QueryBuilder } from \"./qb\";\nimport { QueryResponse, FindOptions } from \"./types\";\nimport { SDKError } from \"../errors\";\n\nexport class Repository<T extends Record<string, any>> {\n private httpClient: HttpClient;\n private tableName: string;\n private primaryKey: string;\n\n constructor(httpClient: HttpClient, tableName: string, primaryKey = \"id\") {\n this.httpClient = httpClient;\n this.tableName = tableName;\n this.primaryKey = primaryKey;\n }\n\n createQueryBuilder(): QueryBuilder {\n return new QueryBuilder(this.httpClient, this.tableName);\n }\n\n async find(\n criteria: Record<string, any> = {},\n options: FindOptions = {}\n ): Promise<T[]> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/find\",\n {\n table: this.tableName,\n criteria,\n options,\n }\n );\n return response.items || [];\n }\n\n async findOne(criteria: Record<string, any>): Promise<T | null> {\n try {\n const response = await this.httpClient.post<T | null>(\n \"/v1/rqlite/find-one\",\n {\n table: this.tableName,\n criteria,\n }\n );\n return response;\n } catch (error) {\n // Return null if not found instead of throwing\n if (error instanceof SDKError && error.httpStatus === 404) {\n return null;\n }\n throw error;\n }\n }\n\n async save(entity: T): Promise<T> {\n const pkValue = entity[this.primaryKey];\n\n if (!pkValue) {\n // INSERT\n const response = await this.httpClient.post<{\n rows_affected: number;\n last_insert_id: number;\n }>(\"/v1/rqlite/exec\", {\n sql: this.buildInsertSql(entity),\n args: this.buildInsertArgs(entity),\n });\n\n if (response.last_insert_id) {\n (entity as any)[this.primaryKey] = response.last_insert_id;\n }\n return entity;\n } else {\n // UPDATE\n await this.httpClient.post(\"/v1/rqlite/exec\", {\n sql: this.buildUpdateSql(entity),\n args: this.buildUpdateArgs(entity),\n });\n return entity;\n }\n }\n\n async remove(entity: T | Record<string, any>): Promise<void> {\n const pkValue = entity[this.primaryKey];\n if (!pkValue) {\n throw new SDKError(\n `Primary key \"${this.primaryKey}\" is required for remove`,\n 400,\n \"MISSING_PK\"\n );\n }\n\n await this.httpClient.post(\"/v1/rqlite/exec\", {\n sql: `DELETE FROM ${this.tableName} WHERE ${this.primaryKey} = ?`,\n args: [pkValue],\n });\n }\n\n private buildInsertSql(entity: T): string {\n const columns = Object.keys(entity).filter((k) => entity[k] !== undefined);\n const placeholders = columns.map(() => \"?\").join(\", \");\n return `INSERT INTO ${this.tableName} (${columns.join(\", \")}) VALUES (${placeholders})`;\n }\n\n private buildInsertArgs(entity: T): any[] {\n return Object.entries(entity)\n .filter(([, v]) => v !== undefined)\n .map(([, v]) => v);\n }\n\n private buildUpdateSql(entity: T): string {\n const columns = Object.keys(entity)\n .filter((k) => entity[k] !== undefined && k !== this.primaryKey)\n .map((k) => `${k} = ?`);\n return `UPDATE ${this.tableName} SET ${columns.join(\", \")} WHERE ${this.primaryKey} = ?`;\n }\n\n private buildUpdateArgs(entity: T): any[] {\n const args = Object.entries(entity)\n .filter(([k, v]) => v !== undefined && k !== this.primaryKey)\n .map(([, v]) => v);\n args.push(entity[this.primaryKey]);\n return args;\n }\n}\n","import { HttpClient } from \"../core/http\";\nimport { QueryBuilder } from \"./qb\";\nimport { Repository } from \"./repository\";\nimport {\n QueryResponse,\n TransactionOp,\n TransactionRequest,\n Entity,\n FindOptions,\n} from \"./types\";\n\nexport class DBClient {\n private httpClient: HttpClient;\n\n constructor(httpClient: HttpClient) {\n this.httpClient = httpClient;\n }\n\n /**\n * Execute a write/DDL SQL statement.\n */\n async exec(\n sql: string,\n args: any[] = []\n ): Promise<{ rows_affected: number; last_insert_id?: number }> {\n return this.httpClient.post(\"/v1/rqlite/exec\", { sql, args });\n }\n\n /**\n * Execute a SELECT query.\n */\n async query<T = any>(sql: string, args: any[] = []): Promise<T[]> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/query\",\n { sql, args }\n );\n return response.items || [];\n }\n\n /**\n * Find rows with map-based criteria.\n */\n async find<T = any>(\n table: string,\n criteria: Record<string, any> = {},\n options: FindOptions = {}\n ): Promise<T[]> {\n const response = await this.httpClient.post<QueryResponse>(\n \"/v1/rqlite/find\",\n {\n table,\n criteria,\n options,\n }\n );\n return response.items || [];\n }\n\n /**\n * Find a single row with map-based criteria.\n */\n async findOne<T = any>(\n table: string,\n criteria: Record<string, any>\n ): Promise<T | null> {\n return this.httpClient.post<T | null>(\"/v1/rqlite/find-one\", {\n table,\n criteria,\n });\n }\n\n /**\n * Create a fluent QueryBuilder for complex SELECT queries.\n */\n createQueryBuilder(table: string): QueryBuilder {\n return new QueryBuilder(this.httpClient, table);\n }\n\n /**\n * Create a Repository for entity-based operations.\n */\n repository<T extends Record<string, any>>(\n tableName: string,\n primaryKey = \"id\"\n ): Repository<T> {\n return new Repository(this.httpClient, tableName, primaryKey);\n }\n\n /**\n * Execute multiple operations atomically.\n */\n async transaction(\n ops: TransactionOp[],\n returnResults = true\n ): Promise<any[]> {\n const response = await this.httpClient.post<{ results?: any[] }>(\n \"/v1/rqlite/transaction\",\n {\n ops,\n return_results: returnResults,\n }\n );\n return response.results || [];\n }\n\n /**\n * Create a table from DDL SQL.\n */\n async createTable(schema: string): Promise<void> {\n await this.httpClient.post(\"/v1/rqlite/create-table\", { schema });\n }\n\n /**\n * Drop a table.\n */\n async dropTable(table: string): Promise<void> {\n await this.httpClient.post(\"/v1/rqlite/drop-table\", { table });\n }\n\n /**\n * Get current database schema.\n */\n async getSchema(): Promise<any> {\n return this.httpClient.get(\"/v1/rqlite/schema\");\n }\n}\n","import WebSocket from \"isomorphic-ws\";\nimport { SDKError } from \"../errors\";\n\nexport interface WSClientConfig {\n wsURL: string;\n timeout?: number;\n maxReconnectAttempts?: number;\n reconnectDelayMs?: number;\n heartbeatIntervalMs?: number;\n authMode?: \"header\" | \"query\";\n authToken?: string;\n WebSocket?: typeof WebSocket;\n}\n\nexport type WSMessageHandler = (data: string) => void;\nexport type WSErrorHandler = (error: Error) => void;\nexport type WSCloseHandler = () => void;\n\nexport class WSClient {\n private url: string;\n private timeout: number;\n private maxReconnectAttempts: number;\n private reconnectDelayMs: number;\n private heartbeatIntervalMs: number;\n private authMode: \"header\" | \"query\";\n private authToken?: string;\n private WebSocketClass: typeof WebSocket;\n\n private ws?: WebSocket;\n private reconnectAttempts = 0;\n private heartbeatInterval?: NodeJS.Timeout;\n private messageHandlers: Set<WSMessageHandler> = new Set();\n private errorHandlers: Set<WSErrorHandler> = new Set();\n private closeHandlers: Set<WSCloseHandler> = new Set();\n private isManuallyClosed = false;\n\n constructor(config: WSClientConfig) {\n this.url = config.wsURL;\n this.timeout = config.timeout ?? 30000;\n this.maxReconnectAttempts = config.maxReconnectAttempts ?? 5;\n this.reconnectDelayMs = config.reconnectDelayMs ?? 1000;\n this.heartbeatIntervalMs = config.heartbeatIntervalMs ?? 30000;\n this.authMode = config.authMode ?? \"header\";\n this.authToken = config.authToken;\n this.WebSocketClass = config.WebSocket ?? WebSocket;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const wsUrl = this.buildWSUrl();\n this.ws = new this.WebSocketClass(wsUrl);\n\n // Note: Custom headers via ws library in Node.js are not sent with WebSocket upgrade requests\n // so we rely on query parameters for authentication\n\n const timeout = setTimeout(() => {\n this.ws?.close();\n reject(new SDKError(\"WebSocket connection timeout\", 408, \"WS_TIMEOUT\"));\n }, this.timeout);\n\n this.ws.addEventListener(\"open\", () => {\n clearTimeout(timeout);\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n resolve();\n });\n\n this.ws.addEventListener(\"message\", (event: Event) => {\n const msgEvent = event as MessageEvent;\n this.messageHandlers.forEach((handler) => handler(msgEvent.data));\n });\n\n this.ws.addEventListener(\"error\", (event: Event) => {\n clearTimeout(timeout);\n const error = new SDKError(\n \"WebSocket error\",\n 500,\n \"WS_ERROR\",\n event\n );\n this.errorHandlers.forEach((handler) => handler(error));\n });\n\n this.ws.addEventListener(\"close\", () => {\n clearTimeout(timeout);\n this.stopHeartbeat();\n if (!this.isManuallyClosed) {\n this.attemptReconnect();\n } else {\n this.closeHandlers.forEach((handler) => handler());\n }\n });\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private buildWSUrl(): string {\n let url = this.url;\n \n // Always append auth token as query parameter for compatibility\n // Works in both Node.js and browser environments\n if (this.authToken) {\n const separator = url.includes(\"?\") ? \"&\" : \"?\";\n const paramName = this.authToken.startsWith(\"ak_\") ? \"api_key\" : \"token\";\n url += `${separator}${paramName}=${encodeURIComponent(this.authToken)}`;\n }\n \n return url;\n }\n\n private startHeartbeat() {\n this.heartbeatInterval = setInterval(() => {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify({ type: \"ping\" }));\n }\n }, this.heartbeatIntervalMs);\n }\n\n private stopHeartbeat() {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = undefined;\n }\n }\n\n private attemptReconnect() {\n if (this.reconnectAttempts < this.maxReconnectAttempts) {\n this.reconnectAttempts++;\n const delayMs = this.reconnectDelayMs * this.reconnectAttempts;\n setTimeout(() => {\n this.connect().catch((error) => {\n this.errorHandlers.forEach((handler) => handler(error));\n });\n }, delayMs);\n } else {\n this.closeHandlers.forEach((handler) => handler());\n }\n }\n\n onMessage(handler: WSMessageHandler) {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n onError(handler: WSErrorHandler) {\n this.errorHandlers.add(handler);\n return () => this.errorHandlers.delete(handler);\n }\n\n onClose(handler: WSCloseHandler) {\n this.closeHandlers.add(handler);\n return () => this.closeHandlers.delete(handler);\n }\n\n send(data: string) {\n if (this.ws?.readyState !== WebSocket.OPEN) {\n throw new SDKError(\n \"WebSocket is not connected\",\n 500,\n \"WS_NOT_CONNECTED\"\n );\n }\n this.ws.send(data);\n }\n\n close() {\n this.isManuallyClosed = true;\n this.stopHeartbeat();\n this.ws?.close();\n }\n\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n setAuthToken(token?: string) {\n this.authToken = token;\n }\n}\n","import { HttpClient } from \"../core/http\";\nimport { WSClient, WSClientConfig } from \"../core/ws\";\n\nexport interface Message {\n data: string;\n topic: string;\n timestamp?: number;\n}\n\nexport type MessageHandler = (message: Message) => void;\nexport type ErrorHandler = (error: Error) => void;\nexport type CloseHandler = () => void;\n\nexport class PubSubClient {\n private httpClient: HttpClient;\n private wsConfig: Partial<WSClientConfig>;\n\n constructor(httpClient: HttpClient, wsConfig: Partial<WSClientConfig> = {}) {\n this.httpClient = httpClient;\n this.wsConfig = wsConfig;\n }\n\n /**\n * Publish a message to a topic.\n */\n async publish(topic: string, data: string | Uint8Array): Promise<void> {\n const dataBase64 =\n typeof data === \"string\" ? Buffer.from(data).toString(\"base64\") : Buffer.from(data).toString(\"base64\");\n\n await this.httpClient.post(\"/v1/pubsub/publish\", {\n topic,\n data_base64: dataBase64,\n });\n }\n\n /**\n * List active topics in the current namespace.\n */\n async topics(): Promise<string[]> {\n const response = await this.httpClient.get<{ topics: string[] }>(\n \"/v1/pubsub/topics\"\n );\n return response.topics || [];\n }\n\n /**\n * Subscribe to a topic via WebSocket.\n * Returns a subscription object with event handlers.\n */\n async subscribe(\n topic: string,\n handlers: {\n onMessage?: MessageHandler;\n onError?: ErrorHandler;\n onClose?: CloseHandler;\n } = {}\n ): Promise<Subscription> {\n const wsUrl = new URL(this.wsConfig.wsURL || \"ws://localhost:6001\");\n wsUrl.pathname = \"/v1/pubsub/ws\";\n wsUrl.searchParams.set(\"topic\", topic);\n\n const wsClient = new WSClient({\n ...this.wsConfig,\n wsURL: wsUrl.toString(),\n authToken: this.httpClient.getToken(),\n });\n\n const subscription = new Subscription(wsClient, topic);\n\n if (handlers.onMessage) {\n subscription.onMessage(handlers.onMessage);\n }\n if (handlers.onError) {\n subscription.onError(handlers.onError);\n }\n if (handlers.onClose) {\n subscription.onClose(handlers.onClose);\n }\n\n await wsClient.connect();\n return subscription;\n }\n}\n\nexport class Subscription {\n private wsClient: WSClient;\n private topic: string;\n private messageHandlers: Set<MessageHandler> = new Set();\n private errorHandlers: Set<ErrorHandler> = new Set();\n private closeHandlers: Set<CloseHandler> = new Set();\n\n constructor(wsClient: WSClient, topic: string) {\n this.wsClient = wsClient;\n this.topic = topic;\n\n this.wsClient.onMessage((data) => {\n try {\n const message: Message = {\n topic: this.topic,\n data: data,\n timestamp: Date.now(),\n };\n this.messageHandlers.forEach((handler) => handler(message));\n } catch (error) {\n this.errorHandlers.forEach((handler) =>\n handler(error instanceof Error ? error : new Error(String(error)))\n );\n }\n });\n\n this.wsClient.onError((error) => {\n this.errorHandlers.forEach((handler) => handler(error));\n });\n\n this.wsClient.onClose(() => {\n this.closeHandlers.forEach((handler) => handler());\n });\n }\n\n onMessage(handler: MessageHandler) {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n onError(handler: ErrorHandler) {\n this.errorHandlers.add(handler);\n return () => this.errorHandlers.delete(handler);\n }\n\n onClose(handler: CloseHandler) {\n this.closeHandlers.add(handler);\n return () => this.closeHandlers.delete(handler);\n }\n\n close() {\n this.wsClient.close();\n }\n\n isConnected(): boolean {\n return this.wsClient.isConnected();\n }\n}\n","import { HttpClient } from \"../core/http\";\n\nexport interface PeerInfo {\n id: string;\n addresses: string[];\n lastSeen?: string;\n}\n\nexport interface NetworkStatus {\n healthy: boolean;\n peers: number;\n uptime?: number;\n}\n\nexport class NetworkClient {\n private httpClient: HttpClient;\n\n constructor(httpClient: HttpClient) {\n this.httpClient = httpClient;\n }\n\n /**\n * Check gateway health.\n */\n async health(): Promise<boolean> {\n try {\n await this.httpClient.get(\"/v1/health\");\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get network status.\n */\n async status(): Promise<NetworkStatus> {\n const response = await this.httpClient.get<NetworkStatus>(\"/v1/status\");\n return response;\n }\n\n /**\n * Get connected peers.\n */\n async peers(): Promise<PeerInfo[]> {\n const response = await this.httpClient.get<{ peers: PeerInfo[] }>(\n \"/v1/network/peers\"\n );\n return response.peers || [];\n }\n\n /**\n * Connect to a peer.\n */\n async connect(peerAddr: string): Promise<void> {\n await this.httpClient.post(\"/v1/network/connect\", { peer_addr: peerAddr });\n }\n\n /**\n * Disconnect from a peer.\n */\n async disconnect(peerId: string): Promise<void> {\n await this.httpClient.post(\"/v1/network/disconnect\", { peer_id: peerId });\n }\n}\n","import { HttpClient, HttpClientConfig } from \"./core/http\";\nimport { AuthClient } from \"./auth/client\";\nimport { DBClient } from \"./db/client\";\nimport { PubSubClient } from \"./pubsub/client\";\nimport { NetworkClient } from \"./network/client\";\nimport { WSClientConfig } from \"./core/ws\";\nimport { StorageAdapter, MemoryStorage, LocalStorageAdapter } from \"./auth/types\";\n\nexport interface ClientConfig extends Omit<HttpClientConfig, \"fetch\"> {\n apiKey?: string;\n jwt?: string;\n storage?: StorageAdapter;\n wsConfig?: Partial<WSClientConfig>;\n fetch?: typeof fetch;\n}\n\nexport interface Client {\n auth: AuthClient;\n db: DBClient;\n pubsub: PubSubClient;\n network: NetworkClient;\n}\n\nexport function createClient(config: ClientConfig): Client {\n const httpClient = new HttpClient({\n baseURL: config.baseURL,\n timeout: config.timeout,\n maxRetries: config.maxRetries,\n retryDelayMs: config.retryDelayMs,\n fetch: config.fetch,\n });\n\n const auth = new AuthClient({\n httpClient,\n storage: config.storage,\n apiKey: config.apiKey,\n jwt: config.jwt,\n });\n\n // Derive WebSocket URL from baseURL if not explicitly provided\n const wsURL = config.wsConfig?.wsURL ?? \n config.baseURL.replace(/^http/, 'ws').replace(/\\/$/, '');\n\n const db = new DBClient(httpClient);\n const pubsub = new PubSubClient(httpClient, {\n ...config.wsConfig,\n wsURL,\n });\n const network = new NetworkClient(httpClient);\n\n return {\n auth,\n db,\n pubsub,\n network,\n };\n}\n\n// Re-exports\nexport { HttpClient } from \"./core/http\";\nexport { WSClient } from \"./core/ws\";\nexport { AuthClient } from \"./auth/client\";\nexport { DBClient } from \"./db/client\";\nexport { QueryBuilder } from \"./db/qb\";\nexport { Repository } from \"./db/repository\";\nexport { PubSubClient, Subscription } from \"./pubsub/client\";\nexport { NetworkClient } from \"./network/client\";\nexport { SDKError } from \"./errors\";\nexport { MemoryStorage, LocalStorageAdapter } from \"./auth/types\";\nexport type {\n StorageAdapter,\n AuthConfig,\n WhoAmI,\n} from \"./auth/types\";\nexport type * from \"./db/types\";\nexport type {\n Message,\n MessageHandler,\n ErrorHandler,\n CloseHandler,\n} from \"./pubsub/client\";\nexport type { PeerInfo, NetworkStatus } from \"./network/client\";\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@debros/network-ts-sdk",
3
+ "version": "0.1.4",
4
+ "description": "TypeScript SDK for DeBros Network Gateway",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "license": "MIT",
9
+ "author": "DeBrosOfficial",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/DeBrosOfficial/network-ts-sdk/tree/v0.0.1"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "src"
23
+ ],
24
+ "scripts": {
25
+ "build": "tsup",
26
+ "dev": "tsup --watch",
27
+ "typecheck": "tsc --noEmit",
28
+ "lint": "eslint src tests",
29
+ "test": "vitest",
30
+ "test:e2e": "vitest run tests/e2e",
31
+ "release:npm": "npm publish --access public --registry=https://registry.npmjs.org/",
32
+ "release:gh": "npm publish --registry=https://npm.pkg.github.com"
33
+ },
34
+ "dependencies": {
35
+ "isomorphic-ws": "^5.0.0"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.0.0",
39
+ "typescript": "^5.3.0",
40
+ "tsup": "^8.0.0",
41
+ "vitest": "^1.0.0",
42
+ "eslint": "^8.0.0",
43
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
44
+ "@typescript-eslint/parser": "^6.0.0"
45
+ },
46
+ "publishConfig": {
47
+ "registry": "https://registry.npmjs.org/",
48
+ "access": "public"
49
+ }
50
+ }
@@ -0,0 +1,97 @@
1
+ import { HttpClient } from "../core/http";
2
+ import {
3
+ AuthConfig,
4
+ WhoAmI,
5
+ StorageAdapter,
6
+ MemoryStorage,
7
+ } from "./types";
8
+
9
+ export class AuthClient {
10
+ private httpClient: HttpClient;
11
+ private storage: StorageAdapter;
12
+ private currentApiKey?: string;
13
+ private currentJwt?: string;
14
+
15
+ constructor(config: {
16
+ httpClient: HttpClient;
17
+ storage?: StorageAdapter;
18
+ apiKey?: string;
19
+ jwt?: string;
20
+ }) {
21
+ this.httpClient = config.httpClient;
22
+ this.storage = config.storage ?? new MemoryStorage();
23
+ this.currentApiKey = config.apiKey;
24
+ this.currentJwt = config.jwt;
25
+
26
+ if (this.currentApiKey) {
27
+ this.httpClient.setApiKey(this.currentApiKey);
28
+ }
29
+ if (this.currentJwt) {
30
+ this.httpClient.setJwt(this.currentJwt);
31
+ }
32
+ }
33
+
34
+ setApiKey(apiKey: string) {
35
+ this.currentApiKey = apiKey;
36
+ this.currentJwt = undefined;
37
+ this.httpClient.setApiKey(apiKey);
38
+ this.storage.set("apiKey", apiKey);
39
+ }
40
+
41
+ setJwt(jwt: string) {
42
+ this.currentJwt = jwt;
43
+ this.currentApiKey = undefined;
44
+ this.httpClient.setJwt(jwt);
45
+ this.storage.set("jwt", jwt);
46
+ }
47
+
48
+ getToken(): string | undefined {
49
+ return this.httpClient.getToken();
50
+ }
51
+
52
+ async whoami(): Promise<WhoAmI> {
53
+ try {
54
+ const response = await this.httpClient.get<WhoAmI>("/v1/auth/whoami");
55
+ return response;
56
+ } catch {
57
+ return { authenticated: false };
58
+ }
59
+ }
60
+
61
+ async refresh(): Promise<string> {
62
+ const response = await this.httpClient.post<{ token: string }>(
63
+ "/v1/auth/refresh"
64
+ );
65
+ const token = response.token;
66
+ this.setJwt(token);
67
+ return token;
68
+ }
69
+
70
+ async logout(): Promise<void> {
71
+ // Only attempt server-side logout if using JWT
72
+ // API keys don't support server-side logout with all=true
73
+ if (this.currentJwt) {
74
+ try {
75
+ await this.httpClient.post("/v1/auth/logout", { all: true });
76
+ } catch (error) {
77
+ // Log warning but don't fail - local cleanup is more important
78
+ console.warn('Server-side logout failed, continuing with local cleanup:', error);
79
+ }
80
+ }
81
+
82
+ // Always clear local state
83
+ this.currentApiKey = undefined;
84
+ this.currentJwt = undefined;
85
+ this.httpClient.setApiKey(undefined);
86
+ this.httpClient.setJwt(undefined);
87
+ await this.storage.clear();
88
+ }
89
+
90
+ async clear(): Promise<void> {
91
+ this.currentApiKey = undefined;
92
+ this.currentJwt = undefined;
93
+ this.httpClient.setApiKey(undefined);
94
+ this.httpClient.setJwt(undefined);
95
+ await this.storage.clear();
96
+ }
97
+ }
@@ -0,0 +1,62 @@
1
+ export interface AuthConfig {
2
+ apiKey?: string;
3
+ jwt?: string;
4
+ }
5
+
6
+ export interface WhoAmI {
7
+ address?: string;
8
+ namespace?: string;
9
+ authenticated: boolean;
10
+ }
11
+
12
+ export interface StorageAdapter {
13
+ get(key: string): Promise<string | null>;
14
+ set(key: string, value: string): Promise<void>;
15
+ clear(): Promise<void>;
16
+ }
17
+
18
+ export class MemoryStorage implements StorageAdapter {
19
+ private storage: Map<string, string> = new Map();
20
+
21
+ async get(key: string): Promise<string | null> {
22
+ return this.storage.get(key) ?? null;
23
+ }
24
+
25
+ async set(key: string, value: string): Promise<void> {
26
+ this.storage.set(key, value);
27
+ }
28
+
29
+ async clear(): Promise<void> {
30
+ this.storage.clear();
31
+ }
32
+ }
33
+
34
+ export class LocalStorageAdapter implements StorageAdapter {
35
+ private prefix = "@network/sdk:";
36
+
37
+ async get(key: string): Promise<string | null> {
38
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
39
+ return globalThis.localStorage.getItem(this.prefix + key);
40
+ }
41
+ return null;
42
+ }
43
+
44
+ async set(key: string, value: string): Promise<void> {
45
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
46
+ globalThis.localStorage.setItem(this.prefix + key, value);
47
+ }
48
+ }
49
+
50
+ async clear(): Promise<void> {
51
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
52
+ const keysToDelete: string[] = [];
53
+ for (let i = 0; i < globalThis.localStorage.length; i++) {
54
+ const key = globalThis.localStorage.key(i);
55
+ if (key?.startsWith(this.prefix)) {
56
+ keysToDelete.push(key);
57
+ }
58
+ }
59
+ keysToDelete.forEach((key) => globalThis.localStorage.removeItem(key));
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,158 @@
1
+ import { SDKError } from "../errors";
2
+
3
+ export interface HttpClientConfig {
4
+ baseURL: string;
5
+ timeout?: number;
6
+ maxRetries?: number;
7
+ retryDelayMs?: number;
8
+ fetch?: typeof fetch;
9
+ }
10
+
11
+ export class HttpClient {
12
+ private baseURL: string;
13
+ private timeout: number;
14
+ private maxRetries: number;
15
+ private retryDelayMs: number;
16
+ private fetch: typeof fetch;
17
+ private apiKey?: string;
18
+ private jwt?: string;
19
+
20
+ constructor(config: HttpClientConfig) {
21
+ this.baseURL = config.baseURL.replace(/\/$/, "");
22
+ this.timeout = config.timeout ?? 30000;
23
+ this.maxRetries = config.maxRetries ?? 3;
24
+ this.retryDelayMs = config.retryDelayMs ?? 1000;
25
+ this.fetch = config.fetch ?? globalThis.fetch;
26
+ }
27
+
28
+ setApiKey(apiKey?: string) {
29
+ this.apiKey = apiKey;
30
+ this.jwt = undefined;
31
+ }
32
+
33
+ setJwt(jwt?: string) {
34
+ this.jwt = jwt;
35
+ this.apiKey = undefined;
36
+ }
37
+
38
+ private getAuthHeaders(): Record<string, string> {
39
+ const headers: Record<string, string> = {};
40
+ if (this.jwt) {
41
+ headers["Authorization"] = `Bearer ${this.jwt}`;
42
+ } else if (this.apiKey) {
43
+ headers["X-API-Key"] = this.apiKey;
44
+ }
45
+ return headers;
46
+ }
47
+
48
+ private getAuthToken(): string | undefined {
49
+ return this.jwt || this.apiKey;
50
+ }
51
+
52
+ async request<T = any>(
53
+ method: "GET" | "POST" | "PUT" | "DELETE",
54
+ path: string,
55
+ options: {
56
+ body?: any;
57
+ headers?: Record<string, string>;
58
+ query?: Record<string, string | number | boolean>;
59
+ } = {}
60
+ ): Promise<T> {
61
+ const url = new URL(this.baseURL + path);
62
+ if (options.query) {
63
+ Object.entries(options.query).forEach(([key, value]) => {
64
+ url.searchParams.append(key, String(value));
65
+ });
66
+ }
67
+
68
+ const headers: Record<string, string> = {
69
+ "Content-Type": "application/json",
70
+ ...this.getAuthHeaders(),
71
+ ...options.headers,
72
+ };
73
+
74
+ const fetchOptions: RequestInit = {
75
+ method,
76
+ headers,
77
+ signal: AbortSignal.timeout(this.timeout),
78
+ };
79
+
80
+ if (options.body !== undefined) {
81
+ fetchOptions.body = JSON.stringify(options.body);
82
+ }
83
+
84
+ return this.requestWithRetry(url.toString(), fetchOptions);
85
+ }
86
+
87
+ private async requestWithRetry(
88
+ url: string,
89
+ options: RequestInit,
90
+ attempt: number = 0
91
+ ): Promise<any> {
92
+ try {
93
+ const response = await this.fetch(url, options);
94
+
95
+ if (!response.ok) {
96
+ let body: any;
97
+ try {
98
+ body = await response.json();
99
+ } catch {
100
+ body = { error: response.statusText };
101
+ }
102
+ throw SDKError.fromResponse(response.status, body);
103
+ }
104
+
105
+ const contentType = response.headers.get("content-type");
106
+ if (contentType?.includes("application/json")) {
107
+ return response.json();
108
+ }
109
+ return response.text();
110
+ } catch (error) {
111
+ if (
112
+ error instanceof SDKError &&
113
+ attempt < this.maxRetries &&
114
+ [408, 429, 500, 502, 503, 504].includes(error.httpStatus)
115
+ ) {
116
+ await new Promise((resolve) =>
117
+ setTimeout(resolve, this.retryDelayMs * (attempt + 1))
118
+ );
119
+ return this.requestWithRetry(url, options, attempt + 1);
120
+ }
121
+ throw error;
122
+ }
123
+ }
124
+
125
+ async get<T = any>(
126
+ path: string,
127
+ options?: Omit<Parameters<typeof this.request>[2], "body">
128
+ ): Promise<T> {
129
+ return this.request<T>("GET", path, options);
130
+ }
131
+
132
+ async post<T = any>(
133
+ path: string,
134
+ body?: any,
135
+ options?: Omit<Parameters<typeof this.request>[2], "body">
136
+ ): Promise<T> {
137
+ return this.request<T>("POST", path, { ...options, body });
138
+ }
139
+
140
+ async put<T = any>(
141
+ path: string,
142
+ body?: any,
143
+ options?: Omit<Parameters<typeof this.request>[2], "body">
144
+ ): Promise<T> {
145
+ return this.request<T>("PUT", path, { ...options, body });
146
+ }
147
+
148
+ async delete<T = any>(
149
+ path: string,
150
+ options?: Omit<Parameters<typeof this.request>[2], "body">
151
+ ): Promise<T> {
152
+ return this.request<T>("DELETE", path, options);
153
+ }
154
+
155
+ getToken(): string | undefined {
156
+ return this.getAuthToken();
157
+ }
158
+ }
package/src/core/ws.ts ADDED
@@ -0,0 +1,182 @@
1
+ import WebSocket from "isomorphic-ws";
2
+ import { SDKError } from "../errors";
3
+
4
+ export interface WSClientConfig {
5
+ wsURL: string;
6
+ timeout?: number;
7
+ maxReconnectAttempts?: number;
8
+ reconnectDelayMs?: number;
9
+ heartbeatIntervalMs?: number;
10
+ authMode?: "header" | "query";
11
+ authToken?: string;
12
+ WebSocket?: typeof WebSocket;
13
+ }
14
+
15
+ export type WSMessageHandler = (data: string) => void;
16
+ export type WSErrorHandler = (error: Error) => void;
17
+ export type WSCloseHandler = () => void;
18
+
19
+ export class WSClient {
20
+ private url: string;
21
+ private timeout: number;
22
+ private maxReconnectAttempts: number;
23
+ private reconnectDelayMs: number;
24
+ private heartbeatIntervalMs: number;
25
+ private authMode: "header" | "query";
26
+ private authToken?: string;
27
+ private WebSocketClass: typeof WebSocket;
28
+
29
+ private ws?: WebSocket;
30
+ private reconnectAttempts = 0;
31
+ private heartbeatInterval?: NodeJS.Timeout;
32
+ private messageHandlers: Set<WSMessageHandler> = new Set();
33
+ private errorHandlers: Set<WSErrorHandler> = new Set();
34
+ private closeHandlers: Set<WSCloseHandler> = new Set();
35
+ private isManuallyClosed = false;
36
+
37
+ constructor(config: WSClientConfig) {
38
+ this.url = config.wsURL;
39
+ this.timeout = config.timeout ?? 30000;
40
+ this.maxReconnectAttempts = config.maxReconnectAttempts ?? 5;
41
+ this.reconnectDelayMs = config.reconnectDelayMs ?? 1000;
42
+ this.heartbeatIntervalMs = config.heartbeatIntervalMs ?? 30000;
43
+ this.authMode = config.authMode ?? "header";
44
+ this.authToken = config.authToken;
45
+ this.WebSocketClass = config.WebSocket ?? WebSocket;
46
+ }
47
+
48
+ connect(): Promise<void> {
49
+ return new Promise((resolve, reject) => {
50
+ try {
51
+ const wsUrl = this.buildWSUrl();
52
+ this.ws = new this.WebSocketClass(wsUrl);
53
+
54
+ // Note: Custom headers via ws library in Node.js are not sent with WebSocket upgrade requests
55
+ // so we rely on query parameters for authentication
56
+
57
+ const timeout = setTimeout(() => {
58
+ this.ws?.close();
59
+ reject(new SDKError("WebSocket connection timeout", 408, "WS_TIMEOUT"));
60
+ }, this.timeout);
61
+
62
+ this.ws.addEventListener("open", () => {
63
+ clearTimeout(timeout);
64
+ this.reconnectAttempts = 0;
65
+ this.startHeartbeat();
66
+ resolve();
67
+ });
68
+
69
+ this.ws.addEventListener("message", (event: Event) => {
70
+ const msgEvent = event as MessageEvent;
71
+ this.messageHandlers.forEach((handler) => handler(msgEvent.data));
72
+ });
73
+
74
+ this.ws.addEventListener("error", (event: Event) => {
75
+ clearTimeout(timeout);
76
+ const error = new SDKError(
77
+ "WebSocket error",
78
+ 500,
79
+ "WS_ERROR",
80
+ event
81
+ );
82
+ this.errorHandlers.forEach((handler) => handler(error));
83
+ });
84
+
85
+ this.ws.addEventListener("close", () => {
86
+ clearTimeout(timeout);
87
+ this.stopHeartbeat();
88
+ if (!this.isManuallyClosed) {
89
+ this.attemptReconnect();
90
+ } else {
91
+ this.closeHandlers.forEach((handler) => handler());
92
+ }
93
+ });
94
+ } catch (error) {
95
+ reject(error);
96
+ }
97
+ });
98
+ }
99
+
100
+ private buildWSUrl(): string {
101
+ let url = this.url;
102
+
103
+ // Always append auth token as query parameter for compatibility
104
+ // Works in both Node.js and browser environments
105
+ if (this.authToken) {
106
+ const separator = url.includes("?") ? "&" : "?";
107
+ const paramName = this.authToken.startsWith("ak_") ? "api_key" : "token";
108
+ url += `${separator}${paramName}=${encodeURIComponent(this.authToken)}`;
109
+ }
110
+
111
+ return url;
112
+ }
113
+
114
+ private startHeartbeat() {
115
+ this.heartbeatInterval = setInterval(() => {
116
+ if (this.ws?.readyState === WebSocket.OPEN) {
117
+ this.ws.send(JSON.stringify({ type: "ping" }));
118
+ }
119
+ }, this.heartbeatIntervalMs);
120
+ }
121
+
122
+ private stopHeartbeat() {
123
+ if (this.heartbeatInterval) {
124
+ clearInterval(this.heartbeatInterval);
125
+ this.heartbeatInterval = undefined;
126
+ }
127
+ }
128
+
129
+ private attemptReconnect() {
130
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
131
+ this.reconnectAttempts++;
132
+ const delayMs = this.reconnectDelayMs * this.reconnectAttempts;
133
+ setTimeout(() => {
134
+ this.connect().catch((error) => {
135
+ this.errorHandlers.forEach((handler) => handler(error));
136
+ });
137
+ }, delayMs);
138
+ } else {
139
+ this.closeHandlers.forEach((handler) => handler());
140
+ }
141
+ }
142
+
143
+ onMessage(handler: WSMessageHandler) {
144
+ this.messageHandlers.add(handler);
145
+ return () => this.messageHandlers.delete(handler);
146
+ }
147
+
148
+ onError(handler: WSErrorHandler) {
149
+ this.errorHandlers.add(handler);
150
+ return () => this.errorHandlers.delete(handler);
151
+ }
152
+
153
+ onClose(handler: WSCloseHandler) {
154
+ this.closeHandlers.add(handler);
155
+ return () => this.closeHandlers.delete(handler);
156
+ }
157
+
158
+ send(data: string) {
159
+ if (this.ws?.readyState !== WebSocket.OPEN) {
160
+ throw new SDKError(
161
+ "WebSocket is not connected",
162
+ 500,
163
+ "WS_NOT_CONNECTED"
164
+ );
165
+ }
166
+ this.ws.send(data);
167
+ }
168
+
169
+ close() {
170
+ this.isManuallyClosed = true;
171
+ this.stopHeartbeat();
172
+ this.ws?.close();
173
+ }
174
+
175
+ isConnected(): boolean {
176
+ return this.ws?.readyState === WebSocket.OPEN;
177
+ }
178
+
179
+ setAuthToken(token?: string) {
180
+ this.authToken = token;
181
+ }
182
+ }