@teneo-protocol/sdk 3.1.2 → 3.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/src/teneo-sdk.ts CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  type HealthStatus
23
23
  } from "./types";
24
24
  import { SDKEvents, SDKError } from "./types/events";
25
+ import { CHAIN_ID_TO_NETWORK } from "./payments/networks";
25
26
  import { ErrorCode } from "./types/error-codes";
26
27
  import { WebSocketClient } from "./core/websocket-client";
27
28
  import { WebhookHandler } from "./handlers/webhook-handler";
@@ -46,7 +47,7 @@ import {
46
47
  ListAvailableAgentsOptions,
47
48
  PaginatedAgentsResult
48
49
  } from "./managers";
49
- import { createPinoLogger } from "./utils/logger";
50
+ import { createConsoleLogger } from "./utils/logger";
50
51
  import { RoomIdSchema, AgentIdSchema, AgentCommandContentSchema } from "./types/validation";
51
52
  import { SecurePrivateKey } from "./utils/secure-private-key";
52
53
  import { setNetworkConfigUrl, initializeNetworks } from "./payments";
@@ -1339,11 +1340,15 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
1339
1340
  * Used in response to a "wallet:tx_requested" event after the user
1340
1341
  * has confirmed, rejected, or encountered a failure with the transaction.
1341
1342
  *
1343
+ * The txHash is automatically formatted with the network name (e.g., `0xabc...|base`)
1344
+ * when a chainId is provided, matching the format the UI uses.
1345
+ *
1342
1346
  * @param taskId - The task ID from the wallet:tx_requested event
1343
1347
  * @param status - Transaction result: "confirmed", "rejected", or "failed"
1344
1348
  * @param txHash - The on-chain transaction hash (required for "confirmed" status)
1345
1349
  * @param error - Error message (optional, for "failed" status)
1346
1350
  * @param room - The room ID from the wallet:tx_requested event (required for routing)
1351
+ * @param chainId - The chain ID from data.tx.chainId (used to format txHash with network name)
1347
1352
  * @throws {SDKError} If the SDK has been destroyed or not connected
1348
1353
  *
1349
1354
  * @example
@@ -1351,9 +1356,9 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
1351
1356
  * sdk.on("wallet:tx_requested", async (data) => {
1352
1357
  * try {
1353
1358
  * const txHash = await wallet.sendTransaction(data.tx);
1354
- * await sdk.sendTxResult(data.taskId, "confirmed", txHash, undefined, data.room);
1359
+ * await sdk.sendTxResult(data.taskId, "confirmed", txHash, undefined, data.room, data.tx.chainId);
1355
1360
  * } catch (err) {
1356
- * await sdk.sendTxResult(data.taskId, "failed", undefined, err.message, data.room);
1361
+ * await sdk.sendTxResult(data.taskId, "failed", undefined, err.message, data.room, data.tx.chainId);
1357
1362
  * }
1358
1363
  * });
1359
1364
  * ```
@@ -1363,7 +1368,8 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
1363
1368
  status: "confirmed" | "rejected" | "failed",
1364
1369
  txHash?: string,
1365
1370
  error?: string,
1366
- room?: string
1371
+ room?: string,
1372
+ chainId?: number
1367
1373
  ): Promise<void> {
1368
1374
  if (this.isDestroyed) {
1369
1375
  throw new SDKError("SDK has been destroyed", ErrorCode.SDK_DESTROYED, null, false);
@@ -1373,6 +1379,15 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
1373
1379
  throw new SDKError("Not connected to Teneo Protocol", ErrorCode.NOT_CONNECTED);
1374
1380
  }
1375
1381
 
1382
+ // Format txHash with network name (e.g., "0xabc...|base") to match UI format
1383
+ let formattedTxHash = txHash;
1384
+ if (txHash && chainId) {
1385
+ const networkName = CHAIN_ID_TO_NETWORK[chainId];
1386
+ if (networkName) {
1387
+ formattedTxHash = `${txHash}|${networkName}`;
1388
+ }
1389
+ }
1390
+
1376
1391
  const message = {
1377
1392
  type: "tx_result" as const,
1378
1393
  ...(room && { room }),
@@ -1380,7 +1395,7 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
1380
1395
  data: {
1381
1396
  task_id: taskId,
1382
1397
  status,
1383
- ...(txHash && { tx_hash: txHash }),
1398
+ ...(formattedTxHash && { tx_hash: formattedTxHash }),
1384
1399
  ...(error && { error })
1385
1400
  }
1386
1401
  };
@@ -2017,6 +2032,12 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
2017
2032
  // Emit on SDK for external listeners
2018
2033
  this.emit("room:deleted", roomId);
2019
2034
  });
2035
+ this.wsClient.on("room:list", (rooms) => {
2036
+ // Emit on RoomManager for promise resolution (see listRooms method)
2037
+ this.rooms.emit("room:list", rooms);
2038
+ // Emit on SDK for external listeners
2039
+ this.emit("room:list", rooms);
2040
+ });
2020
2041
  this.wsClient.on("room:create_error", (error) => {
2021
2042
  // Emit on RoomManagementManager for promise rejection
2022
2043
  this.roomManagement.emit("room:create_error", error);
@@ -2155,10 +2176,10 @@ export class TeneoSDK extends EventEmitter<SDKEvents> {
2155
2176
  }
2156
2177
 
2157
2178
  /**
2158
- * Create default logger using pino
2179
+ * Create default console-based logger
2159
2180
  */
2160
2181
  private createDefaultLogger(): Logger {
2161
- return createPinoLogger(this.config.logLevel ?? "info", "TeneoSDK");
2182
+ return createConsoleLogger(this.config.logLevel ?? "info", "TeneoSDK");
2162
2183
  }
2163
2184
 
2164
2185
  /**
@@ -320,6 +320,7 @@ export interface SDKEvents {
320
320
  }) => void;
321
321
 
322
322
  // Room events
323
+ "room:list": (rooms: z.infer<typeof RoomInfoSchema>[]) => void;
323
324
  "room:subscribed": (data: { roomId: string; subscriptions: string[] }) => void;
324
325
  "room:unsubscribed": (data: { roomId: string; subscriptions: string[] }) => void;
325
326
  "room:message": (roomId: string, message: z.infer<typeof BaseMessageSchema>) => void;
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Logger creation utilities
7
7
  */
8
- export { createPinoLogger } from "./logger";
8
+ export { createConsoleLogger, createPinoLogger } from "./logger";
9
9
 
10
10
  /**
11
11
  * SSRF protection utilities for webhook URL validation
@@ -1,14 +1,30 @@
1
1
  /**
2
2
  * Logger utility for Teneo Protocol SDK
3
- * Provides pino-based logging with structured output and optional pretty printing
3
+ * Provides console-based logging with level filtering
4
4
  */
5
5
 
6
- import pino from "pino";
7
6
  import type { Logger, LogLevel } from "../types";
8
7
 
8
+ const LOG_LEVELS: Record<string, number> = {
9
+ debug: 0,
10
+ info: 1,
11
+ warn: 2,
12
+ error: 3,
13
+ silent: 4
14
+ };
15
+
16
+ function formatData(data: unknown): string {
17
+ if (data === undefined || data === null) return "";
18
+ try {
19
+ return " " + JSON.stringify(data, null, 2);
20
+ } catch {
21
+ return " " + String(data);
22
+ }
23
+ }
24
+
9
25
  /**
10
- * Creates a pino-based logger that conforms to the SDK Logger interface.
11
- * Automatically configures pretty printing for development environments.
26
+ * Creates a console-based logger that conforms to the SDK Logger interface.
27
+ * Filters messages below the configured log level.
12
28
  *
13
29
  * @param level - Log level (debug, info, warn, error, silent)
14
30
  * @param name - Logger name for identifying log source (e.g., "TeneoSDK", "WebSocketClient")
@@ -16,72 +32,38 @@ import type { Logger, LogLevel } from "../types";
16
32
  *
17
33
  * @example
18
34
  * ```typescript
19
- * const logger = createPinoLogger('info', 'TeneoSDK');
35
+ * const logger = createConsoleLogger('info', 'TeneoSDK');
20
36
  * logger.info('SDK initialized', { wsUrl: 'wss://example.com' });
21
37
  * logger.error('Connection failed', { code: 'CONN_FAILED', attempt: 3 });
22
38
  * ```
23
39
  */
24
- export function createPinoLogger(level: LogLevel, name?: string): Logger {
25
- // Map 'silent' to pino's 'silent' level
26
- const pinoLevel = level === "silent" ? "silent" : level;
40
+ export function createConsoleLogger(level: LogLevel, name?: string): Logger {
41
+ const threshold = LOG_LEVELS[level] ?? LOG_LEVELS.info;
42
+ const prefix = name ? `[${name}]` : "";
27
43
 
28
- // Create pino logger with optional pretty printing for development
29
- const pinoLogger = pino({
30
- level: pinoLevel,
31
- name: name || "TeneoSDK",
32
- // Use pino-pretty in development for readable logs
33
- transport:
34
- process.env.NODE_ENV !== "production"
35
- ? {
36
- target: "pino-pretty",
37
- options: {
38
- colorize: true,
39
- ignore: "pid,hostname",
40
- translateTime: "HH:MM:ss.l",
41
- singleLine: false
42
- }
43
- }
44
- : undefined,
45
- // Production: fast JSON logs
46
- formatters:
47
- process.env.NODE_ENV === "production"
48
- ? {
49
- level: (label) => {
50
- return { level: label };
51
- }
52
- }
53
- : undefined
54
- });
55
-
56
- // Adapt pino's API to match our Logger interface
57
44
  return {
58
45
  debug: (message: string, data?: unknown) => {
59
- if (data !== undefined) {
60
- pinoLogger.debug(data as object, message);
61
- } else {
62
- pinoLogger.debug(message);
46
+ if (threshold <= LOG_LEVELS.debug) {
47
+ console.debug(`${prefix} ${message}${formatData(data)}`);
63
48
  }
64
49
  },
65
50
  info: (message: string, data?: unknown) => {
66
- if (data !== undefined) {
67
- pinoLogger.info(data as object, message);
68
- } else {
69
- pinoLogger.info(message);
51
+ if (threshold <= LOG_LEVELS.info) {
52
+ console.info(`${prefix} ${message}${formatData(data)}`);
70
53
  }
71
54
  },
72
55
  warn: (message: string, data?: unknown) => {
73
- if (data !== undefined) {
74
- pinoLogger.warn(data as object, message);
75
- } else {
76
- pinoLogger.warn(message);
56
+ if (threshold <= LOG_LEVELS.warn) {
57
+ console.warn(`${prefix} ${message}${formatData(data)}`);
77
58
  }
78
59
  },
79
60
  error: (message: string, data?: unknown) => {
80
- if (data !== undefined) {
81
- pinoLogger.error(data as object, message);
82
- } else {
83
- pinoLogger.error(message);
61
+ if (threshold <= LOG_LEVELS.error) {
62
+ console.error(`${prefix} ${message}${formatData(data)}`);
84
63
  }
85
64
  }
86
65
  };
87
66
  }
67
+
68
+ /** @deprecated Use createConsoleLogger instead */
69
+ export const createPinoLogger = createConsoleLogger;
@@ -7,6 +7,17 @@ import { describe, it, expect, beforeEach, vi } from "vitest";
7
7
  import { TeneoSDK } from "../../src/teneo-sdk";
8
8
  import { ErrorCode } from "../../src/types/error-codes";
9
9
 
10
+ // Mock the networks module so we can control CHAIN_ID_TO_NETWORK
11
+ vi.mock("../../src/payments/networks", async (importOriginal) => {
12
+ const actual = await importOriginal<typeof import("../../src/payments/networks")>();
13
+ return {
14
+ ...actual,
15
+ CHAIN_ID_TO_NETWORK: {} as Record<number, string>,
16
+ };
17
+ });
18
+
19
+ import { CHAIN_ID_TO_NETWORK } from "../../src/payments/networks";
20
+
10
21
  describe("TeneoSDK New Methods", () => {
11
22
  let sdk: TeneoSDK;
12
23
  let sendMessageSpy: ReturnType<typeof vi.fn>;
@@ -156,6 +167,37 @@ describe("TeneoSDK New Methods", () => {
156
167
  });
157
168
  });
158
169
 
170
+ it("should format txHash with network name when chainId is provided", async () => {
171
+ // Populate the chain ID mapping like fetchNetworkConfigs would
172
+ const chainMap = CHAIN_ID_TO_NETWORK as Record<number, string>;
173
+ chainMap[8453] = "base";
174
+ chainMap[43114] = "avalanche";
175
+
176
+ await sdk.sendTxResult("task-100", "confirmed", "0xabc", undefined, "room-abc", 8453);
177
+
178
+ expect(sendMessageSpy).toHaveBeenCalledWith({
179
+ type: "tx_result",
180
+ room: "room-abc",
181
+ timestamp: expect.any(String),
182
+ data: {
183
+ task_id: "task-100",
184
+ status: "confirmed",
185
+ tx_hash: "0xabc|base"
186
+ }
187
+ });
188
+
189
+ // Cleanup
190
+ delete chainMap[8453];
191
+ delete chainMap[43114];
192
+ });
193
+
194
+ it("should send raw txHash when chainId is unknown", async () => {
195
+ await sdk.sendTxResult("task-100", "confirmed", "0xabc", undefined, "room-abc", 99999);
196
+
197
+ const sentMessage = sendMessageSpy.mock.calls[0][0];
198
+ expect(sentMessage.data.tx_hash).toBe("0xabc");
199
+ });
200
+
159
201
  it("should not include room when not provided", async () => {
160
202
  await sdk.sendTxResult("task-100", "rejected");
161
203