@debros/network-ts-sdk 0.1.4 → 0.2.5
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/README.md +102 -7
- package/dist/index.d.ts +184 -29
- package/dist/index.js +375 -92
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/src/auth/client.ts +144 -10
- package/src/core/http.ts +80 -11
- package/src/core/ws.ts +87 -80
- package/src/index.ts +15 -9
- package/src/network/client.ts +58 -4
- package/src/pubsub/client.ts +174 -28
package/dist/index.js.map
CHANGED
|
@@ -1 +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":[]}
|
|
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 ?? 60000; // Increased from 30s to 60s for pub/sub operations\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 // Don't clear JWT - allow both to coexist\n if (typeof console !== \"undefined\") {\n console.log(\n \"[HttpClient] API key set:\",\n !!apiKey,\n \"JWT still present:\",\n !!this.jwt\n );\n }\n }\n\n setJwt(jwt?: string) {\n this.jwt = jwt;\n // Don't clear API key - allow both to coexist\n if (typeof console !== \"undefined\") {\n console.log(\n \"[HttpClient] JWT set:\",\n !!jwt,\n \"API key still present:\",\n !!this.apiKey\n );\n }\n }\n\n private getAuthHeaders(path: string): Record<string, string> {\n const headers: Record<string, string> = {};\n\n // For database, pubsub, and proxy operations, ONLY use API key to avoid JWT user context\n // interfering with namespace-level authorization\n const isDbOperation = path.includes(\"/v1/rqlite/\");\n const isPubSubOperation = path.includes(\"/v1/pubsub/\");\n const isProxyOperation = path.includes(\"/v1/proxy/\");\n\n if (isDbOperation || isPubSubOperation || isProxyOperation) {\n // For database/pubsub/proxy operations: use only API key (preferred for namespace operations)\n if (this.apiKey) {\n headers[\"X-API-Key\"] = this.apiKey;\n } else if (this.jwt) {\n // Fallback to JWT if no API key\n headers[\"Authorization\"] = `Bearer ${this.jwt}`;\n }\n } else {\n // For auth/other operations: send both JWT and API key\n if (this.jwt) {\n headers[\"Authorization\"] = `Bearer ${this.jwt}`;\n }\n if (this.apiKey) {\n headers[\"X-API-Key\"] = this.apiKey;\n }\n }\n return headers;\n }\n\n private getAuthToken(): string | undefined {\n return this.jwt || this.apiKey;\n }\n\n getApiKey(): string | undefined {\n return 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 timeout?: number; // Per-request timeout override\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(path),\n ...options.headers,\n };\n\n // Debug: Log headers being sent\n if (\n typeof console !== \"undefined\" &&\n (path.includes(\"/db/\") ||\n path.includes(\"/query\") ||\n path.includes(\"/auth/\") ||\n path.includes(\"/pubsub/\") ||\n path.includes(\"/proxy/\"))\n ) {\n console.log(\"[HttpClient] Request headers for\", path, {\n hasAuth: !!headers[\"Authorization\"],\n hasApiKey: !!headers[\"X-API-Key\"],\n authPrefix: headers[\"Authorization\"]\n ? headers[\"Authorization\"].substring(0, 20)\n : \"none\",\n apiKeyPrefix: headers[\"X-API-Key\"]\n ? headers[\"X-API-Key\"].substring(0, 20)\n : \"none\",\n });\n }\n\n const controller = new AbortController();\n const requestTimeout = options.timeout ?? this.timeout; // Use override or default\n const timeoutId = setTimeout(() => controller.abort(), requestTimeout);\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n signal: controller.signal,\n };\n\n if (options.body !== undefined) {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n try {\n return await this.requestWithRetry(url.toString(), fetchOptions);\n } finally {\n clearTimeout(timeoutId);\n }\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 { AuthConfig, WhoAmI, StorageAdapter, MemoryStorage } 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 // Don't clear JWT - it will be cleared explicitly on logout\n this.httpClient.setApiKey(apiKey);\n this.storage.set(\"apiKey\", apiKey);\n }\n\n setJwt(jwt: string) {\n this.currentJwt = jwt;\n // Don't clear API key - keep it as fallback for after logout\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 /**\n * Logout user and clear JWT, but preserve API key\n * Use this for user logout in apps where API key is app-level credential\n */\n async logoutUser(): Promise<void> {\n // Attempt server-side logout if using JWT\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(\n \"Server-side logout failed, continuing with local cleanup:\",\n error\n );\n }\n }\n\n // Clear JWT only, preserve API key\n this.currentJwt = undefined;\n this.httpClient.setJwt(undefined);\n await this.storage.set(\"jwt\", \"\"); // Clear JWT from storage\n\n // Ensure API key is loaded and set as active auth method\n if (!this.currentApiKey) {\n // Try to load from storage\n const storedApiKey = await this.storage.get(\"apiKey\");\n if (storedApiKey) {\n this.currentApiKey = storedApiKey;\n }\n }\n\n // Restore API key as the active auth method\n if (this.currentApiKey) {\n this.httpClient.setApiKey(this.currentApiKey);\n console.log(\"[Auth] API key restored after user logout\");\n } else {\n console.warn(\"[Auth] No API key available after logout\");\n }\n }\n\n /**\n * Full logout - clears both JWT and API key\n * Use this to completely reset authentication state\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(\n \"Server-side logout failed, continuing with local cleanup:\",\n error\n );\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 /**\n * Request a challenge nonce for wallet authentication\n */\n async challenge(params: {\n wallet: string;\n purpose?: string;\n namespace?: string;\n }): Promise<{\n nonce: string;\n wallet: string;\n namespace: string;\n expires_at: string;\n }> {\n const response = await this.httpClient.post(\"/v1/auth/challenge\", {\n wallet: params.wallet,\n purpose: params.purpose || \"authentication\",\n namespace: params.namespace || \"default\",\n });\n return response;\n }\n\n /**\n * Verify wallet signature and get JWT token\n */\n async verify(params: {\n wallet: string;\n nonce: string;\n signature: string;\n namespace?: string;\n chain_type?: \"ETH\" | \"SOL\";\n }): Promise<{\n access_token: string;\n refresh_token?: string;\n subject: string;\n namespace: string;\n api_key?: string;\n expires_in?: number;\n token_type?: string;\n }> {\n const response = await this.httpClient.post(\"/v1/auth/verify\", {\n wallet: params.wallet,\n nonce: params.nonce,\n signature: params.signature,\n namespace: params.namespace || \"default\",\n chain_type: params.chain_type || \"ETH\",\n });\n\n // Persist JWT\n this.setJwt(response.access_token);\n\n // Persist API key if server provided it (created in verifyHandler)\n if ((response as any).api_key) {\n this.setApiKey((response as any).api_key);\n }\n\n // Persist refresh token if present (optional, for silent renewal)\n if ((response as any).refresh_token) {\n await this.storage.set(\"refreshToken\", (response as any).refresh_token);\n }\n\n return response as any;\n }\n\n /**\n * Get API key for wallet (creates namespace ownership)\n */\n async getApiKey(params: {\n wallet: string;\n nonce: string;\n signature: string;\n namespace?: string;\n chain_type?: \"ETH\" | \"SOL\";\n }): Promise<{\n api_key: string;\n namespace: string;\n wallet: string;\n }> {\n const response = await this.httpClient.post(\"/v1/auth/api-key\", {\n wallet: params.wallet,\n nonce: params.nonce,\n signature: params.signature,\n namespace: params.namespace || \"default\",\n chain_type: params.chain_type || \"ETH\",\n });\n\n // Automatically set the API key\n this.setApiKey(response.api_key);\n\n return response;\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 authToken?: string;\n WebSocket?: typeof WebSocket;\n}\n\nexport type WSMessageHandler = (data: string) => void;\nexport type WSErrorHandler = (error: Error) => void;\nexport type WSCloseHandler = () => void;\nexport type WSOpenHandler = () => void;\n\n/**\n * Simple WebSocket client with minimal abstractions\n * No complex reconnection, no heartbeats - keep it simple\n */\nexport class WSClient {\n private url: string;\n private timeout: number;\n private authToken?: string;\n private WebSocketClass: typeof WebSocket;\n\n private ws?: WebSocket;\n private messageHandlers: Set<WSMessageHandler> = new Set();\n private errorHandlers: Set<WSErrorHandler> = new Set();\n private closeHandlers: Set<WSCloseHandler> = new Set();\n private openHandlers: Set<WSOpenHandler> = new Set();\n private isClosed = false;\n\n constructor(config: WSClientConfig) {\n this.url = config.wsURL;\n this.timeout = config.timeout ?? 30000;\n this.authToken = config.authToken;\n this.WebSocketClass = config.WebSocket ?? WebSocket;\n }\n\n /**\n * Connect to WebSocket server\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 this.isClosed = false;\n\n const timeout = setTimeout(() => {\n this.ws?.close();\n reject(\n new SDKError(\"WebSocket connection timeout\", 408, \"WS_TIMEOUT\")\n );\n }, this.timeout);\n\n this.ws.addEventListener(\"open\", () => {\n clearTimeout(timeout);\n console.log(\"[WSClient] Connected to\", this.url);\n this.openHandlers.forEach((handler) => handler());\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 console.error(\"[WSClient] WebSocket error:\", event);\n clearTimeout(timeout);\n const error = new SDKError(\"WebSocket error\", 500, \"WS_ERROR\", event);\n this.errorHandlers.forEach((handler) => handler(error));\n });\n\n this.ws.addEventListener(\"close\", () => {\n clearTimeout(timeout);\n console.log(\"[WSClient] Connection closed\");\n this.closeHandlers.forEach((handler) => handler());\n });\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * Build WebSocket URL with auth token\n */\n private buildWSUrl(): string {\n let url = this.url;\n\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 /**\n * Register message handler\n */\n onMessage(handler: WSMessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n /**\n * Unregister message handler\n */\n offMessage(handler: WSMessageHandler): void {\n this.messageHandlers.delete(handler);\n }\n\n /**\n * Register error handler\n */\n onError(handler: WSErrorHandler): () => void {\n this.errorHandlers.add(handler);\n return () => this.errorHandlers.delete(handler);\n }\n\n /**\n * Unregister error handler\n */\n offError(handler: WSErrorHandler): void {\n this.errorHandlers.delete(handler);\n }\n\n /**\n * Register close handler\n */\n onClose(handler: WSCloseHandler): () => void {\n this.closeHandlers.add(handler);\n return () => this.closeHandlers.delete(handler);\n }\n\n /**\n * Unregister close handler\n */\n offClose(handler: WSCloseHandler): void {\n this.closeHandlers.delete(handler);\n }\n\n /**\n * Register open handler\n */\n onOpen(handler: WSOpenHandler): () => void {\n this.openHandlers.add(handler);\n return () => this.openHandlers.delete(handler);\n }\n\n /**\n * Send data through WebSocket\n */\n send(data: string): void {\n if (this.ws?.readyState !== WebSocket.OPEN) {\n throw new SDKError(\"WebSocket is not connected\", 500, \"WS_NOT_CONNECTED\");\n }\n this.ws.send(data);\n }\n\n /**\n * Close WebSocket connection\n */\n close(): void {\n if (this.isClosed) {\n return;\n }\n this.isClosed = true;\n this.ws?.close();\n }\n\n /**\n * Check if WebSocket is connected\n */\n isConnected(): boolean {\n return !this.isClosed && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Update auth token\n */\n setAuthToken(token?: string): void {\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 interface RawEnvelope {\n data: string; // base64-encoded\n timestamp: number;\n topic: string;\n}\n\n// Cross-platform base64 encoding/decoding utilities\nfunction base64Encode(str: string): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(str).toString(\"base64\");\n } else if (typeof btoa !== \"undefined\") {\n return btoa(\n encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) =>\n String.fromCharCode(parseInt(p1, 16))\n )\n );\n }\n throw new Error(\"No base64 encoding method available\");\n}\n\nfunction base64EncodeBytes(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(bytes).toString(\"base64\");\n } else if (typeof btoa !== \"undefined\") {\n let binary = \"\";\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n throw new Error(\"No base64 encoding method available\");\n}\n\nfunction base64Decode(b64: string): string {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.from(b64, \"base64\").toString(\"utf-8\");\n } else if (typeof atob !== \"undefined\") {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n }\n throw new Error(\"No base64 decoding method available\");\n}\n\nexport type MessageHandler = (message: Message) => void;\nexport type ErrorHandler = (error: Error) => void;\nexport type CloseHandler = () => void;\n\n/**\n * Simple PubSub client - one WebSocket connection per topic\n * No connection pooling, no reference counting - keep it simple\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 via HTTP\n */\n async publish(topic: string, data: string | Uint8Array): Promise<void> {\n let dataBase64: string;\n if (typeof data === \"string\") {\n dataBase64 = base64Encode(data);\n } else {\n dataBase64 = base64EncodeBytes(data);\n }\n\n await this.httpClient.post(\n \"/v1/pubsub/publish\",\n {\n topic,\n data_base64: dataBase64,\n },\n {\n timeout: 30000,\n }\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 * Creates one WebSocket connection per topic\n */\n async subscribe(\n topic: string,\n handlers: {\n onMessage?: MessageHandler;\n onError?: ErrorHandler;\n onClose?: CloseHandler;\n } = {}\n ): Promise<Subscription> {\n // Build WebSocket URL for this topic\n const wsUrl = new URL(this.wsConfig.wsURL || \"ws://127.0.0.1:6001\");\n wsUrl.pathname = \"/v1/pubsub/ws\";\n wsUrl.searchParams.set(\"topic\", topic);\n\n const authToken = this.httpClient.getApiKey() ?? this.httpClient.getToken();\n\n // Create WebSocket client\n const wsClient = new WSClient({\n ...this.wsConfig,\n wsURL: wsUrl.toString(),\n authToken,\n });\n\n await wsClient.connect();\n\n // Create subscription wrapper\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 return subscription;\n }\n}\n\n/**\n * Subscription represents an active WebSocket subscription to a topic\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 private isClosed = false;\n private wsMessageHandler: ((data: string) => void) | null = null;\n private wsErrorHandler: ((error: Error) => void) | null = null;\n private wsCloseHandler: (() => void) | null = null;\n\n constructor(wsClient: WSClient, topic: string) {\n this.wsClient = wsClient;\n this.topic = topic;\n\n // Register message handler\n this.wsMessageHandler = (data) => {\n try {\n // Parse gateway JSON envelope: {data: base64String, timestamp, topic}\n const envelope: RawEnvelope = JSON.parse(data);\n\n // Validate envelope structure\n if (!envelope || typeof envelope !== \"object\") {\n throw new Error(\"Invalid envelope: not an object\");\n }\n if (!envelope.data || typeof envelope.data !== \"string\") {\n throw new Error(\"Invalid envelope: missing or invalid data field\");\n }\n if (!envelope.topic || typeof envelope.topic !== \"string\") {\n throw new Error(\"Invalid envelope: missing or invalid topic field\");\n }\n if (typeof envelope.timestamp !== \"number\") {\n throw new Error(\n \"Invalid envelope: missing or invalid timestamp field\"\n );\n }\n\n // Decode base64 data\n const messageData = base64Decode(envelope.data);\n\n const message: Message = {\n topic: envelope.topic,\n data: messageData,\n timestamp: envelope.timestamp,\n };\n\n console.log(\"[Subscription] Received message on topic:\", this.topic);\n this.messageHandlers.forEach((handler) => handler(message));\n } catch (error) {\n console.error(\"[Subscription] Error processing message:\", error);\n this.errorHandlers.forEach((handler) =>\n handler(error instanceof Error ? error : new Error(String(error)))\n );\n }\n };\n\n this.wsClient.onMessage(this.wsMessageHandler);\n\n // Register error handler\n this.wsErrorHandler = (error) => {\n this.errorHandlers.forEach((handler) => handler(error));\n };\n this.wsClient.onError(this.wsErrorHandler);\n\n // Register close handler\n this.wsCloseHandler = () => {\n this.closeHandlers.forEach((handler) => handler());\n };\n this.wsClient.onClose(this.wsCloseHandler);\n }\n\n /**\n * Register message handler\n */\n onMessage(handler: MessageHandler): () => void {\n this.messageHandlers.add(handler);\n return () => this.messageHandlers.delete(handler);\n }\n\n /**\n * Register error handler\n */\n onError(handler: ErrorHandler): () => void {\n this.errorHandlers.add(handler);\n return () => this.errorHandlers.delete(handler);\n }\n\n /**\n * Register close handler\n */\n onClose(handler: CloseHandler): () => void {\n this.closeHandlers.add(handler);\n return () => this.closeHandlers.delete(handler);\n }\n\n /**\n * Close subscription and underlying WebSocket\n */\n close(): void {\n if (this.isClosed) {\n return;\n }\n this.isClosed = true;\n\n // Remove handlers from WSClient\n if (this.wsMessageHandler) {\n this.wsClient.offMessage(this.wsMessageHandler);\n this.wsMessageHandler = null;\n }\n if (this.wsErrorHandler) {\n this.wsClient.offError(this.wsErrorHandler);\n this.wsErrorHandler = null;\n }\n if (this.wsCloseHandler) {\n this.wsClient.offClose(this.wsCloseHandler);\n this.wsCloseHandler = null;\n }\n\n // Clear all local handlers\n this.messageHandlers.clear();\n this.errorHandlers.clear();\n this.closeHandlers.clear();\n\n // Close WebSocket connection\n this.wsClient.close();\n }\n\n /**\n * Check if subscription is active\n */\n isConnected(): boolean {\n return !this.isClosed && 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 node_id: string;\n connected: boolean;\n peer_count: number;\n database_size: number;\n uptime: number;\n}\n\nexport interface ProxyRequest {\n url: string;\n method: string;\n headers?: Record<string, string>;\n body?: string;\n}\n\nexport interface ProxyResponse {\n status_code: number;\n headers: Record<string, string>;\n body: string;\n error?: string;\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>(\n \"/v1/network/status\"\n );\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 /**\n * Proxy an HTTP request through the Anyone network.\n * Requires authentication (API key or JWT).\n *\n * @param request - The proxy request configuration\n * @returns The proxied response\n * @throws {SDKError} If the Anyone proxy is not available or the request fails\n *\n * @example\n * ```ts\n * const response = await client.network.proxyAnon({\n * url: 'https://api.example.com/data',\n * method: 'GET',\n * headers: {\n * 'Accept': 'application/json'\n * }\n * });\n *\n * console.log(response.status_code); // 200\n * console.log(response.body); // Response data\n * ```\n */\n async proxyAnon(request: ProxyRequest): Promise<ProxyResponse> {\n const response = await this.httpClient.post<ProxyResponse>(\n \"/v1/proxy/anon\",\n request\n );\n\n // Check if the response contains an error\n if (response.error) {\n throw new Error(`Proxy request failed: ${response.error}`);\n }\n\n return response;\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 {\n StorageAdapter,\n MemoryStorage,\n LocalStorageAdapter,\n} 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 =\n 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 { StorageAdapter, AuthConfig, WhoAmI } from \"./auth/types\";\nexport type * from \"./db/types\";\nexport type {\n Message,\n MessageHandler,\n ErrorHandler,\n CloseHandler,\n} from \"./pubsub/client\";\nexport type {\n PeerInfo,\n NetworkStatus,\n ProxyRequest,\n ProxyResponse,\n} from \"./network/client\";\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@debros/network-ts-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "TypeScript SDK for DeBros Network Gateway",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,12 +36,13 @@
|
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
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
39
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
44
|
-
"@typescript-eslint/parser": "^6.0.0"
|
|
40
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
41
|
+
"dotenv": "^17.2.3",
|
|
42
|
+
"eslint": "^8.0.0",
|
|
43
|
+
"tsup": "^8.0.0",
|
|
44
|
+
"typescript": "^5.3.0",
|
|
45
|
+
"vitest": "^1.0.0"
|
|
45
46
|
},
|
|
46
47
|
"publishConfig": {
|
|
47
48
|
"registry": "https://registry.npmjs.org/",
|
package/src/auth/client.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { HttpClient } from "../core/http";
|
|
2
|
-
import {
|
|
3
|
-
AuthConfig,
|
|
4
|
-
WhoAmI,
|
|
5
|
-
StorageAdapter,
|
|
6
|
-
MemoryStorage,
|
|
7
|
-
} from "./types";
|
|
2
|
+
import { AuthConfig, WhoAmI, StorageAdapter, MemoryStorage } from "./types";
|
|
8
3
|
|
|
9
4
|
export class AuthClient {
|
|
10
5
|
private httpClient: HttpClient;
|
|
@@ -33,14 +28,14 @@ export class AuthClient {
|
|
|
33
28
|
|
|
34
29
|
setApiKey(apiKey: string) {
|
|
35
30
|
this.currentApiKey = apiKey;
|
|
36
|
-
|
|
31
|
+
// Don't clear JWT - it will be cleared explicitly on logout
|
|
37
32
|
this.httpClient.setApiKey(apiKey);
|
|
38
33
|
this.storage.set("apiKey", apiKey);
|
|
39
34
|
}
|
|
40
35
|
|
|
41
36
|
setJwt(jwt: string) {
|
|
42
37
|
this.currentJwt = jwt;
|
|
43
|
-
|
|
38
|
+
// Don't clear API key - keep it as fallback for after logout
|
|
44
39
|
this.httpClient.setJwt(jwt);
|
|
45
40
|
this.storage.set("jwt", jwt);
|
|
46
41
|
}
|
|
@@ -67,6 +62,51 @@ export class AuthClient {
|
|
|
67
62
|
return token;
|
|
68
63
|
}
|
|
69
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Logout user and clear JWT, but preserve API key
|
|
67
|
+
* Use this for user logout in apps where API key is app-level credential
|
|
68
|
+
*/
|
|
69
|
+
async logoutUser(): Promise<void> {
|
|
70
|
+
// Attempt server-side logout if using JWT
|
|
71
|
+
if (this.currentJwt) {
|
|
72
|
+
try {
|
|
73
|
+
await this.httpClient.post("/v1/auth/logout", { all: true });
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// Log warning but don't fail - local cleanup is more important
|
|
76
|
+
console.warn(
|
|
77
|
+
"Server-side logout failed, continuing with local cleanup:",
|
|
78
|
+
error
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Clear JWT only, preserve API key
|
|
84
|
+
this.currentJwt = undefined;
|
|
85
|
+
this.httpClient.setJwt(undefined);
|
|
86
|
+
await this.storage.set("jwt", ""); // Clear JWT from storage
|
|
87
|
+
|
|
88
|
+
// Ensure API key is loaded and set as active auth method
|
|
89
|
+
if (!this.currentApiKey) {
|
|
90
|
+
// Try to load from storage
|
|
91
|
+
const storedApiKey = await this.storage.get("apiKey");
|
|
92
|
+
if (storedApiKey) {
|
|
93
|
+
this.currentApiKey = storedApiKey;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Restore API key as the active auth method
|
|
98
|
+
if (this.currentApiKey) {
|
|
99
|
+
this.httpClient.setApiKey(this.currentApiKey);
|
|
100
|
+
console.log("[Auth] API key restored after user logout");
|
|
101
|
+
} else {
|
|
102
|
+
console.warn("[Auth] No API key available after logout");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Full logout - clears both JWT and API key
|
|
108
|
+
* Use this to completely reset authentication state
|
|
109
|
+
*/
|
|
70
110
|
async logout(): Promise<void> {
|
|
71
111
|
// Only attempt server-side logout if using JWT
|
|
72
112
|
// API keys don't support server-side logout with all=true
|
|
@@ -75,10 +115,13 @@ export class AuthClient {
|
|
|
75
115
|
await this.httpClient.post("/v1/auth/logout", { all: true });
|
|
76
116
|
} catch (error) {
|
|
77
117
|
// Log warning but don't fail - local cleanup is more important
|
|
78
|
-
console.warn(
|
|
118
|
+
console.warn(
|
|
119
|
+
"Server-side logout failed, continuing with local cleanup:",
|
|
120
|
+
error
|
|
121
|
+
);
|
|
79
122
|
}
|
|
80
123
|
}
|
|
81
|
-
|
|
124
|
+
|
|
82
125
|
// Always clear local state
|
|
83
126
|
this.currentApiKey = undefined;
|
|
84
127
|
this.currentJwt = undefined;
|
|
@@ -94,4 +137,95 @@ export class AuthClient {
|
|
|
94
137
|
this.httpClient.setJwt(undefined);
|
|
95
138
|
await this.storage.clear();
|
|
96
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Request a challenge nonce for wallet authentication
|
|
143
|
+
*/
|
|
144
|
+
async challenge(params: {
|
|
145
|
+
wallet: string;
|
|
146
|
+
purpose?: string;
|
|
147
|
+
namespace?: string;
|
|
148
|
+
}): Promise<{
|
|
149
|
+
nonce: string;
|
|
150
|
+
wallet: string;
|
|
151
|
+
namespace: string;
|
|
152
|
+
expires_at: string;
|
|
153
|
+
}> {
|
|
154
|
+
const response = await this.httpClient.post("/v1/auth/challenge", {
|
|
155
|
+
wallet: params.wallet,
|
|
156
|
+
purpose: params.purpose || "authentication",
|
|
157
|
+
namespace: params.namespace || "default",
|
|
158
|
+
});
|
|
159
|
+
return response;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Verify wallet signature and get JWT token
|
|
164
|
+
*/
|
|
165
|
+
async verify(params: {
|
|
166
|
+
wallet: string;
|
|
167
|
+
nonce: string;
|
|
168
|
+
signature: string;
|
|
169
|
+
namespace?: string;
|
|
170
|
+
chain_type?: "ETH" | "SOL";
|
|
171
|
+
}): Promise<{
|
|
172
|
+
access_token: string;
|
|
173
|
+
refresh_token?: string;
|
|
174
|
+
subject: string;
|
|
175
|
+
namespace: string;
|
|
176
|
+
api_key?: string;
|
|
177
|
+
expires_in?: number;
|
|
178
|
+
token_type?: string;
|
|
179
|
+
}> {
|
|
180
|
+
const response = await this.httpClient.post("/v1/auth/verify", {
|
|
181
|
+
wallet: params.wallet,
|
|
182
|
+
nonce: params.nonce,
|
|
183
|
+
signature: params.signature,
|
|
184
|
+
namespace: params.namespace || "default",
|
|
185
|
+
chain_type: params.chain_type || "ETH",
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Persist JWT
|
|
189
|
+
this.setJwt(response.access_token);
|
|
190
|
+
|
|
191
|
+
// Persist API key if server provided it (created in verifyHandler)
|
|
192
|
+
if ((response as any).api_key) {
|
|
193
|
+
this.setApiKey((response as any).api_key);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Persist refresh token if present (optional, for silent renewal)
|
|
197
|
+
if ((response as any).refresh_token) {
|
|
198
|
+
await this.storage.set("refreshToken", (response as any).refresh_token);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return response as any;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get API key for wallet (creates namespace ownership)
|
|
206
|
+
*/
|
|
207
|
+
async getApiKey(params: {
|
|
208
|
+
wallet: string;
|
|
209
|
+
nonce: string;
|
|
210
|
+
signature: string;
|
|
211
|
+
namespace?: string;
|
|
212
|
+
chain_type?: "ETH" | "SOL";
|
|
213
|
+
}): Promise<{
|
|
214
|
+
api_key: string;
|
|
215
|
+
namespace: string;
|
|
216
|
+
wallet: string;
|
|
217
|
+
}> {
|
|
218
|
+
const response = await this.httpClient.post("/v1/auth/api-key", {
|
|
219
|
+
wallet: params.wallet,
|
|
220
|
+
nonce: params.nonce,
|
|
221
|
+
signature: params.signature,
|
|
222
|
+
namespace: params.namespace || "default",
|
|
223
|
+
chain_type: params.chain_type || "ETH",
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Automatically set the API key
|
|
227
|
+
this.setApiKey(response.api_key);
|
|
228
|
+
|
|
229
|
+
return response;
|
|
230
|
+
}
|
|
97
231
|
}
|
package/src/core/http.ts
CHANGED
|
@@ -19,7 +19,7 @@ export class HttpClient {
|
|
|
19
19
|
|
|
20
20
|
constructor(config: HttpClientConfig) {
|
|
21
21
|
this.baseURL = config.baseURL.replace(/\/$/, "");
|
|
22
|
-
this.timeout = config.timeout ??
|
|
22
|
+
this.timeout = config.timeout ?? 60000; // Increased from 30s to 60s for pub/sub operations
|
|
23
23
|
this.maxRetries = config.maxRetries ?? 3;
|
|
24
24
|
this.retryDelayMs = config.retryDelayMs ?? 1000;
|
|
25
25
|
this.fetch = config.fetch ?? globalThis.fetch;
|
|
@@ -27,20 +27,55 @@ export class HttpClient {
|
|
|
27
27
|
|
|
28
28
|
setApiKey(apiKey?: string) {
|
|
29
29
|
this.apiKey = apiKey;
|
|
30
|
-
|
|
30
|
+
// Don't clear JWT - allow both to coexist
|
|
31
|
+
if (typeof console !== "undefined") {
|
|
32
|
+
console.log(
|
|
33
|
+
"[HttpClient] API key set:",
|
|
34
|
+
!!apiKey,
|
|
35
|
+
"JWT still present:",
|
|
36
|
+
!!this.jwt
|
|
37
|
+
);
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
setJwt(jwt?: string) {
|
|
34
42
|
this.jwt = jwt;
|
|
35
|
-
|
|
43
|
+
// Don't clear API key - allow both to coexist
|
|
44
|
+
if (typeof console !== "undefined") {
|
|
45
|
+
console.log(
|
|
46
|
+
"[HttpClient] JWT set:",
|
|
47
|
+
!!jwt,
|
|
48
|
+
"API key still present:",
|
|
49
|
+
!!this.apiKey
|
|
50
|
+
);
|
|
51
|
+
}
|
|
36
52
|
}
|
|
37
53
|
|
|
38
|
-
private getAuthHeaders(): Record<string, string> {
|
|
54
|
+
private getAuthHeaders(path: string): Record<string, string> {
|
|
39
55
|
const headers: Record<string, string> = {};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
|
|
57
|
+
// For database, pubsub, and proxy operations, ONLY use API key to avoid JWT user context
|
|
58
|
+
// interfering with namespace-level authorization
|
|
59
|
+
const isDbOperation = path.includes("/v1/rqlite/");
|
|
60
|
+
const isPubSubOperation = path.includes("/v1/pubsub/");
|
|
61
|
+
const isProxyOperation = path.includes("/v1/proxy/");
|
|
62
|
+
|
|
63
|
+
if (isDbOperation || isPubSubOperation || isProxyOperation) {
|
|
64
|
+
// For database/pubsub/proxy operations: use only API key (preferred for namespace operations)
|
|
65
|
+
if (this.apiKey) {
|
|
66
|
+
headers["X-API-Key"] = this.apiKey;
|
|
67
|
+
} else if (this.jwt) {
|
|
68
|
+
// Fallback to JWT if no API key
|
|
69
|
+
headers["Authorization"] = `Bearer ${this.jwt}`;
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// For auth/other operations: send both JWT and API key
|
|
73
|
+
if (this.jwt) {
|
|
74
|
+
headers["Authorization"] = `Bearer ${this.jwt}`;
|
|
75
|
+
}
|
|
76
|
+
if (this.apiKey) {
|
|
77
|
+
headers["X-API-Key"] = this.apiKey;
|
|
78
|
+
}
|
|
44
79
|
}
|
|
45
80
|
return headers;
|
|
46
81
|
}
|
|
@@ -49,6 +84,10 @@ export class HttpClient {
|
|
|
49
84
|
return this.jwt || this.apiKey;
|
|
50
85
|
}
|
|
51
86
|
|
|
87
|
+
getApiKey(): string | undefined {
|
|
88
|
+
return this.apiKey;
|
|
89
|
+
}
|
|
90
|
+
|
|
52
91
|
async request<T = any>(
|
|
53
92
|
method: "GET" | "POST" | "PUT" | "DELETE",
|
|
54
93
|
path: string,
|
|
@@ -56,6 +95,7 @@ export class HttpClient {
|
|
|
56
95
|
body?: any;
|
|
57
96
|
headers?: Record<string, string>;
|
|
58
97
|
query?: Record<string, string | number | boolean>;
|
|
98
|
+
timeout?: number; // Per-request timeout override
|
|
59
99
|
} = {}
|
|
60
100
|
): Promise<T> {
|
|
61
101
|
const url = new URL(this.baseURL + path);
|
|
@@ -67,21 +107,50 @@ export class HttpClient {
|
|
|
67
107
|
|
|
68
108
|
const headers: Record<string, string> = {
|
|
69
109
|
"Content-Type": "application/json",
|
|
70
|
-
...this.getAuthHeaders(),
|
|
110
|
+
...this.getAuthHeaders(path),
|
|
71
111
|
...options.headers,
|
|
72
112
|
};
|
|
73
113
|
|
|
114
|
+
// Debug: Log headers being sent
|
|
115
|
+
if (
|
|
116
|
+
typeof console !== "undefined" &&
|
|
117
|
+
(path.includes("/db/") ||
|
|
118
|
+
path.includes("/query") ||
|
|
119
|
+
path.includes("/auth/") ||
|
|
120
|
+
path.includes("/pubsub/") ||
|
|
121
|
+
path.includes("/proxy/"))
|
|
122
|
+
) {
|
|
123
|
+
console.log("[HttpClient] Request headers for", path, {
|
|
124
|
+
hasAuth: !!headers["Authorization"],
|
|
125
|
+
hasApiKey: !!headers["X-API-Key"],
|
|
126
|
+
authPrefix: headers["Authorization"]
|
|
127
|
+
? headers["Authorization"].substring(0, 20)
|
|
128
|
+
: "none",
|
|
129
|
+
apiKeyPrefix: headers["X-API-Key"]
|
|
130
|
+
? headers["X-API-Key"].substring(0, 20)
|
|
131
|
+
: "none",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const controller = new AbortController();
|
|
136
|
+
const requestTimeout = options.timeout ?? this.timeout; // Use override or default
|
|
137
|
+
const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
|
|
138
|
+
|
|
74
139
|
const fetchOptions: RequestInit = {
|
|
75
140
|
method,
|
|
76
141
|
headers,
|
|
77
|
-
signal:
|
|
142
|
+
signal: controller.signal,
|
|
78
143
|
};
|
|
79
144
|
|
|
80
145
|
if (options.body !== undefined) {
|
|
81
146
|
fetchOptions.body = JSON.stringify(options.body);
|
|
82
147
|
}
|
|
83
148
|
|
|
84
|
-
|
|
149
|
+
try {
|
|
150
|
+
return await this.requestWithRetry(url.toString(), fetchOptions);
|
|
151
|
+
} finally {
|
|
152
|
+
clearTimeout(timeoutId);
|
|
153
|
+
}
|
|
85
154
|
}
|
|
86
155
|
|
|
87
156
|
private async requestWithRetry(
|