@debros/network-ts-sdk 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,826 @@
1
+ // src/errors.ts
2
+ var SDKError = class _SDKError extends Error {
3
+ constructor(message, httpStatus = 500, code = "SDK_ERROR", details = {}) {
4
+ super(message);
5
+ this.name = "SDKError";
6
+ this.httpStatus = httpStatus;
7
+ this.code = code;
8
+ this.details = details;
9
+ }
10
+ static fromResponse(status, body, message) {
11
+ const errorMsg = message || body?.error || `HTTP ${status}`;
12
+ const code = body?.code || `HTTP_${status}`;
13
+ return new _SDKError(errorMsg, status, code, body);
14
+ }
15
+ toJSON() {
16
+ return {
17
+ name: this.name,
18
+ message: this.message,
19
+ httpStatus: this.httpStatus,
20
+ code: this.code,
21
+ details: this.details
22
+ };
23
+ }
24
+ };
25
+
26
+ // src/core/http.ts
27
+ var HttpClient = class {
28
+ constructor(config) {
29
+ this.baseURL = config.baseURL.replace(/\/$/, "");
30
+ this.timeout = config.timeout ?? 3e4;
31
+ this.maxRetries = config.maxRetries ?? 3;
32
+ this.retryDelayMs = config.retryDelayMs ?? 1e3;
33
+ this.fetch = config.fetch ?? globalThis.fetch;
34
+ }
35
+ setApiKey(apiKey) {
36
+ this.apiKey = apiKey;
37
+ this.jwt = void 0;
38
+ }
39
+ setJwt(jwt) {
40
+ this.jwt = jwt;
41
+ this.apiKey = void 0;
42
+ }
43
+ getAuthHeaders() {
44
+ const headers = {};
45
+ if (this.jwt) {
46
+ headers["Authorization"] = `Bearer ${this.jwt}`;
47
+ } else if (this.apiKey) {
48
+ headers["X-API-Key"] = this.apiKey;
49
+ }
50
+ return headers;
51
+ }
52
+ getAuthToken() {
53
+ return this.jwt || this.apiKey;
54
+ }
55
+ async request(method, path, options = {}) {
56
+ const url = new URL(this.baseURL + path);
57
+ if (options.query) {
58
+ Object.entries(options.query).forEach(([key, value]) => {
59
+ url.searchParams.append(key, String(value));
60
+ });
61
+ }
62
+ const headers = {
63
+ "Content-Type": "application/json",
64
+ ...this.getAuthHeaders(),
65
+ ...options.headers
66
+ };
67
+ const fetchOptions = {
68
+ method,
69
+ headers,
70
+ signal: AbortSignal.timeout(this.timeout)
71
+ };
72
+ if (options.body !== void 0) {
73
+ fetchOptions.body = JSON.stringify(options.body);
74
+ }
75
+ return this.requestWithRetry(url.toString(), fetchOptions);
76
+ }
77
+ async requestWithRetry(url, options, attempt = 0) {
78
+ try {
79
+ const response = await this.fetch(url, options);
80
+ if (!response.ok) {
81
+ let body;
82
+ try {
83
+ body = await response.json();
84
+ } catch {
85
+ body = { error: response.statusText };
86
+ }
87
+ throw SDKError.fromResponse(response.status, body);
88
+ }
89
+ const contentType = response.headers.get("content-type");
90
+ if (contentType?.includes("application/json")) {
91
+ return response.json();
92
+ }
93
+ return response.text();
94
+ } catch (error) {
95
+ if (error instanceof SDKError && attempt < this.maxRetries && [408, 429, 500, 502, 503, 504].includes(error.httpStatus)) {
96
+ await new Promise(
97
+ (resolve) => setTimeout(resolve, this.retryDelayMs * (attempt + 1))
98
+ );
99
+ return this.requestWithRetry(url, options, attempt + 1);
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ async get(path, options) {
105
+ return this.request("GET", path, options);
106
+ }
107
+ async post(path, body, options) {
108
+ return this.request("POST", path, { ...options, body });
109
+ }
110
+ async put(path, body, options) {
111
+ return this.request("PUT", path, { ...options, body });
112
+ }
113
+ async delete(path, options) {
114
+ return this.request("DELETE", path, options);
115
+ }
116
+ getToken() {
117
+ return this.getAuthToken();
118
+ }
119
+ };
120
+
121
+ // src/auth/types.ts
122
+ var MemoryStorage = class {
123
+ constructor() {
124
+ this.storage = /* @__PURE__ */ new Map();
125
+ }
126
+ async get(key) {
127
+ return this.storage.get(key) ?? null;
128
+ }
129
+ async set(key, value) {
130
+ this.storage.set(key, value);
131
+ }
132
+ async clear() {
133
+ this.storage.clear();
134
+ }
135
+ };
136
+ var LocalStorageAdapter = class {
137
+ constructor() {
138
+ this.prefix = "@network/sdk:";
139
+ }
140
+ async get(key) {
141
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
142
+ return globalThis.localStorage.getItem(this.prefix + key);
143
+ }
144
+ return null;
145
+ }
146
+ async set(key, value) {
147
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
148
+ globalThis.localStorage.setItem(this.prefix + key, value);
149
+ }
150
+ }
151
+ async clear() {
152
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
153
+ const keysToDelete = [];
154
+ for (let i = 0; i < globalThis.localStorage.length; i++) {
155
+ const key = globalThis.localStorage.key(i);
156
+ if (key?.startsWith(this.prefix)) {
157
+ keysToDelete.push(key);
158
+ }
159
+ }
160
+ keysToDelete.forEach((key) => globalThis.localStorage.removeItem(key));
161
+ }
162
+ }
163
+ };
164
+
165
+ // src/auth/client.ts
166
+ var AuthClient = class {
167
+ constructor(config) {
168
+ this.httpClient = config.httpClient;
169
+ this.storage = config.storage ?? new MemoryStorage();
170
+ this.currentApiKey = config.apiKey;
171
+ this.currentJwt = config.jwt;
172
+ if (this.currentApiKey) {
173
+ this.httpClient.setApiKey(this.currentApiKey);
174
+ }
175
+ if (this.currentJwt) {
176
+ this.httpClient.setJwt(this.currentJwt);
177
+ }
178
+ }
179
+ setApiKey(apiKey) {
180
+ this.currentApiKey = apiKey;
181
+ this.currentJwt = void 0;
182
+ this.httpClient.setApiKey(apiKey);
183
+ this.storage.set("apiKey", apiKey);
184
+ }
185
+ setJwt(jwt) {
186
+ this.currentJwt = jwt;
187
+ this.currentApiKey = void 0;
188
+ this.httpClient.setJwt(jwt);
189
+ this.storage.set("jwt", jwt);
190
+ }
191
+ getToken() {
192
+ return this.httpClient.getToken();
193
+ }
194
+ async whoami() {
195
+ try {
196
+ const response = await this.httpClient.get("/v1/auth/whoami");
197
+ return response;
198
+ } catch {
199
+ return { authenticated: false };
200
+ }
201
+ }
202
+ async refresh() {
203
+ const response = await this.httpClient.post(
204
+ "/v1/auth/refresh"
205
+ );
206
+ const token = response.token;
207
+ this.setJwt(token);
208
+ return token;
209
+ }
210
+ async logout() {
211
+ if (this.currentJwt) {
212
+ try {
213
+ await this.httpClient.post("/v1/auth/logout", { all: true });
214
+ } catch (error) {
215
+ console.warn("Server-side logout failed, continuing with local cleanup:", error);
216
+ }
217
+ }
218
+ this.currentApiKey = void 0;
219
+ this.currentJwt = void 0;
220
+ this.httpClient.setApiKey(void 0);
221
+ this.httpClient.setJwt(void 0);
222
+ await this.storage.clear();
223
+ }
224
+ async clear() {
225
+ this.currentApiKey = void 0;
226
+ this.currentJwt = void 0;
227
+ this.httpClient.setApiKey(void 0);
228
+ this.httpClient.setJwt(void 0);
229
+ await this.storage.clear();
230
+ }
231
+ };
232
+
233
+ // src/db/qb.ts
234
+ var QueryBuilder = class {
235
+ constructor(httpClient, table) {
236
+ this.options = {};
237
+ this.httpClient = httpClient;
238
+ this.table = table;
239
+ }
240
+ select(...columns) {
241
+ this.options.select = columns;
242
+ return this;
243
+ }
244
+ innerJoin(table, on) {
245
+ if (!this.options.joins) this.options.joins = [];
246
+ this.options.joins.push({ kind: "INNER", table, on });
247
+ return this;
248
+ }
249
+ leftJoin(table, on) {
250
+ if (!this.options.joins) this.options.joins = [];
251
+ this.options.joins.push({ kind: "LEFT", table, on });
252
+ return this;
253
+ }
254
+ rightJoin(table, on) {
255
+ if (!this.options.joins) this.options.joins = [];
256
+ this.options.joins.push({ kind: "RIGHT", table, on });
257
+ return this;
258
+ }
259
+ where(expr, args) {
260
+ if (!this.options.where) this.options.where = [];
261
+ this.options.where.push({ conj: "AND", expr, args });
262
+ return this;
263
+ }
264
+ andWhere(expr, args) {
265
+ return this.where(expr, args);
266
+ }
267
+ orWhere(expr, args) {
268
+ if (!this.options.where) this.options.where = [];
269
+ this.options.where.push({ conj: "OR", expr, args });
270
+ return this;
271
+ }
272
+ groupBy(...columns) {
273
+ this.options.group_by = columns;
274
+ return this;
275
+ }
276
+ orderBy(...columns) {
277
+ this.options.order_by = columns;
278
+ return this;
279
+ }
280
+ limit(n) {
281
+ this.options.limit = n;
282
+ return this;
283
+ }
284
+ offset(n) {
285
+ this.options.offset = n;
286
+ return this;
287
+ }
288
+ async getMany(ctx) {
289
+ const response = await this.httpClient.post(
290
+ "/v1/rqlite/select",
291
+ {
292
+ table: this.table,
293
+ ...this.options
294
+ }
295
+ );
296
+ return response.items || [];
297
+ }
298
+ async getOne(ctx) {
299
+ const response = await this.httpClient.post(
300
+ "/v1/rqlite/select",
301
+ {
302
+ table: this.table,
303
+ ...this.options,
304
+ one: true,
305
+ limit: 1
306
+ }
307
+ );
308
+ const items = response.items || [];
309
+ return items.length > 0 ? items[0] : null;
310
+ }
311
+ async count() {
312
+ const response = await this.httpClient.post(
313
+ "/v1/rqlite/select",
314
+ {
315
+ table: this.table,
316
+ select: ["COUNT(*) AS count"],
317
+ where: this.options.where,
318
+ one: true
319
+ }
320
+ );
321
+ const items = response.items || [];
322
+ return items.length > 0 ? items[0].count : 0;
323
+ }
324
+ };
325
+
326
+ // src/db/repository.ts
327
+ var Repository = class {
328
+ constructor(httpClient, tableName, primaryKey = "id") {
329
+ this.httpClient = httpClient;
330
+ this.tableName = tableName;
331
+ this.primaryKey = primaryKey;
332
+ }
333
+ createQueryBuilder() {
334
+ return new QueryBuilder(this.httpClient, this.tableName);
335
+ }
336
+ async find(criteria = {}, options = {}) {
337
+ const response = await this.httpClient.post(
338
+ "/v1/rqlite/find",
339
+ {
340
+ table: this.tableName,
341
+ criteria,
342
+ options
343
+ }
344
+ );
345
+ return response.items || [];
346
+ }
347
+ async findOne(criteria) {
348
+ try {
349
+ const response = await this.httpClient.post(
350
+ "/v1/rqlite/find-one",
351
+ {
352
+ table: this.tableName,
353
+ criteria
354
+ }
355
+ );
356
+ return response;
357
+ } catch (error) {
358
+ if (error instanceof SDKError && error.httpStatus === 404) {
359
+ return null;
360
+ }
361
+ throw error;
362
+ }
363
+ }
364
+ async save(entity) {
365
+ const pkValue = entity[this.primaryKey];
366
+ if (!pkValue) {
367
+ const response = await this.httpClient.post("/v1/rqlite/exec", {
368
+ sql: this.buildInsertSql(entity),
369
+ args: this.buildInsertArgs(entity)
370
+ });
371
+ if (response.last_insert_id) {
372
+ entity[this.primaryKey] = response.last_insert_id;
373
+ }
374
+ return entity;
375
+ } else {
376
+ await this.httpClient.post("/v1/rqlite/exec", {
377
+ sql: this.buildUpdateSql(entity),
378
+ args: this.buildUpdateArgs(entity)
379
+ });
380
+ return entity;
381
+ }
382
+ }
383
+ async remove(entity) {
384
+ const pkValue = entity[this.primaryKey];
385
+ if (!pkValue) {
386
+ throw new SDKError(
387
+ `Primary key "${this.primaryKey}" is required for remove`,
388
+ 400,
389
+ "MISSING_PK"
390
+ );
391
+ }
392
+ await this.httpClient.post("/v1/rqlite/exec", {
393
+ sql: `DELETE FROM ${this.tableName} WHERE ${this.primaryKey} = ?`,
394
+ args: [pkValue]
395
+ });
396
+ }
397
+ buildInsertSql(entity) {
398
+ const columns = Object.keys(entity).filter((k) => entity[k] !== void 0);
399
+ const placeholders = columns.map(() => "?").join(", ");
400
+ return `INSERT INTO ${this.tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
401
+ }
402
+ buildInsertArgs(entity) {
403
+ return Object.entries(entity).filter(([, v]) => v !== void 0).map(([, v]) => v);
404
+ }
405
+ buildUpdateSql(entity) {
406
+ const columns = Object.keys(entity).filter((k) => entity[k] !== void 0 && k !== this.primaryKey).map((k) => `${k} = ?`);
407
+ return `UPDATE ${this.tableName} SET ${columns.join(", ")} WHERE ${this.primaryKey} = ?`;
408
+ }
409
+ buildUpdateArgs(entity) {
410
+ const args = Object.entries(entity).filter(([k, v]) => v !== void 0 && k !== this.primaryKey).map(([, v]) => v);
411
+ args.push(entity[this.primaryKey]);
412
+ return args;
413
+ }
414
+ };
415
+
416
+ // src/db/client.ts
417
+ var DBClient = class {
418
+ constructor(httpClient) {
419
+ this.httpClient = httpClient;
420
+ }
421
+ /**
422
+ * Execute a write/DDL SQL statement.
423
+ */
424
+ async exec(sql, args = []) {
425
+ return this.httpClient.post("/v1/rqlite/exec", { sql, args });
426
+ }
427
+ /**
428
+ * Execute a SELECT query.
429
+ */
430
+ async query(sql, args = []) {
431
+ const response = await this.httpClient.post(
432
+ "/v1/rqlite/query",
433
+ { sql, args }
434
+ );
435
+ return response.items || [];
436
+ }
437
+ /**
438
+ * Find rows with map-based criteria.
439
+ */
440
+ async find(table, criteria = {}, options = {}) {
441
+ const response = await this.httpClient.post(
442
+ "/v1/rqlite/find",
443
+ {
444
+ table,
445
+ criteria,
446
+ options
447
+ }
448
+ );
449
+ return response.items || [];
450
+ }
451
+ /**
452
+ * Find a single row with map-based criteria.
453
+ */
454
+ async findOne(table, criteria) {
455
+ return this.httpClient.post("/v1/rqlite/find-one", {
456
+ table,
457
+ criteria
458
+ });
459
+ }
460
+ /**
461
+ * Create a fluent QueryBuilder for complex SELECT queries.
462
+ */
463
+ createQueryBuilder(table) {
464
+ return new QueryBuilder(this.httpClient, table);
465
+ }
466
+ /**
467
+ * Create a Repository for entity-based operations.
468
+ */
469
+ repository(tableName, primaryKey = "id") {
470
+ return new Repository(this.httpClient, tableName, primaryKey);
471
+ }
472
+ /**
473
+ * Execute multiple operations atomically.
474
+ */
475
+ async transaction(ops, returnResults = true) {
476
+ const response = await this.httpClient.post(
477
+ "/v1/rqlite/transaction",
478
+ {
479
+ ops,
480
+ return_results: returnResults
481
+ }
482
+ );
483
+ return response.results || [];
484
+ }
485
+ /**
486
+ * Create a table from DDL SQL.
487
+ */
488
+ async createTable(schema) {
489
+ await this.httpClient.post("/v1/rqlite/create-table", { schema });
490
+ }
491
+ /**
492
+ * Drop a table.
493
+ */
494
+ async dropTable(table) {
495
+ await this.httpClient.post("/v1/rqlite/drop-table", { table });
496
+ }
497
+ /**
498
+ * Get current database schema.
499
+ */
500
+ async getSchema() {
501
+ return this.httpClient.get("/v1/rqlite/schema");
502
+ }
503
+ };
504
+
505
+ // src/core/ws.ts
506
+ import WebSocket from "isomorphic-ws";
507
+ var WSClient = class {
508
+ constructor(config) {
509
+ this.reconnectAttempts = 0;
510
+ this.messageHandlers = /* @__PURE__ */ new Set();
511
+ this.errorHandlers = /* @__PURE__ */ new Set();
512
+ this.closeHandlers = /* @__PURE__ */ new Set();
513
+ this.isManuallyClosed = false;
514
+ this.url = config.wsURL;
515
+ this.timeout = config.timeout ?? 3e4;
516
+ this.maxReconnectAttempts = config.maxReconnectAttempts ?? 5;
517
+ this.reconnectDelayMs = config.reconnectDelayMs ?? 1e3;
518
+ this.heartbeatIntervalMs = config.heartbeatIntervalMs ?? 3e4;
519
+ this.authMode = config.authMode ?? "header";
520
+ this.authToken = config.authToken;
521
+ this.WebSocketClass = config.WebSocket ?? WebSocket;
522
+ }
523
+ connect() {
524
+ return new Promise((resolve, reject) => {
525
+ try {
526
+ const wsUrl = this.buildWSUrl();
527
+ this.ws = new this.WebSocketClass(wsUrl);
528
+ const timeout = setTimeout(() => {
529
+ this.ws?.close();
530
+ reject(new SDKError("WebSocket connection timeout", 408, "WS_TIMEOUT"));
531
+ }, this.timeout);
532
+ this.ws.addEventListener("open", () => {
533
+ clearTimeout(timeout);
534
+ this.reconnectAttempts = 0;
535
+ this.startHeartbeat();
536
+ resolve();
537
+ });
538
+ this.ws.addEventListener("message", (event) => {
539
+ const msgEvent = event;
540
+ this.messageHandlers.forEach((handler) => handler(msgEvent.data));
541
+ });
542
+ this.ws.addEventListener("error", (event) => {
543
+ clearTimeout(timeout);
544
+ const error = new SDKError(
545
+ "WebSocket error",
546
+ 500,
547
+ "WS_ERROR",
548
+ event
549
+ );
550
+ this.errorHandlers.forEach((handler) => handler(error));
551
+ });
552
+ this.ws.addEventListener("close", () => {
553
+ clearTimeout(timeout);
554
+ this.stopHeartbeat();
555
+ if (!this.isManuallyClosed) {
556
+ this.attemptReconnect();
557
+ } else {
558
+ this.closeHandlers.forEach((handler) => handler());
559
+ }
560
+ });
561
+ } catch (error) {
562
+ reject(error);
563
+ }
564
+ });
565
+ }
566
+ buildWSUrl() {
567
+ let url = this.url;
568
+ if (this.authToken) {
569
+ const separator = url.includes("?") ? "&" : "?";
570
+ const paramName = this.authToken.startsWith("ak_") ? "api_key" : "token";
571
+ url += `${separator}${paramName}=${encodeURIComponent(this.authToken)}`;
572
+ }
573
+ return url;
574
+ }
575
+ startHeartbeat() {
576
+ this.heartbeatInterval = setInterval(() => {
577
+ if (this.ws?.readyState === WebSocket.OPEN) {
578
+ this.ws.send(JSON.stringify({ type: "ping" }));
579
+ }
580
+ }, this.heartbeatIntervalMs);
581
+ }
582
+ stopHeartbeat() {
583
+ if (this.heartbeatInterval) {
584
+ clearInterval(this.heartbeatInterval);
585
+ this.heartbeatInterval = void 0;
586
+ }
587
+ }
588
+ attemptReconnect() {
589
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
590
+ this.reconnectAttempts++;
591
+ const delayMs = this.reconnectDelayMs * this.reconnectAttempts;
592
+ setTimeout(() => {
593
+ this.connect().catch((error) => {
594
+ this.errorHandlers.forEach((handler) => handler(error));
595
+ });
596
+ }, delayMs);
597
+ } else {
598
+ this.closeHandlers.forEach((handler) => handler());
599
+ }
600
+ }
601
+ onMessage(handler) {
602
+ this.messageHandlers.add(handler);
603
+ return () => this.messageHandlers.delete(handler);
604
+ }
605
+ onError(handler) {
606
+ this.errorHandlers.add(handler);
607
+ return () => this.errorHandlers.delete(handler);
608
+ }
609
+ onClose(handler) {
610
+ this.closeHandlers.add(handler);
611
+ return () => this.closeHandlers.delete(handler);
612
+ }
613
+ send(data) {
614
+ if (this.ws?.readyState !== WebSocket.OPEN) {
615
+ throw new SDKError(
616
+ "WebSocket is not connected",
617
+ 500,
618
+ "WS_NOT_CONNECTED"
619
+ );
620
+ }
621
+ this.ws.send(data);
622
+ }
623
+ close() {
624
+ this.isManuallyClosed = true;
625
+ this.stopHeartbeat();
626
+ this.ws?.close();
627
+ }
628
+ isConnected() {
629
+ return this.ws?.readyState === WebSocket.OPEN;
630
+ }
631
+ setAuthToken(token) {
632
+ this.authToken = token;
633
+ }
634
+ };
635
+
636
+ // src/pubsub/client.ts
637
+ var PubSubClient = class {
638
+ constructor(httpClient, wsConfig = {}) {
639
+ this.httpClient = httpClient;
640
+ this.wsConfig = wsConfig;
641
+ }
642
+ /**
643
+ * Publish a message to a topic.
644
+ */
645
+ async publish(topic, data) {
646
+ const dataBase64 = typeof data === "string" ? Buffer.from(data).toString("base64") : Buffer.from(data).toString("base64");
647
+ await this.httpClient.post("/v1/pubsub/publish", {
648
+ topic,
649
+ data_base64: dataBase64
650
+ });
651
+ }
652
+ /**
653
+ * List active topics in the current namespace.
654
+ */
655
+ async topics() {
656
+ const response = await this.httpClient.get(
657
+ "/v1/pubsub/topics"
658
+ );
659
+ return response.topics || [];
660
+ }
661
+ /**
662
+ * Subscribe to a topic via WebSocket.
663
+ * Returns a subscription object with event handlers.
664
+ */
665
+ async subscribe(topic, handlers = {}) {
666
+ const wsUrl = new URL(this.wsConfig.wsURL || "ws://localhost:6001");
667
+ wsUrl.pathname = "/v1/pubsub/ws";
668
+ wsUrl.searchParams.set("topic", topic);
669
+ const wsClient = new WSClient({
670
+ ...this.wsConfig,
671
+ wsURL: wsUrl.toString(),
672
+ authToken: this.httpClient.getToken()
673
+ });
674
+ const subscription = new Subscription(wsClient, topic);
675
+ if (handlers.onMessage) {
676
+ subscription.onMessage(handlers.onMessage);
677
+ }
678
+ if (handlers.onError) {
679
+ subscription.onError(handlers.onError);
680
+ }
681
+ if (handlers.onClose) {
682
+ subscription.onClose(handlers.onClose);
683
+ }
684
+ await wsClient.connect();
685
+ return subscription;
686
+ }
687
+ };
688
+ var Subscription = class {
689
+ constructor(wsClient, topic) {
690
+ this.messageHandlers = /* @__PURE__ */ new Set();
691
+ this.errorHandlers = /* @__PURE__ */ new Set();
692
+ this.closeHandlers = /* @__PURE__ */ new Set();
693
+ this.wsClient = wsClient;
694
+ this.topic = topic;
695
+ this.wsClient.onMessage((data) => {
696
+ try {
697
+ const message = {
698
+ topic: this.topic,
699
+ data,
700
+ timestamp: Date.now()
701
+ };
702
+ this.messageHandlers.forEach((handler) => handler(message));
703
+ } catch (error) {
704
+ this.errorHandlers.forEach(
705
+ (handler) => handler(error instanceof Error ? error : new Error(String(error)))
706
+ );
707
+ }
708
+ });
709
+ this.wsClient.onError((error) => {
710
+ this.errorHandlers.forEach((handler) => handler(error));
711
+ });
712
+ this.wsClient.onClose(() => {
713
+ this.closeHandlers.forEach((handler) => handler());
714
+ });
715
+ }
716
+ onMessage(handler) {
717
+ this.messageHandlers.add(handler);
718
+ return () => this.messageHandlers.delete(handler);
719
+ }
720
+ onError(handler) {
721
+ this.errorHandlers.add(handler);
722
+ return () => this.errorHandlers.delete(handler);
723
+ }
724
+ onClose(handler) {
725
+ this.closeHandlers.add(handler);
726
+ return () => this.closeHandlers.delete(handler);
727
+ }
728
+ close() {
729
+ this.wsClient.close();
730
+ }
731
+ isConnected() {
732
+ return this.wsClient.isConnected();
733
+ }
734
+ };
735
+
736
+ // src/network/client.ts
737
+ var NetworkClient = class {
738
+ constructor(httpClient) {
739
+ this.httpClient = httpClient;
740
+ }
741
+ /**
742
+ * Check gateway health.
743
+ */
744
+ async health() {
745
+ try {
746
+ await this.httpClient.get("/v1/health");
747
+ return true;
748
+ } catch {
749
+ return false;
750
+ }
751
+ }
752
+ /**
753
+ * Get network status.
754
+ */
755
+ async status() {
756
+ const response = await this.httpClient.get("/v1/status");
757
+ return response;
758
+ }
759
+ /**
760
+ * Get connected peers.
761
+ */
762
+ async peers() {
763
+ const response = await this.httpClient.get(
764
+ "/v1/network/peers"
765
+ );
766
+ return response.peers || [];
767
+ }
768
+ /**
769
+ * Connect to a peer.
770
+ */
771
+ async connect(peerAddr) {
772
+ await this.httpClient.post("/v1/network/connect", { peer_addr: peerAddr });
773
+ }
774
+ /**
775
+ * Disconnect from a peer.
776
+ */
777
+ async disconnect(peerId) {
778
+ await this.httpClient.post("/v1/network/disconnect", { peer_id: peerId });
779
+ }
780
+ };
781
+
782
+ // src/index.ts
783
+ function createClient(config) {
784
+ const httpClient = new HttpClient({
785
+ baseURL: config.baseURL,
786
+ timeout: config.timeout,
787
+ maxRetries: config.maxRetries,
788
+ retryDelayMs: config.retryDelayMs,
789
+ fetch: config.fetch
790
+ });
791
+ const auth = new AuthClient({
792
+ httpClient,
793
+ storage: config.storage,
794
+ apiKey: config.apiKey,
795
+ jwt: config.jwt
796
+ });
797
+ const wsURL = config.wsConfig?.wsURL ?? config.baseURL.replace(/^http/, "ws").replace(/\/$/, "");
798
+ const db = new DBClient(httpClient);
799
+ const pubsub = new PubSubClient(httpClient, {
800
+ ...config.wsConfig,
801
+ wsURL
802
+ });
803
+ const network = new NetworkClient(httpClient);
804
+ return {
805
+ auth,
806
+ db,
807
+ pubsub,
808
+ network
809
+ };
810
+ }
811
+ export {
812
+ AuthClient,
813
+ DBClient,
814
+ HttpClient,
815
+ LocalStorageAdapter,
816
+ MemoryStorage,
817
+ NetworkClient,
818
+ PubSubClient,
819
+ QueryBuilder,
820
+ Repository,
821
+ SDKError,
822
+ Subscription,
823
+ WSClient,
824
+ createClient
825
+ };
826
+ //# sourceMappingURL=index.js.map