@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 CHANGED
@@ -1,4 +1,4 @@
1
- # @network/sdk - TypeScript SDK for DeBros Network
1
+ # @debros/network-ts-sdk - TypeScript SDK for DeBros Network
2
2
 
3
3
  A modern, isomorphic TypeScript SDK for the DeBros Network gateway. Works seamlessly in both Node.js and browser environments with support for database operations, pub/sub messaging, and network management.
4
4
 
@@ -14,7 +14,7 @@ A modern, isomorphic TypeScript SDK for the DeBros Network gateway. Works seamle
14
14
  ## Installation
15
15
 
16
16
  ```bash
17
- npm install @network/network-ts-sdk
17
+ npm install @debros/network-ts-sdk
18
18
  ```
19
19
 
20
20
  ## Quick Start
@@ -22,7 +22,7 @@ npm install @network/network-ts-sdk
22
22
  ### Initialize the Client
23
23
 
24
24
  ```typescript
25
- import { createClient } from "@network/sdk";
25
+ import { createClient } from "@debros/network-ts-sdk";
26
26
 
27
27
  const client = createClient({
28
28
  baseURL: "http://localhost:6001",
@@ -122,10 +122,23 @@ const results = await client.db.transaction([
122
122
 
123
123
  ### Pub/Sub Messaging
124
124
 
125
+ The SDK provides a robust pub/sub client with:
126
+
127
+ - **Multi-subscriber support**: Multiple connections can subscribe to the same topic
128
+ - **Namespace isolation**: Topics are scoped to your authenticated namespace
129
+ - **Server timestamps**: Messages preserve server-side timestamps
130
+ - **Binary-safe**: Supports both string and binary (`Uint8Array`) payloads
131
+ - **Strict envelope validation**: Type-safe message parsing with error handling
132
+
125
133
  #### Publish a Message
126
134
 
127
135
  ```typescript
136
+ // Publish a string message
128
137
  await client.pubsub.publish("notifications", "Hello, Network!");
138
+
139
+ // Publish binary data
140
+ const binaryData = new Uint8Array([1, 2, 3, 4]);
141
+ await client.pubsub.publish("binary-topic", binaryData);
129
142
  ```
130
143
 
131
144
  #### Subscribe to Topics
@@ -133,7 +146,9 @@ await client.pubsub.publish("notifications", "Hello, Network!");
133
146
  ```typescript
134
147
  const subscription = await client.pubsub.subscribe("notifications", {
135
148
  onMessage: (msg) => {
136
- console.log("Received:", msg.data);
149
+ console.log("Topic:", msg.topic);
150
+ console.log("Data:", msg.data);
151
+ console.log("Server timestamp:", new Date(msg.timestamp));
137
152
  },
138
153
  onError: (err) => {
139
154
  console.error("Subscription error:", err);
@@ -147,6 +162,52 @@ const subscription = await client.pubsub.subscribe("notifications", {
147
162
  subscription.close();
148
163
  ```
149
164
 
165
+ **Message Interface:**
166
+
167
+ ```typescript
168
+ interface Message {
169
+ data: string; // Decoded message payload (string)
170
+ topic: string; // Topic name
171
+ timestamp: number; // Server timestamp in milliseconds
172
+ }
173
+ ```
174
+
175
+ #### Debug Raw Envelopes
176
+
177
+ For debugging, you can inspect raw message envelopes before decoding:
178
+
179
+ ```typescript
180
+ const subscription = await client.pubsub.subscribe("notifications", {
181
+ onMessage: (msg) => {
182
+ console.log("Decoded message:", msg.data);
183
+ },
184
+ onRaw: (envelope) => {
185
+ console.log("Raw envelope:", envelope);
186
+ // { data: "base64...", timestamp: 1234567890, topic: "notifications" }
187
+ },
188
+ });
189
+ ```
190
+
191
+ #### Multi-Subscriber Support
192
+
193
+ Multiple subscriptions to the same topic are supported. Each receives its own copy of messages:
194
+
195
+ ```typescript
196
+ // First subscriber
197
+ const sub1 = await client.pubsub.subscribe("events", {
198
+ onMessage: (msg) => console.log("Sub1:", msg.data),
199
+ });
200
+
201
+ // Second subscriber (both receive messages)
202
+ const sub2 = await client.pubsub.subscribe("events", {
203
+ onMessage: (msg) => console.log("Sub2:", msg.data),
204
+ });
205
+
206
+ // Unsubscribe independently
207
+ sub1.close(); // sub2 still active
208
+ sub2.close(); // fully unsubscribed
209
+ ```
210
+
150
211
  #### List Topics
151
212
 
152
213
  ```typescript
@@ -211,6 +272,40 @@ peers.forEach((peer) => {
211
272
  });
212
273
  ```
213
274
 
275
+ #### Proxy Requests Through Anyone Network
276
+
277
+ Make anonymous HTTP requests through the Anyone network:
278
+
279
+ ```typescript
280
+ // Simple GET request
281
+ const response = await client.network.proxyAnon({
282
+ url: "https://api.example.com/data",
283
+ method: "GET",
284
+ headers: {
285
+ Accept: "application/json",
286
+ },
287
+ });
288
+
289
+ console.log(response.status_code); // 200
290
+ console.log(response.body); // Response data as string
291
+ console.log(response.headers); // Response headers
292
+
293
+ // POST request with body
294
+ const postResponse = await client.network.proxyAnon({
295
+ url: "https://api.example.com/submit",
296
+ method: "POST",
297
+ headers: {
298
+ "Content-Type": "application/json",
299
+ },
300
+ body: JSON.stringify({ key: "value" }),
301
+ });
302
+
303
+ // Parse JSON response
304
+ const data = JSON.parse(postResponse.body);
305
+ ```
306
+
307
+ **Note:** The proxy endpoint requires authentication (API key or JWT) and only works when the Anyone relay is running on the gateway server.
308
+
214
309
  ## Configuration
215
310
 
216
311
  ### ClientConfig
@@ -234,7 +329,7 @@ interface ClientConfig {
234
329
  By default, credentials are stored in memory. For browser apps, use localStorage:
235
330
 
236
331
  ```typescript
237
- import { createClient, LocalStorageAdapter } from "@network/sdk";
332
+ import { createClient, LocalStorageAdapter } from "@debros/network-ts-sdk";
238
333
 
239
334
  const client = createClient({
240
335
  baseURL: "http://localhost:6001",
@@ -248,7 +343,7 @@ const client = createClient({
248
343
  The SDK throws `SDKError` for all errors:
249
344
 
250
345
  ```typescript
251
- import { SDKError } from "@network/sdk";
346
+ import { SDKError } from "@debros/network-ts-sdk";
252
347
 
253
348
  try {
254
349
  await client.db.query("SELECT * FROM nonexistent");
@@ -268,7 +363,7 @@ The SDK works in browsers with minimal setup:
268
363
 
269
364
  ```typescript
270
365
  // Browser example
271
- import { createClient } from "@network/sdk";
366
+ import { createClient } from "@debros/network-ts-sdk";
272
367
 
273
368
  const client = createClient({
274
369
  baseURL: "https://gateway.example.com",
package/dist/index.d.ts CHANGED
@@ -20,10 +20,12 @@ declare class HttpClient {
20
20
  setJwt(jwt?: string): void;
21
21
  private getAuthHeaders;
22
22
  private getAuthToken;
23
+ getApiKey(): string | undefined;
23
24
  request<T = any>(method: "GET" | "POST" | "PUT" | "DELETE", path: string, options?: {
24
25
  body?: any;
25
26
  headers?: Record<string, string>;
26
27
  query?: Record<string, string | number | boolean>;
28
+ timeout?: number;
27
29
  }): Promise<T>;
28
30
  private requestWithRetry;
29
31
  get<T = any>(path: string, options?: Omit<Parameters<typeof this.request>[2], "body">): Promise<T>;
@@ -76,8 +78,62 @@ declare class AuthClient {
76
78
  getToken(): string | undefined;
77
79
  whoami(): Promise<WhoAmI>;
78
80
  refresh(): Promise<string>;
81
+ /**
82
+ * Logout user and clear JWT, but preserve API key
83
+ * Use this for user logout in apps where API key is app-level credential
84
+ */
85
+ logoutUser(): Promise<void>;
86
+ /**
87
+ * Full logout - clears both JWT and API key
88
+ * Use this to completely reset authentication state
89
+ */
79
90
  logout(): Promise<void>;
80
91
  clear(): Promise<void>;
92
+ /**
93
+ * Request a challenge nonce for wallet authentication
94
+ */
95
+ challenge(params: {
96
+ wallet: string;
97
+ purpose?: string;
98
+ namespace?: string;
99
+ }): Promise<{
100
+ nonce: string;
101
+ wallet: string;
102
+ namespace: string;
103
+ expires_at: string;
104
+ }>;
105
+ /**
106
+ * Verify wallet signature and get JWT token
107
+ */
108
+ verify(params: {
109
+ wallet: string;
110
+ nonce: string;
111
+ signature: string;
112
+ namespace?: string;
113
+ chain_type?: "ETH" | "SOL";
114
+ }): Promise<{
115
+ access_token: string;
116
+ refresh_token?: string;
117
+ subject: string;
118
+ namespace: string;
119
+ api_key?: string;
120
+ expires_in?: number;
121
+ token_type?: string;
122
+ }>;
123
+ /**
124
+ * Get API key for wallet (creates namespace ownership)
125
+ */
126
+ getApiKey(params: {
127
+ wallet: string;
128
+ nonce: string;
129
+ signature: string;
130
+ namespace?: string;
131
+ chain_type?: "ETH" | "SOL";
132
+ }): Promise<{
133
+ api_key: string;
134
+ namespace: string;
135
+ wallet: string;
136
+ }>;
81
137
  }
82
138
 
83
139
  declare class QueryBuilder {
@@ -214,70 +270,110 @@ declare class DBClient {
214
270
  interface WSClientConfig {
215
271
  wsURL: string;
216
272
  timeout?: number;
217
- maxReconnectAttempts?: number;
218
- reconnectDelayMs?: number;
219
- heartbeatIntervalMs?: number;
220
- authMode?: "header" | "query";
221
273
  authToken?: string;
222
274
  WebSocket?: typeof WebSocket;
223
275
  }
224
276
  type WSMessageHandler = (data: string) => void;
225
277
  type WSErrorHandler = (error: Error) => void;
226
278
  type WSCloseHandler = () => void;
279
+ type WSOpenHandler = () => void;
280
+ /**
281
+ * Simple WebSocket client with minimal abstractions
282
+ * No complex reconnection, no heartbeats - keep it simple
283
+ */
227
284
  declare class WSClient {
228
285
  private url;
229
286
  private timeout;
230
- private maxReconnectAttempts;
231
- private reconnectDelayMs;
232
- private heartbeatIntervalMs;
233
- private authMode;
234
287
  private authToken?;
235
288
  private WebSocketClass;
236
289
  private ws?;
237
- private reconnectAttempts;
238
- private heartbeatInterval?;
239
290
  private messageHandlers;
240
291
  private errorHandlers;
241
292
  private closeHandlers;
242
- private isManuallyClosed;
293
+ private openHandlers;
294
+ private isClosed;
243
295
  constructor(config: WSClientConfig);
296
+ /**
297
+ * Connect to WebSocket server
298
+ */
244
299
  connect(): Promise<void>;
300
+ /**
301
+ * Build WebSocket URL with auth token
302
+ */
245
303
  private buildWSUrl;
246
- private startHeartbeat;
247
- private stopHeartbeat;
248
- private attemptReconnect;
249
- onMessage(handler: WSMessageHandler): () => boolean;
250
- onError(handler: WSErrorHandler): () => boolean;
251
- onClose(handler: WSCloseHandler): () => boolean;
304
+ /**
305
+ * Register message handler
306
+ */
307
+ onMessage(handler: WSMessageHandler): () => void;
308
+ /**
309
+ * Unregister message handler
310
+ */
311
+ offMessage(handler: WSMessageHandler): void;
312
+ /**
313
+ * Register error handler
314
+ */
315
+ onError(handler: WSErrorHandler): () => void;
316
+ /**
317
+ * Unregister error handler
318
+ */
319
+ offError(handler: WSErrorHandler): void;
320
+ /**
321
+ * Register close handler
322
+ */
323
+ onClose(handler: WSCloseHandler): () => void;
324
+ /**
325
+ * Unregister close handler
326
+ */
327
+ offClose(handler: WSCloseHandler): void;
328
+ /**
329
+ * Register open handler
330
+ */
331
+ onOpen(handler: WSOpenHandler): () => void;
332
+ /**
333
+ * Send data through WebSocket
334
+ */
252
335
  send(data: string): void;
336
+ /**
337
+ * Close WebSocket connection
338
+ */
253
339
  close(): void;
340
+ /**
341
+ * Check if WebSocket is connected
342
+ */
254
343
  isConnected(): boolean;
344
+ /**
345
+ * Update auth token
346
+ */
255
347
  setAuthToken(token?: string): void;
256
348
  }
257
349
 
258
350
  interface Message {
259
351
  data: string;
260
352
  topic: string;
261
- timestamp?: number;
353
+ timestamp: number;
262
354
  }
263
355
  type MessageHandler = (message: Message) => void;
264
356
  type ErrorHandler = (error: Error) => void;
265
357
  type CloseHandler = () => void;
358
+ /**
359
+ * Simple PubSub client - one WebSocket connection per topic
360
+ * No connection pooling, no reference counting - keep it simple
361
+ */
266
362
  declare class PubSubClient {
267
363
  private httpClient;
268
364
  private wsConfig;
269
365
  constructor(httpClient: HttpClient, wsConfig?: Partial<WSClientConfig>);
270
366
  /**
271
- * Publish a message to a topic.
367
+ * Publish a message to a topic via HTTP
272
368
  */
273
369
  publish(topic: string, data: string | Uint8Array): Promise<void>;
274
370
  /**
275
- * List active topics in the current namespace.
371
+ * List active topics in the current namespace
276
372
  */
277
373
  topics(): Promise<string[]>;
278
374
  /**
279
- * Subscribe to a topic via WebSocket.
280
- * Returns a subscription object with event handlers.
375
+ * Subscribe to a topic via WebSocket
376
+ * Creates one WebSocket connection per topic
281
377
  */
282
378
  subscribe(topic: string, handlers?: {
283
379
  onMessage?: MessageHandler;
@@ -285,17 +381,39 @@ declare class PubSubClient {
285
381
  onClose?: CloseHandler;
286
382
  }): Promise<Subscription>;
287
383
  }
384
+ /**
385
+ * Subscription represents an active WebSocket subscription to a topic
386
+ */
288
387
  declare class Subscription {
289
388
  private wsClient;
290
389
  private topic;
291
390
  private messageHandlers;
292
391
  private errorHandlers;
293
392
  private closeHandlers;
393
+ private isClosed;
394
+ private wsMessageHandler;
395
+ private wsErrorHandler;
396
+ private wsCloseHandler;
294
397
  constructor(wsClient: WSClient, topic: string);
295
- onMessage(handler: MessageHandler): () => boolean;
296
- onError(handler: ErrorHandler): () => boolean;
297
- onClose(handler: CloseHandler): () => boolean;
398
+ /**
399
+ * Register message handler
400
+ */
401
+ onMessage(handler: MessageHandler): () => void;
402
+ /**
403
+ * Register error handler
404
+ */
405
+ onError(handler: ErrorHandler): () => void;
406
+ /**
407
+ * Register close handler
408
+ */
409
+ onClose(handler: CloseHandler): () => void;
410
+ /**
411
+ * Close subscription and underlying WebSocket
412
+ */
298
413
  close(): void;
414
+ /**
415
+ * Check if subscription is active
416
+ */
299
417
  isConnected(): boolean;
300
418
  }
301
419
 
@@ -305,9 +423,23 @@ interface PeerInfo {
305
423
  lastSeen?: string;
306
424
  }
307
425
  interface NetworkStatus {
308
- healthy: boolean;
309
- peers: number;
310
- uptime?: number;
426
+ node_id: string;
427
+ connected: boolean;
428
+ peer_count: number;
429
+ database_size: number;
430
+ uptime: number;
431
+ }
432
+ interface ProxyRequest {
433
+ url: string;
434
+ method: string;
435
+ headers?: Record<string, string>;
436
+ body?: string;
437
+ }
438
+ interface ProxyResponse {
439
+ status_code: number;
440
+ headers: Record<string, string>;
441
+ body: string;
442
+ error?: string;
311
443
  }
312
444
  declare class NetworkClient {
313
445
  private httpClient;
@@ -332,6 +464,29 @@ declare class NetworkClient {
332
464
  * Disconnect from a peer.
333
465
  */
334
466
  disconnect(peerId: string): Promise<void>;
467
+ /**
468
+ * Proxy an HTTP request through the Anyone network.
469
+ * Requires authentication (API key or JWT).
470
+ *
471
+ * @param request - The proxy request configuration
472
+ * @returns The proxied response
473
+ * @throws {SDKError} If the Anyone proxy is not available or the request fails
474
+ *
475
+ * @example
476
+ * ```ts
477
+ * const response = await client.network.proxyAnon({
478
+ * url: 'https://api.example.com/data',
479
+ * method: 'GET',
480
+ * headers: {
481
+ * 'Accept': 'application/json'
482
+ * }
483
+ * });
484
+ *
485
+ * console.log(response.status_code); // 200
486
+ * console.log(response.body); // Response data
487
+ * ```
488
+ */
489
+ proxyAnon(request: ProxyRequest): Promise<ProxyResponse>;
335
490
  }
336
491
 
337
492
  declare class SDKError extends Error {
@@ -364,4 +519,4 @@ interface Client {
364
519
  }
365
520
  declare function createClient(config: ClientConfig): Client;
366
521
 
367
- export { AuthClient, type AuthConfig, type Client, type ClientConfig, type CloseHandler, type ColumnDefinition, DBClient, type Entity, type ErrorHandler, type FindOptions, HttpClient, LocalStorageAdapter, MemoryStorage, type Message, type MessageHandler, NetworkClient, type NetworkStatus, type PeerInfo, PubSubClient, QueryBuilder, type QueryResponse, Repository, SDKError, type SelectOptions, type StorageAdapter, Subscription, type TransactionOp, type TransactionRequest, WSClient, type WhoAmI, createClient, extractPrimaryKey, extractTableName };
522
+ export { AuthClient, type AuthConfig, type Client, type ClientConfig, type CloseHandler, type ColumnDefinition, DBClient, type Entity, type ErrorHandler, type FindOptions, HttpClient, LocalStorageAdapter, MemoryStorage, type Message, type MessageHandler, NetworkClient, type NetworkStatus, type PeerInfo, type ProxyRequest, type ProxyResponse, PubSubClient, QueryBuilder, type QueryResponse, Repository, SDKError, type SelectOptions, type StorageAdapter, Subscription, type TransactionOp, type TransactionRequest, WSClient, type WhoAmI, createClient, extractPrimaryKey, extractTableName };