@0xmonaco/core 0.4.1 → 0.5.0

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.
Files changed (148) hide show
  1. package/README.md +23 -8
  2. package/dist/api/applications/api.d.ts +1 -2
  3. package/dist/api/applications/api.d.ts.map +1 -1
  4. package/dist/api/applications/api.js +1 -2
  5. package/dist/api/applications/api.js.map +1 -1
  6. package/dist/api/applications/index.d.ts +1 -2
  7. package/dist/api/applications/index.d.ts.map +1 -1
  8. package/dist/api/applications/index.js +1 -1
  9. package/dist/api/applications/index.js.map +1 -1
  10. package/dist/api/auth/api.d.ts +1 -1
  11. package/dist/api/auth/api.d.ts.map +1 -1
  12. package/dist/api/auth/api.js +2 -2
  13. package/dist/api/auth/api.js.map +1 -1
  14. package/dist/api/auth/index.d.ts +1 -2
  15. package/dist/api/auth/index.d.ts.map +1 -1
  16. package/dist/api/auth/index.js +1 -1
  17. package/dist/api/auth/index.js.map +1 -1
  18. package/dist/api/base.d.ts +26 -1
  19. package/dist/api/base.d.ts.map +1 -1
  20. package/dist/api/base.js +173 -43
  21. package/dist/api/base.js.map +1 -1
  22. package/dist/api/fees/api.d.ts +1 -1
  23. package/dist/api/fees/api.d.ts.map +1 -1
  24. package/dist/api/fees/api.js +4 -4
  25. package/dist/api/fees/api.js.map +1 -1
  26. package/dist/api/fees/index.d.ts +1 -1
  27. package/dist/api/fees/index.d.ts.map +1 -1
  28. package/dist/api/fees/index.js +1 -1
  29. package/dist/api/fees/index.js.map +1 -1
  30. package/dist/api/index.d.ts +10 -8
  31. package/dist/api/index.d.ts.map +1 -1
  32. package/dist/api/index.js +10 -8
  33. package/dist/api/index.js.map +1 -1
  34. package/dist/api/market/api.d.ts +1 -1
  35. package/dist/api/market/api.d.ts.map +1 -1
  36. package/dist/api/market/api.js +12 -3
  37. package/dist/api/market/api.js.map +1 -1
  38. package/dist/api/market/index.d.ts +1 -2
  39. package/dist/api/market/index.d.ts.map +1 -1
  40. package/dist/api/market/index.js +1 -1
  41. package/dist/api/market/index.js.map +1 -1
  42. package/dist/api/orderbook/api.d.ts +16 -0
  43. package/dist/api/orderbook/api.d.ts.map +1 -0
  44. package/dist/api/orderbook/api.js +38 -0
  45. package/dist/api/orderbook/api.js.map +1 -0
  46. package/dist/api/orderbook/index.d.ts +2 -0
  47. package/dist/api/orderbook/index.d.ts.map +1 -0
  48. package/dist/api/orderbook/index.js +2 -0
  49. package/dist/api/orderbook/index.js.map +1 -0
  50. package/dist/api/profile/api.d.ts +10 -11
  51. package/dist/api/profile/api.d.ts.map +1 -1
  52. package/dist/api/profile/api.js +17 -11
  53. package/dist/api/profile/api.js.map +1 -1
  54. package/dist/api/profile/index.d.ts +1 -1
  55. package/dist/api/profile/index.d.ts.map +1 -1
  56. package/dist/api/profile/index.js +1 -1
  57. package/dist/api/profile/index.js.map +1 -1
  58. package/dist/api/trades/api.d.ts +45 -0
  59. package/dist/api/trades/api.d.ts.map +1 -0
  60. package/dist/api/trades/api.js +43 -0
  61. package/dist/api/trades/api.js.map +1 -0
  62. package/dist/api/trades/index.d.ts +2 -0
  63. package/dist/api/trades/index.d.ts.map +1 -0
  64. package/dist/api/trades/index.js +2 -0
  65. package/dist/api/trades/index.js.map +1 -0
  66. package/dist/api/trading/api.d.ts +1 -2
  67. package/dist/api/trading/api.d.ts.map +1 -1
  68. package/dist/api/trading/api.js +10 -2
  69. package/dist/api/trading/api.js.map +1 -1
  70. package/dist/api/trading/index.d.ts +1 -2
  71. package/dist/api/trading/index.d.ts.map +1 -1
  72. package/dist/api/trading/index.js +1 -1
  73. package/dist/api/trading/index.js.map +1 -1
  74. package/dist/api/vault/api.d.ts +17 -19
  75. package/dist/api/vault/api.d.ts.map +1 -1
  76. package/dist/api/vault/api.js +58 -46
  77. package/dist/api/vault/api.js.map +1 -1
  78. package/dist/api/vault/index.d.ts +1 -2
  79. package/dist/api/vault/index.d.ts.map +1 -1
  80. package/dist/api/vault/index.js +1 -1
  81. package/dist/api/vault/index.js.map +1 -1
  82. package/dist/api/websocket/index.d.ts +3 -9
  83. package/dist/api/websocket/index.d.ts.map +1 -1
  84. package/dist/api/websocket/index.js +3 -9
  85. package/dist/api/websocket/index.js.map +1 -1
  86. package/dist/api/websocket/types.d.ts +34 -0
  87. package/dist/api/websocket/types.d.ts.map +1 -0
  88. package/dist/api/websocket/types.js +2 -0
  89. package/dist/api/websocket/types.js.map +1 -0
  90. package/dist/api/websocket/utils.d.ts +9 -0
  91. package/dist/api/websocket/utils.d.ts.map +1 -0
  92. package/dist/api/websocket/utils.js +23 -0
  93. package/dist/api/websocket/utils.js.map +1 -0
  94. package/dist/api/websocket/websocket.d.ts +6 -0
  95. package/dist/api/websocket/websocket.d.ts.map +1 -0
  96. package/dist/api/websocket/websocket.js +309 -0
  97. package/dist/api/websocket/websocket.js.map +1 -0
  98. package/dist/errors/errors.d.ts +382 -0
  99. package/dist/errors/errors.d.ts.map +1 -0
  100. package/dist/errors/errors.js +801 -0
  101. package/dist/errors/errors.js.map +1 -0
  102. package/dist/errors/index.d.ts +2 -0
  103. package/dist/errors/index.d.ts.map +1 -0
  104. package/dist/errors/index.js +2 -0
  105. package/dist/errors/index.js.map +1 -0
  106. package/dist/index.d.ts +5 -11
  107. package/dist/index.d.ts.map +1 -1
  108. package/dist/index.js +5 -22
  109. package/dist/index.js.map +1 -1
  110. package/dist/networks/index.d.ts +2 -0
  111. package/dist/networks/index.d.ts.map +1 -0
  112. package/dist/networks/index.js +2 -0
  113. package/dist/networks/index.js.map +1 -0
  114. package/dist/{networks.d.ts → networks/networks.d.ts} +1 -1
  115. package/dist/networks/networks.d.ts.map +1 -0
  116. package/dist/{networks.js → networks/networks.js} +4 -3
  117. package/dist/networks/networks.js.map +1 -0
  118. package/dist/sdk.d.ts +19 -27
  119. package/dist/sdk.d.ts.map +1 -1
  120. package/dist/sdk.js +77 -107
  121. package/dist/sdk.js.map +1 -1
  122. package/dist/utils/index.d.ts +1 -1
  123. package/dist/utils/index.d.ts.map +1 -1
  124. package/dist/utils/index.js +1 -1
  125. package/dist/utils/index.js.map +1 -1
  126. package/package.json +5 -7
  127. package/dist/api/websocket/base-ws-client.d.ts +0 -85
  128. package/dist/api/websocket/base-ws-client.d.ts.map +0 -1
  129. package/dist/api/websocket/base-ws-client.js +0 -256
  130. package/dist/api/websocket/base-ws-client.js.map +0 -1
  131. package/dist/api/websocket/clients/ohlcv-ws-client.d.ts +0 -57
  132. package/dist/api/websocket/clients/ohlcv-ws-client.d.ts.map +0 -1
  133. package/dist/api/websocket/clients/ohlcv-ws-client.js +0 -132
  134. package/dist/api/websocket/clients/ohlcv-ws-client.js.map +0 -1
  135. package/dist/api/websocket/clients/orderbook-ws-client.d.ts +0 -70
  136. package/dist/api/websocket/clients/orderbook-ws-client.d.ts.map +0 -1
  137. package/dist/api/websocket/clients/orderbook-ws-client.js +0 -197
  138. package/dist/api/websocket/clients/orderbook-ws-client.js.map +0 -1
  139. package/dist/api/websocket/clients/orders-ws-client.d.ts +0 -61
  140. package/dist/api/websocket/clients/orders-ws-client.d.ts.map +0 -1
  141. package/dist/api/websocket/clients/orders-ws-client.js +0 -150
  142. package/dist/api/websocket/clients/orders-ws-client.js.map +0 -1
  143. package/dist/errors.d.ts +0 -103
  144. package/dist/errors.d.ts.map +0 -1
  145. package/dist/errors.js +0 -108
  146. package/dist/errors.js.map +0 -1
  147. package/dist/networks.d.ts.map +0 -1
  148. package/dist/networks.js.map +0 -1
@@ -0,0 +1,801 @@
1
+ /**
2
+ * Monaco SDK Error Types
3
+ *
4
+ * Standardized error classes for SDK operations with built-in sensitive data sanitization.
5
+ * All error classes inherit from MonacoCoreError and provide structured error information
6
+ * with automatic suggestions for common failure scenarios.
7
+ *
8
+ * @module errors
9
+ */
10
+ import { StatusCodes } from "http-status-codes";
11
+ /**
12
+ * Sensitive field names that should be redacted in error logs.
13
+ *
14
+ * When errors are serialized (via toJSON()) and sent to external monitoring services
15
+ * like Sentry, Datadog, or CloudWatch, these fields will be replaced with "[REDACTED]"
16
+ * to prevent exposure of sensitive information.
17
+ *
18
+ * Categories:
19
+ * - Authentication & Authorization: tokens, API keys, secrets
20
+ * - User PII: emails, phone numbers, addresses
21
+ * - Security credentials: private keys, mnemonics, signatures
22
+ * - Session data: cookies, session IDs
23
+ *
24
+ * @constant
25
+ */
26
+ const SENSITIVE_FIELDS = [
27
+ // Authentication & Authorization
28
+ "token",
29
+ "accessToken",
30
+ "access_token",
31
+ "refreshToken",
32
+ "refresh_token",
33
+ "authToken",
34
+ "auth_token",
35
+ "bearerToken",
36
+ "bearer_token",
37
+ "jwtToken",
38
+ "jwt_token",
39
+ "apiKey",
40
+ "api_key",
41
+ "apikey",
42
+ "clientSecret",
43
+ "client_secret",
44
+ "clientId",
45
+ "client_id",
46
+ "secret",
47
+ "password",
48
+ "authorization",
49
+ "bearer",
50
+ "auth",
51
+ "credentials",
52
+ "credential",
53
+ // User PII
54
+ "email",
55
+ "phone",
56
+ "phoneNumber",
57
+ "phone_number",
58
+ "ssn",
59
+ "socialSecurity",
60
+ "social_security",
61
+ "address",
62
+ "passport",
63
+ "passportNumber",
64
+ "passport_number",
65
+ "driversLicense",
66
+ "drivers_license",
67
+ // Financial
68
+ "cardNumber",
69
+ "card_number",
70
+ "creditCard",
71
+ "credit_card",
72
+ "cvv",
73
+ "pin",
74
+ // Security & Crypto
75
+ "signature",
76
+ "privateKey",
77
+ "private_key",
78
+ "publicKey",
79
+ "public_key",
80
+ "mnemonic",
81
+ "seed",
82
+ "salt",
83
+ "hash",
84
+ "certificate",
85
+ "cert",
86
+ "fingerprint",
87
+ // Session & Cookies
88
+ "cookie",
89
+ "session",
90
+ "sessionId",
91
+ "session_id",
92
+ "sessionToken",
93
+ "session_token",
94
+ // Network & Device
95
+ "ipAddress",
96
+ "ip_address",
97
+ "deviceId",
98
+ "device_id",
99
+ "userId",
100
+ "user_id",
101
+ "accountId",
102
+ "account_id",
103
+ ];
104
+ /**
105
+ * Sanitize data by redacting sensitive fields and limiting size.
106
+ *
107
+ * Recursively processes data structures to protect sensitive information while
108
+ * preserving debugging utility. Used by error classes when serializing to JSON.
109
+ *
110
+ * **Protections applied:**
111
+ * - Redacts sensitive fields (tokens, passwords, PII, etc.)
112
+ * - Truncates long strings (500 chars for object values, 1000 for standalone)
113
+ * - Limits array size (10 items max, then "... N more items")
114
+ * - Prevents infinite recursion (max depth: 5)
115
+ *
116
+ * **Examples:**
117
+ * ```typescript
118
+ * sanitizeData({ token: "secret", name: "John" })
119
+ * // → { token: "[REDACTED]", name: "John" }
120
+ *
121
+ * sanitizeData(["a".repeat(1000)])
122
+ * // → ["aaa... [truncated]"]
123
+ *
124
+ * sanitizeData({ nested: { deep: { ... } } }, 2)
125
+ * // → { nested: { deep: "[Max depth reached]" } }
126
+ * ```
127
+ *
128
+ * @param data - Data to sanitize (any type)
129
+ * @param maxDepth - Maximum recursion depth to prevent infinite loops (default: 5)
130
+ * @param currentDepth - Internal parameter tracking current recursion level
131
+ * @returns Sanitized data safe for logging to external services
132
+ */
133
+ function sanitizeData(data, maxDepth = 5, currentDepth = 0) {
134
+ // Prevent infinite recursion
135
+ if (currentDepth >= maxDepth) {
136
+ return "[Max depth reached]";
137
+ }
138
+ // Handle null/undefined
139
+ if (data === null || data === undefined) {
140
+ return data;
141
+ }
142
+ // Handle arrays
143
+ if (Array.isArray(data)) {
144
+ // Limit array size to prevent huge logs
145
+ const limit = 10;
146
+ const sanitized = data.slice(0, limit).map((item) => sanitizeData(item, maxDepth, currentDepth + 1));
147
+ if (data.length > limit) {
148
+ sanitized.push(`[... ${data.length - limit} more items]`);
149
+ }
150
+ return sanitized;
151
+ }
152
+ // Handle objects
153
+ if (typeof data === "object") {
154
+ const sanitized = {};
155
+ for (const [key, value] of Object.entries(data)) {
156
+ const lowerKey = key.toLowerCase();
157
+ // Check if field is sensitive
158
+ const isSensitive = SENSITIVE_FIELDS.some((field) => lowerKey.includes(field.toLowerCase()));
159
+ if (isSensitive) {
160
+ sanitized[key] = "[REDACTED]";
161
+ }
162
+ else if (typeof value === "string" && value.length > 500) {
163
+ // Truncate long strings to prevent huge logs
164
+ sanitized[key] = value.substring(0, 500) + "... [truncated]";
165
+ }
166
+ else {
167
+ sanitized[key] = sanitizeData(value, maxDepth, currentDepth + 1);
168
+ }
169
+ }
170
+ return sanitized;
171
+ }
172
+ // Handle strings
173
+ if (typeof data === "string") {
174
+ // Truncate long strings
175
+ if (data.length > 1000) {
176
+ return data.substring(0, 1000) + "... [truncated]";
177
+ }
178
+ return data;
179
+ }
180
+ // Primitives (numbers, booleans) pass through
181
+ return data;
182
+ }
183
+ /**
184
+ * Monaco Core SDK error codes.
185
+ *
186
+ * Categorized error codes for better error handling and debugging.
187
+ * Each error class uses one of these codes to identify the error type.
188
+ *
189
+ * **Categories:**
190
+ *
191
+ * **Initialization Errors** (Configuration and setup):
192
+ * - `INITIALIZATION_ERROR`: General initialization failure
193
+ * - `INVALID_CONFIG`: Invalid SDK configuration (missing/wrong parameters)
194
+ * - `INVALID_STATE`: Invalid SDK state (operation called at wrong time)
195
+ * - `UNSUPPORTED_NETWORK`: Network not supported by SDK
196
+ *
197
+ * **API Errors** (External communication):
198
+ * - `API_ERROR`: API request failed (HTTP errors, network issues)
199
+ * - `CONTRACT_ERROR`: Smart contract interaction failure
200
+ * - `TRANSACTION_ERROR`: Blockchain transaction failure
201
+ *
202
+ * **Order Errors** (Trading operations):
203
+ * - `ORDER_ERROR`: General order operation failure
204
+ * - `INVALID_ORDER`: Order validation failure (invalid parameters)
205
+ * - `ORDER_NOT_FOUND`: Order does not exist
206
+ * - `INSUFFICIENT_BALANCE`: Insufficient token balance for operation
207
+ *
208
+ * **Event Errors** (WebSocket and subscriptions):
209
+ * - `EVENT_ERROR`: General event handling failure
210
+ * - `SUBSCRIPTION_ERROR`: Event subscription failure
211
+ *
212
+ * @example
213
+ * ```typescript
214
+ * try {
215
+ * await sdk.someOperation();
216
+ * } catch (error) {
217
+ * if (error.code === ERROR_CODES.INVALID_CONFIG) {
218
+ * // Handle configuration error
219
+ * } else if (error.code === ERROR_CODES.API_ERROR) {
220
+ * // Handle API error
221
+ * }
222
+ * }
223
+ * ```
224
+ *
225
+ * @constant
226
+ */
227
+ export const ERROR_CODES = {
228
+ /** Initialization errors */
229
+ INITIALIZATION_ERROR: "INITIALIZATION_ERROR",
230
+ INVALID_CONFIG: "INVALID_CONFIG",
231
+ INVALID_STATE: "INVALID_STATE",
232
+ UNSUPPORTED_NETWORK: "UNSUPPORTED_NETWORK",
233
+ /** API errors */
234
+ API_ERROR: "API_ERROR",
235
+ CONTRACT_ERROR: "CONTRACT_ERROR",
236
+ TRANSACTION_ERROR: "TRANSACTION_ERROR",
237
+ /** Order errors */
238
+ ORDER_ERROR: "ORDER_ERROR",
239
+ INVALID_ORDER: "INVALID_ORDER",
240
+ ORDER_NOT_FOUND: "ORDER_NOT_FOUND",
241
+ INSUFFICIENT_BALANCE: "INSUFFICIENT_BALANCE",
242
+ /** Event errors */
243
+ EVENT_ERROR: "EVENT_ERROR",
244
+ SUBSCRIPTION_ERROR: "SUBSCRIPTION_ERROR",
245
+ };
246
+ /**
247
+ * Base class for all Monaco SDK errors.
248
+ *
249
+ * Provides common error functionality including:
250
+ * - Structured error codes for programmatic handling
251
+ * - Automatic recovery suggestions based on error context
252
+ * - Retryability indication for automatic retry logic
253
+ * - Timestamps for error tracking
254
+ * - JSON serialization for logging to external services
255
+ * - Cause chain support for error wrapping
256
+ *
257
+ * All SDK errors inherit from this class and provide specific error details.
258
+ *
259
+ * **Common Properties:**
260
+ * - `code`: MonacoErrorCode - Categorized error identifier
261
+ * - `message`: string - Human-readable error description
262
+ * - `suggestion`: string | undefined - Actionable recovery steps
263
+ * - `retryable`: boolean - Whether the operation can be retried
264
+ * - `timestamp`: number - Unix timestamp when error occurred
265
+ * - `cause`: unknown - Original error that caused this error (if wrapped)
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * try {
270
+ * await sdk.someOperation();
271
+ * } catch (error) {
272
+ * if (error instanceof MonacoCoreError) {
273
+ * console.log(`Error: ${error.message}`);
274
+ * console.log(`Code: ${error.code}`);
275
+ * console.log(`Suggestion: ${error.suggestion}`);
276
+ * console.log(`Can retry: ${error.retryable}`);
277
+ *
278
+ * // Send to monitoring service
279
+ * logger.error(error.toJSON());
280
+ * }
281
+ * }
282
+ * ```
283
+ *
284
+ * @abstract
285
+ */
286
+ export class MonacoCoreError extends Error {
287
+ constructor(message, options) {
288
+ super(message);
289
+ this.retryable = false;
290
+ this.name = this.constructor.name;
291
+ this.timestamp = Date.now();
292
+ if (options?.cause) {
293
+ this.cause = options.cause;
294
+ }
295
+ if (options?.suggestion) {
296
+ this.suggestion = options.suggestion;
297
+ }
298
+ if (options?.retryable !== undefined) {
299
+ this.retryable = options.retryable;
300
+ }
301
+ }
302
+ /**
303
+ * Serialize error to JSON for logging/reporting
304
+ */
305
+ toJSON() {
306
+ return {
307
+ name: this.name,
308
+ code: this.code,
309
+ message: this.message,
310
+ suggestion: this.suggestion,
311
+ retryable: this.retryable,
312
+ timestamp: this.timestamp,
313
+ cause: this.cause instanceof Error ? this.cause.message : this.cause,
314
+ };
315
+ }
316
+ }
317
+ /**
318
+ * Error thrown when SDK is initialized or configured incorrectly.
319
+ *
320
+ * Indicates invalid or missing configuration parameters that prevent
321
+ * the SDK from initializing or operating correctly. Includes automatic
322
+ * suggestions for common configuration fields.
323
+ *
324
+ * **Additional Properties:**
325
+ * - `field`: string | undefined - The configuration field that's invalid
326
+ * - `value`: unknown - The invalid value provided (sanitized in toJSON)
327
+ *
328
+ * **Common Causes:**
329
+ * - Missing required parameters (walletClient, seiRpcUrl, wsUrl)
330
+ * - Invalid URL formats
331
+ * - Unsupported network values
332
+ * - Wallet client chain mismatch
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * // Missing required field
337
+ * throw new InvalidConfigError(
338
+ * "Wallet client is required",
339
+ * "walletClient"
340
+ * );
341
+ *
342
+ * // Invalid value
343
+ * throw new InvalidConfigError(
344
+ * "Invalid URL format",
345
+ * "seiRpcUrl",
346
+ * "not-a-url"
347
+ * );
348
+ *
349
+ * // With cause
350
+ * try {
351
+ * new URL(config.wsUrl);
352
+ * } catch (error) {
353
+ * throw new InvalidConfigError(
354
+ * "wsUrl must be a valid URL",
355
+ * "wsUrl",
356
+ * config.wsUrl,
357
+ * error
358
+ * );
359
+ * }
360
+ * ```
361
+ */
362
+ export class InvalidConfigError extends MonacoCoreError {
363
+ constructor(message, field, value, cause) {
364
+ const suggestion = field
365
+ ? `Check the '${field}' configuration parameter. ${getSuggestionForConfigField(field)}`
366
+ : "Review your SDK configuration and ensure all required fields are provided correctly.";
367
+ super(message, { cause, suggestion, retryable: false });
368
+ this.code = "INVALID_CONFIG";
369
+ this.field = field;
370
+ this.value = value;
371
+ }
372
+ toJSON() {
373
+ // Sanitize value based on field name - if the field is sensitive, redact the value
374
+ let sanitizedValue;
375
+ if (this.field) {
376
+ const lowerField = this.field.toLowerCase();
377
+ const isSensitive = SENSITIVE_FIELDS.some((sensitive) => lowerField.includes(sensitive.toLowerCase()));
378
+ if (isSensitive) {
379
+ sanitizedValue = "[REDACTED]";
380
+ }
381
+ else {
382
+ // Still sanitize the value in case it's an object with sensitive fields
383
+ sanitizedValue = sanitizeData(this.value);
384
+ }
385
+ }
386
+ else {
387
+ sanitizedValue = sanitizeData(this.value);
388
+ }
389
+ return {
390
+ ...super.toJSON(),
391
+ field: this.field,
392
+ value: sanitizedValue,
393
+ };
394
+ }
395
+ }
396
+ /**
397
+ * Get field-specific suggestions for common configuration parameters.
398
+ *
399
+ * Provides actionable guidance for fixing invalid configuration values.
400
+ * Used by InvalidConfigError to generate context-aware suggestions.
401
+ *
402
+ * **Supported Fields:**
403
+ * - `walletClient`: Wallet creation and account configuration
404
+ * - `seiRpcUrl`: RPC endpoint URLs for testnet/mainnet
405
+ * - `wsUrl`: WebSocket endpoint URLs
406
+ * - `network`: Valid network presets and custom URLs
407
+ * - `*` (default): Generic configuration documentation link
408
+ *
409
+ * @param field - Configuration field name (case-insensitive)
410
+ * @returns Specific suggestion string for the field
411
+ * @internal
412
+ */
413
+ function getSuggestionForConfigField(field) {
414
+ switch (field.toLowerCase()) {
415
+ case "walletclient":
416
+ return "Ensure you're creating the wallet client with a valid account and chain configuration.";
417
+ case "seirpcurl":
418
+ return "Use 'https://evm-rpc-testnet.sei-apis.com' for testnet or 'https://evm-rpc.sei-apis.com' for mainnet.";
419
+ case "wsurl":
420
+ return "Use 'wss://development.apimonaco.xyz/ws' for testnet or 'wss://api.monaco.xyz/ws' for mainnet.";
421
+ case "network":
422
+ return "Valid networks are: 'mainnet', 'testnet', 'local', 'staging', or a custom API URL.";
423
+ default:
424
+ return "Refer to the SDK documentation for correct configuration format.";
425
+ }
426
+ }
427
+ /**
428
+ * Error thrown when an operation is called in an invalid SDK state.
429
+ *
430
+ * Indicates that a method was called at the wrong time or when prerequisites
431
+ * weren't met. Includes state transition information when available.
432
+ *
433
+ * **Additional Properties:**
434
+ * - `currentState`: string | undefined - The current state of the SDK
435
+ * - `expectedState`: string | undefined - The state required for this operation
436
+ *
437
+ * **Common Causes:**
438
+ * - Calling authenticated methods before login
439
+ * - Calling methods after logout/disconnect
440
+ * - Operation sequence violations
441
+ *
442
+ * @example
443
+ * ```typescript
444
+ * // With state information
445
+ * throw new InvalidStateError(
446
+ * "Cannot place orders while disconnected",
447
+ * "disconnected",
448
+ * "connected"
449
+ * );
450
+ * // Suggestion: "Current state is 'disconnected', Expected state is 'connected'. Ensure operations are performed in the correct order."
451
+ *
452
+ * // Without state information
453
+ * throw new InvalidStateError(
454
+ * "Prerequisites not met"
455
+ * );
456
+ * // Suggestion: "Check that prerequisites are met before calling this method."
457
+ * ```
458
+ */
459
+ export class InvalidStateError extends MonacoCoreError {
460
+ constructor(message, currentState, expectedState, cause) {
461
+ const suggestion = expectedState
462
+ ? `${currentState ? `Current state is '${currentState}', ` : ""}Expected state is '${expectedState}'. Ensure operations are performed in the correct order.`
463
+ : "Check that prerequisites are met before calling this method.";
464
+ super(message, { cause, suggestion, retryable: false });
465
+ this.code = "INVALID_STATE";
466
+ this.currentState = currentState;
467
+ this.expectedState = expectedState;
468
+ }
469
+ toJSON() {
470
+ return {
471
+ ...super.toJSON(),
472
+ currentState: this.currentState,
473
+ expectedState: this.expectedState,
474
+ };
475
+ }
476
+ }
477
+ /**
478
+ * Error thrown when an API request fails.
479
+ *
480
+ * Represents failures in HTTP/API communication including network errors,
481
+ * server errors, validation failures, and rate limiting. Automatically
482
+ * determines retry-ability and provides context-aware recovery suggestions.
483
+ *
484
+ * **Additional Properties:**
485
+ * - `endpoint`: string | undefined - The API endpoint that failed
486
+ * - `statusCode`: number | undefined - HTTP status code (undefined for network errors)
487
+ * - `responseBody`: unknown - Response body from the API (sanitized in toJSON)
488
+ * - `requestBody`: unknown - Request body sent to the API (sanitized in toJSON)
489
+ * - `requestId`: string | undefined - Request ID from X-Request-ID header
490
+ * - `retryAfter`: number | undefined - Retry-After header value in seconds
491
+ *
492
+ * **Common Status Codes:**
493
+ * - `undefined`: Network error (connection failed, timeout, DNS error)
494
+ * - `400`: Bad request (validation failed, invalid parameters)
495
+ * - `401`: Unauthorized (missing or expired token)
496
+ * - `403`: Forbidden (insufficient permissions)
497
+ * - `404`: Not found (resource doesn't exist)
498
+ * - `429`: Rate limit exceeded
499
+ * - `500+`: Server error
500
+ *
501
+ * **Retryability:**
502
+ * - ✅ Retryable: Network errors, 429, 500+, 409
503
+ * - ❌ Not retryable: 400, 401, 403, 404, and most client errors
504
+ *
505
+ * @example
506
+ * ```typescript
507
+ * // Network error (no response)
508
+ * throw new APIError("Network request failed", {
509
+ * endpoint: "/api/orders",
510
+ * cause: new Error("ECONNREFUSED")
511
+ * });
512
+ *
513
+ * // API validation error
514
+ * throw new APIError("Invalid order parameters", {
515
+ * endpoint: "/api/orders",
516
+ * statusCode: 400,
517
+ * responseBody: { error: "Price must be positive" },
518
+ * requestBody: { price: -10 }
519
+ * });
520
+ *
521
+ * // Rate limit with retry-after
522
+ * throw new APIError("Rate limit exceeded", {
523
+ * endpoint: "/api/orders",
524
+ * statusCode: 429,
525
+ * requestId: "req_abc123",
526
+ * retryAfter: 60
527
+ * });
528
+ *
529
+ * // Check if retryable
530
+ * try {
531
+ * await sdk.someOperation();
532
+ * } catch (error) {
533
+ * if (error instanceof APIError && error.retryable) {
534
+ * // Implement retry logic
535
+ * await delay(error.retryAfter || 5);
536
+ * await sdk.someOperation();
537
+ * }
538
+ * }
539
+ * ```
540
+ */
541
+ export class APIError extends MonacoCoreError {
542
+ constructor(message, options) {
543
+ // Determine suggestion and retryability based on status code
544
+ const { suggestion, retryable } = getErrorSuggestion(options?.statusCode, message, options?.responseBody);
545
+ super(message, { cause: options?.cause, suggestion, retryable });
546
+ this.code = "API_ERROR";
547
+ this.endpoint = options?.endpoint;
548
+ this.statusCode = options?.statusCode;
549
+ this.responseBody = options?.responseBody;
550
+ this.requestBody = options?.requestBody;
551
+ this.requestId = options?.requestId;
552
+ this.retryAfter = options?.retryAfter;
553
+ }
554
+ /**
555
+ * Override toJSON to include API-specific fields with sanitization
556
+ *
557
+ * Sanitizes requestBody and responseBody to prevent sensitive data exposure
558
+ * when errors are logged to external monitoring services.
559
+ */
560
+ toJSON() {
561
+ return {
562
+ ...super.toJSON(),
563
+ endpoint: this.endpoint,
564
+ statusCode: this.statusCode,
565
+ responseBody: sanitizeData(this.responseBody),
566
+ requestBody: sanitizeData(this.requestBody),
567
+ requestId: this.requestId,
568
+ retryAfter: this.retryAfter,
569
+ };
570
+ }
571
+ }
572
+ /**
573
+ * Generate helpful error suggestions and determine retryability based on HTTP status codes.
574
+ *
575
+ * Analyzes API errors to provide actionable recovery suggestions and indicate whether
576
+ * the operation can be safely retried. Used automatically by APIError constructor.
577
+ *
578
+ * **Status Code Precedence** (checked in this order):
579
+ * 1. No status code (network errors) → retryable
580
+ * 2. 401 Unauthorized → check for token expiration, not retryable
581
+ * 3. 403 Forbidden → permission issue, not retryable
582
+ * 4. 404 Not Found → resource missing, not retryable
583
+ * 5. 409 Conflict → resource conflict, retryable
584
+ * 6. 400 Bad Request → check for specific issues (balance, validation), not retryable
585
+ * 7. 429 Too Many Requests → rate limit, retryable with backoff
586
+ * 8. 500-599 Server Errors → retryable (explicit range check)
587
+ * 9. Default → not retryable
588
+ *
589
+ * **Examples:**
590
+ * ```typescript
591
+ * getErrorSuggestion(401, "Token expired")
592
+ * // → {
593
+ * // suggestion: "Access token has expired. Call sdk.refreshAuth()...",
594
+ * // retryable: false
595
+ * // }
596
+ *
597
+ * getErrorSuggestion(429, "Rate limit", { retry_after: 60 })
598
+ * // → {
599
+ * // suggestion: "Rate limit exceeded. Wait 60 seconds before retrying...",
600
+ * // retryable: true
601
+ * // }
602
+ *
603
+ * getErrorSuggestion(undefined, "Network failed")
604
+ * // → {
605
+ * // suggestion: "Network request failed. Check your internet connection...",
606
+ * // retryable: true
607
+ * // }
608
+ * ```
609
+ *
610
+ * @param statusCode - HTTP status code from the failed request (undefined for network errors)
611
+ * @param message - Error message from the API or network layer
612
+ * @param responseBody - Response body from the API (may contain retry_after, etc.)
613
+ * @returns Object with suggestion string and retryable boolean
614
+ * @internal
615
+ */
616
+ function getErrorSuggestion(statusCode, message, responseBody) {
617
+ // Network/timeout errors - always retryable
618
+ if (!statusCode) {
619
+ return {
620
+ suggestion: "Network request failed. Check your internet connection and try again.",
621
+ retryable: true,
622
+ };
623
+ }
624
+ // Authentication errors (401 Unauthorized)
625
+ if (statusCode === StatusCodes.UNAUTHORIZED) {
626
+ if (message?.toLowerCase().includes("expired")) {
627
+ return {
628
+ suggestion: "Access token has expired. Call sdk.refreshAuth() to get a new token, or call sdk.login() to re-authenticate.",
629
+ retryable: false,
630
+ };
631
+ }
632
+ return {
633
+ suggestion: "Authentication required. Call sdk.login(clientId) to authenticate before making this request.",
634
+ retryable: false,
635
+ };
636
+ }
637
+ // Forbidden (403)
638
+ if (statusCode === StatusCodes.FORBIDDEN) {
639
+ return {
640
+ suggestion: "Access denied. Ensure your application has the required permissions and your client ID is valid.",
641
+ retryable: false,
642
+ };
643
+ }
644
+ // Not found (404)
645
+ if (statusCode === StatusCodes.NOT_FOUND) {
646
+ return {
647
+ suggestion: "Resource not found. Check that the ID or identifier is correct and the resource exists.",
648
+ retryable: false,
649
+ };
650
+ }
651
+ // Conflict (409) - check BEFORE 500+ to avoid being shadowed
652
+ if (statusCode === StatusCodes.CONFLICT) {
653
+ return {
654
+ suggestion: "Resource conflict. The resource may have been modified. Refresh and try again.",
655
+ retryable: true,
656
+ };
657
+ }
658
+ // Validation errors (400 Bad Request)
659
+ if (statusCode === StatusCodes.BAD_REQUEST) {
660
+ if (message?.toLowerCase().includes("insufficient balance")) {
661
+ return {
662
+ suggestion: "Insufficient balance. Deposit more funds using sdk.vault.deposit() or reduce the order size.",
663
+ retryable: false,
664
+ };
665
+ }
666
+ if (message?.toLowerCase().includes("invalid")) {
667
+ return {
668
+ suggestion: "Invalid request parameters. Check the API documentation for correct parameter format and values.",
669
+ retryable: false,
670
+ };
671
+ }
672
+ return {
673
+ suggestion: "Bad request. Verify that all required parameters are provided and correctly formatted.",
674
+ retryable: false,
675
+ };
676
+ }
677
+ // Rate limiting (429 Too Many Requests)
678
+ if (statusCode === StatusCodes.TOO_MANY_REQUESTS) {
679
+ let retryText;
680
+ if (typeof responseBody === "object" && responseBody !== null && "retry_after" in responseBody && responseBody.retry_after) {
681
+ const retryAfterValue = responseBody.retry_after;
682
+ retryText = ` Wait ${String(retryAfterValue)} seconds before retrying.`;
683
+ }
684
+ else {
685
+ retryText = " Wait a moment before retrying.";
686
+ }
687
+ return {
688
+ suggestion: `Rate limit exceeded.${retryText} Consider implementing exponential backoff for retries.`,
689
+ retryable: true,
690
+ };
691
+ }
692
+ // Server errors (500-599) - retryable
693
+ // Use explicit range check to avoid shadowing other status codes
694
+ if (statusCode >= StatusCodes.INTERNAL_SERVER_ERROR && statusCode < 600) {
695
+ return {
696
+ suggestion: "Server error occurred. This is likely a temporary issue. Try again in a few moments.",
697
+ retryable: true,
698
+ };
699
+ }
700
+ // Default - not retryable
701
+ return {
702
+ suggestion: undefined,
703
+ retryable: false,
704
+ };
705
+ }
706
+ /**
707
+ * Error thrown when a smart contract interaction fails.
708
+ *
709
+ * Represents failures in blockchain contract interactions including transaction
710
+ * reverts, gas estimation failures, and contract execution errors. Includes
711
+ * revert reasons and transaction hashes when available for debugging.
712
+ *
713
+ * **Additional Properties:**
714
+ * - `revertReason`: string | undefined - The reason the contract reverted
715
+ * - `transactionHash`: string | undefined - Transaction hash (if transaction was submitted)
716
+ * - `contractAddress`: string | undefined - Address of the contract that failed
717
+ *
718
+ * **Common Causes:**
719
+ * - Contract revert (require/assert failed)
720
+ * - Gas estimation failure (transaction would fail)
721
+ * - Insufficient gas provided
722
+ * - Contract state restrictions (e.g., paused, unauthorized)
723
+ * - Transaction reverted after submission
724
+ *
725
+ * @example
726
+ * ```typescript
727
+ * // Contract revert during simulation
728
+ * throw new ContractError(
729
+ * "Insufficient balance for withdrawal",
730
+ * {
731
+ * revertReason: "Insufficient balance",
732
+ * contractAddress: "0x123...",
733
+ * }
734
+ * );
735
+ *
736
+ * // Transaction reverted on-chain
737
+ * throw new ContractError(
738
+ * "Transaction reverted",
739
+ * {
740
+ * transactionHash: "0xabc...",
741
+ * revertReason: "Slippage tolerance exceeded",
742
+ * contractAddress: "0x456...",
743
+ * }
744
+ * );
745
+ *
746
+ * // Gas estimation failure
747
+ * try {
748
+ * await contract.estimateGas.someMethod(...args);
749
+ * } catch (error) {
750
+ * throw new ContractError(
751
+ * "Gas estimation failed",
752
+ * {
753
+ * revertReason: error.reason,
754
+ * contractAddress: contract.address,
755
+ * cause: error,
756
+ * }
757
+ * );
758
+ * }
759
+ * ```
760
+ */
761
+ export class ContractError extends MonacoCoreError {
762
+ constructor(message, options) {
763
+ const suggestion = getContractErrorSuggestion(options?.revertReason);
764
+ super(message, { cause: options?.cause, suggestion, retryable: false });
765
+ this.code = "CONTRACT_ERROR";
766
+ this.revertReason = options?.revertReason;
767
+ this.transactionHash = options?.transactionHash;
768
+ this.contractAddress = options?.contractAddress;
769
+ }
770
+ toJSON() {
771
+ return {
772
+ ...super.toJSON(),
773
+ revertReason: this.revertReason,
774
+ transactionHash: this.transactionHash,
775
+ contractAddress: this.contractAddress,
776
+ };
777
+ }
778
+ }
779
+ /**
780
+ * Get suggestions for common contract errors
781
+ */
782
+ function getContractErrorSuggestion(revertReason) {
783
+ if (!revertReason) {
784
+ return "Smart contract execution failed. Check transaction parameters and try again.";
785
+ }
786
+ const reason = revertReason.toLowerCase();
787
+ if (reason.includes("insufficient allowance")) {
788
+ return "Token allowance is insufficient. Call sdk.vault.approve() to increase the token allowance for the vault contract.";
789
+ }
790
+ if (reason.includes("insufficient balance")) {
791
+ return "Wallet balance is insufficient for this transaction. Ensure you have enough tokens and native currency for gas fees.";
792
+ }
793
+ if (reason.includes("nonce")) {
794
+ return "Transaction nonce error. This may be due to a pending transaction. Wait for pending transactions to complete or reset your account nonce.";
795
+ }
796
+ if (reason.includes("gas")) {
797
+ return "Transaction ran out of gas. Try increasing the gas limit for this transaction.";
798
+ }
799
+ return undefined;
800
+ }
801
+ //# sourceMappingURL=errors.js.map