@sequence0/sdk 0.1.0 → 1.0.1
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 +63 -5
- package/dist/chains/bitcoin.d.ts +15 -3
- package/dist/chains/bitcoin.d.ts.map +1 -1
- package/dist/chains/bitcoin.js +23 -3
- package/dist/chains/bitcoin.js.map +1 -1
- package/dist/chains/ethereum.d.ts +3 -0
- package/dist/chains/ethereum.d.ts.map +1 -1
- package/dist/chains/ethereum.js +156 -20
- package/dist/chains/ethereum.js.map +1 -1
- package/dist/core/client.d.ts +132 -2
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +501 -32
- package/dist/core/client.js.map +1 -1
- package/dist/core/types.d.ts +55 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/dist/utils/discovery.d.ts +95 -0
- package/dist/utils/discovery.d.ts.map +1 -0
- package/dist/utils/discovery.js +212 -0
- package/dist/utils/discovery.js.map +1 -0
- package/dist/utils/errors.d.ts +26 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +32 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/fee.d.ts +107 -0
- package/dist/utils/fee.d.ts.map +1 -0
- package/dist/utils/fee.js +220 -0
- package/dist/utils/fee.js.map +1 -0
- package/dist/utils/http.d.ts +98 -2
- package/dist/utils/http.d.ts.map +1 -1
- package/dist/utils/http.js +238 -6
- package/dist/utils/http.js.map +1 -1
- package/dist/utils/logger.d.ts +43 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +129 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +43 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +99 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/validation.d.ts +74 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +380 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/wallet/wallet.d.ts +13 -1
- package/dist/wallet/wallet.d.ts.map +1 -1
- package/dist/wallet/wallet.js +86 -21
- package/dist/wallet/wallet.js.map +1 -1
- package/package.json +9 -3
package/dist/utils/http.js
CHANGED
|
@@ -2,30 +2,242 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Lightweight HTTP client for Sequence0 agent node REST API
|
|
4
4
|
*
|
|
5
|
-
* Uses native fetch
|
|
5
|
+
* Uses native fetch -- works in Node.js 18+ and all modern browsers.
|
|
6
|
+
* Includes client-side rate limiting, automatic retries with exponential
|
|
7
|
+
* backoff, request/response debug logging, response validation, and
|
|
8
|
+
* a per-host circuit breaker to fail fast on unreachable agents.
|
|
6
9
|
*/
|
|
7
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.HttpClient = void 0;
|
|
11
|
+
exports.HttpClient = exports.CircuitBreaker = exports.CircuitBreakerError = void 0;
|
|
9
12
|
const errors_1 = require("./errors");
|
|
13
|
+
const rate_limiter_1 = require("./rate-limiter");
|
|
14
|
+
const logger_1 = require("./logger");
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when a request is rejected because the circuit breaker is OPEN.
|
|
17
|
+
* The caller should select a different agent or wait for the cooldown.
|
|
18
|
+
*/
|
|
19
|
+
class CircuitBreakerError extends errors_1.Sequence0Error {
|
|
20
|
+
constructor(host, timeUntilHalfOpen) {
|
|
21
|
+
super(`Circuit breaker OPEN for ${host} — requests rejected for ${Math.ceil(timeUntilHalfOpen / 1000)}s`, 'CIRCUIT_OPEN');
|
|
22
|
+
this.host = host;
|
|
23
|
+
this.timeUntilHalfOpen = timeUntilHalfOpen;
|
|
24
|
+
this.name = 'CircuitBreakerError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.CircuitBreakerError = CircuitBreakerError;
|
|
28
|
+
/**
|
|
29
|
+
* Per-host circuit breaker.
|
|
30
|
+
*
|
|
31
|
+
* States:
|
|
32
|
+
* CLOSED — normal operation, requests pass through
|
|
33
|
+
* OPEN — failing, requests are rejected immediately
|
|
34
|
+
* HALF_OPEN — testing recovery, one request is allowed through
|
|
35
|
+
*
|
|
36
|
+
* Transitions:
|
|
37
|
+
* CLOSED → OPEN after `failureThreshold` consecutive failures
|
|
38
|
+
* OPEN → HALF_OPEN after `cooldownMs` elapses
|
|
39
|
+
* HALF_OPEN → CLOSED on first success
|
|
40
|
+
* HALF_OPEN → OPEN on first failure
|
|
41
|
+
*/
|
|
42
|
+
class CircuitBreaker {
|
|
43
|
+
constructor(options = {}) {
|
|
44
|
+
this.states = new Map();
|
|
45
|
+
this.failureCounts = new Map();
|
|
46
|
+
this.lastFailureTimes = new Map();
|
|
47
|
+
this.failureThreshold = options.failureThreshold ?? 3;
|
|
48
|
+
this.cooldownMs = options.cooldownMs ?? 30000;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check whether a request to the given host is allowed.
|
|
52
|
+
* Throws CircuitBreakerError if the circuit is OPEN and cooldown has not elapsed.
|
|
53
|
+
*/
|
|
54
|
+
allowRequest(host) {
|
|
55
|
+
const state = this.getState(host);
|
|
56
|
+
if (state === 'CLOSED' || state === 'HALF_OPEN') {
|
|
57
|
+
return; // Request allowed
|
|
58
|
+
}
|
|
59
|
+
// OPEN — check if cooldown has elapsed → transition to HALF_OPEN
|
|
60
|
+
const lastFailure = this.lastFailureTimes.get(host) ?? 0;
|
|
61
|
+
const elapsed = Date.now() - lastFailure;
|
|
62
|
+
if (elapsed >= this.cooldownMs) {
|
|
63
|
+
this.states.set(host, 'HALF_OPEN');
|
|
64
|
+
return; // Allow one probe request
|
|
65
|
+
}
|
|
66
|
+
throw new CircuitBreakerError(host, this.cooldownMs - elapsed);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Record a successful request. Resets the circuit to CLOSED.
|
|
70
|
+
*/
|
|
71
|
+
recordSuccess(host) {
|
|
72
|
+
this.states.set(host, 'CLOSED');
|
|
73
|
+
this.failureCounts.set(host, 0);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Record a failed request. Increments failure count and may trip the circuit.
|
|
77
|
+
*/
|
|
78
|
+
recordFailure(host) {
|
|
79
|
+
const state = this.getState(host);
|
|
80
|
+
if (state === 'HALF_OPEN') {
|
|
81
|
+
// HALF_OPEN → OPEN on first failure
|
|
82
|
+
this.states.set(host, 'OPEN');
|
|
83
|
+
this.lastFailureTimes.set(host, Date.now());
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// CLOSED — increment failure count
|
|
87
|
+
const count = (this.failureCounts.get(host) ?? 0) + 1;
|
|
88
|
+
this.failureCounts.set(host, count);
|
|
89
|
+
this.lastFailureTimes.set(host, Date.now());
|
|
90
|
+
if (count >= this.failureThreshold) {
|
|
91
|
+
this.states.set(host, 'OPEN');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Get the current state for a host (defaults to CLOSED).
|
|
96
|
+
*/
|
|
97
|
+
getState(host) {
|
|
98
|
+
return this.states.get(host) ?? 'CLOSED';
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Reset the circuit breaker for a specific host.
|
|
102
|
+
*/
|
|
103
|
+
reset(host) {
|
|
104
|
+
this.states.delete(host);
|
|
105
|
+
this.failureCounts.delete(host);
|
|
106
|
+
this.lastFailureTimes.delete(host);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Reset all circuit breakers.
|
|
110
|
+
*/
|
|
111
|
+
resetAll() {
|
|
112
|
+
this.states.clear();
|
|
113
|
+
this.failureCounts.clear();
|
|
114
|
+
this.lastFailureTimes.clear();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
118
|
+
// ── Keep-Alive ────────────────────────────────────────────────────
|
|
119
|
+
/** Default keep-alive timeout in ms */
|
|
120
|
+
const KEEP_ALIVE_TIMEOUT_MS = 30000;
|
|
121
|
+
/** HTTP status codes that are safe to retry */
|
|
122
|
+
const RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);
|
|
10
123
|
class HttpClient {
|
|
11
124
|
constructor(options) {
|
|
12
125
|
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
13
126
|
this.timeout = options.timeout || 30000;
|
|
127
|
+
this.maxRetries = options.maxRetries ?? 3;
|
|
128
|
+
// Extract host from baseUrl for circuit breaker keying
|
|
129
|
+
try {
|
|
130
|
+
const parsed = new URL(this.baseUrl);
|
|
131
|
+
this.host = parsed.host;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
this.host = this.baseUrl;
|
|
135
|
+
}
|
|
136
|
+
// Build headers with keep-alive support
|
|
137
|
+
const keepAlive = options.keepAlive !== false; // default: true
|
|
138
|
+
const keepAliveTimeout = Math.floor((options.keepAliveTimeout ?? KEEP_ALIVE_TIMEOUT_MS) / 1000);
|
|
14
139
|
this.headers = {
|
|
15
140
|
'Content-Type': 'application/json',
|
|
141
|
+
...(keepAlive
|
|
142
|
+
? {
|
|
143
|
+
Connection: 'keep-alive',
|
|
144
|
+
'Keep-Alive': `timeout=${keepAliveTimeout}`,
|
|
145
|
+
}
|
|
146
|
+
: {}),
|
|
16
147
|
...options.headers,
|
|
17
148
|
};
|
|
149
|
+
// Set up rate limiter (enabled by default)
|
|
150
|
+
if (options.rateLimiter === false) {
|
|
151
|
+
this.rateLimiter = null;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
this.rateLimiter = new rate_limiter_1.RateLimiter(options.rateLimiter || {});
|
|
155
|
+
}
|
|
156
|
+
// Set up logger
|
|
157
|
+
if (options.logger) {
|
|
158
|
+
this.logger = options.logger;
|
|
159
|
+
}
|
|
160
|
+
else if (options.debug) {
|
|
161
|
+
this.logger = new logger_1.DebugLogger(true);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this.logger = new logger_1.NullLogger();
|
|
165
|
+
}
|
|
166
|
+
// Circuit breaker (optional, shared instance recommended)
|
|
167
|
+
this.circuitBreaker = options.circuitBreaker ?? null;
|
|
18
168
|
}
|
|
19
169
|
async get(path) {
|
|
20
|
-
return this.
|
|
170
|
+
return this.requestWithRetry('GET', path);
|
|
21
171
|
}
|
|
22
172
|
async post(path, body) {
|
|
23
|
-
return this.
|
|
173
|
+
return this.requestWithRetry('POST', path, body);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Destroy internal resources (rate limiter timers, etc.)
|
|
177
|
+
*/
|
|
178
|
+
destroy() {
|
|
179
|
+
if (this.rateLimiter) {
|
|
180
|
+
this.rateLimiter.destroy();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Request with circuit breaker check, automatic retries, and exponential backoff.
|
|
185
|
+
*/
|
|
186
|
+
async requestWithRetry(method, path, body) {
|
|
187
|
+
// Check circuit breaker before attempting any requests
|
|
188
|
+
if (this.circuitBreaker) {
|
|
189
|
+
this.circuitBreaker.allowRequest(this.host);
|
|
190
|
+
}
|
|
191
|
+
let lastError = null;
|
|
192
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
193
|
+
try {
|
|
194
|
+
const result = await this.request(method, path, body, attempt);
|
|
195
|
+
// Record success with circuit breaker
|
|
196
|
+
if (this.circuitBreaker) {
|
|
197
|
+
this.circuitBreaker.recordSuccess(this.host);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
lastError = error;
|
|
203
|
+
// Don't retry on non-retryable errors
|
|
204
|
+
if (error instanceof errors_1.NetworkError && error.statusCode) {
|
|
205
|
+
if (!RETRYABLE_STATUS_CODES.has(error.statusCode)) {
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Don't retry on the last attempt
|
|
210
|
+
if (attempt >= this.maxRetries) {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
// Exponential backoff: 200ms, 400ms, 800ms, ...
|
|
214
|
+
const delay = Math.min(200 * Math.pow(2, attempt), 5000);
|
|
215
|
+
this.logger.warn(`Retrying ${method} ${path} (attempt ${attempt + 1}/${this.maxRetries})`, {
|
|
216
|
+
delay,
|
|
217
|
+
error: lastError.message,
|
|
218
|
+
});
|
|
219
|
+
await sleep(delay);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// All retries exhausted — record failure with circuit breaker
|
|
223
|
+
if (this.circuitBreaker) {
|
|
224
|
+
this.circuitBreaker.recordFailure(this.host);
|
|
225
|
+
}
|
|
226
|
+
throw lastError;
|
|
24
227
|
}
|
|
25
|
-
async request(method, path, body) {
|
|
228
|
+
async request(method, path, body, attempt = 0) {
|
|
229
|
+
// Acquire rate limiter token before making the request
|
|
230
|
+
if (this.rateLimiter) {
|
|
231
|
+
await this.rateLimiter.acquire();
|
|
232
|
+
}
|
|
26
233
|
const url = `${this.baseUrl}${path}`;
|
|
27
234
|
const controller = new AbortController();
|
|
28
235
|
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
236
|
+
const startTime = Date.now();
|
|
237
|
+
this.logger.debug(`${method} ${path}`, {
|
|
238
|
+
attempt,
|
|
239
|
+
...(body && typeof body === 'object' ? { body_keys: Object.keys(body) } : {}),
|
|
240
|
+
});
|
|
29
241
|
try {
|
|
30
242
|
const response = await fetch(url, {
|
|
31
243
|
method,
|
|
@@ -33,6 +245,7 @@ class HttpClient {
|
|
|
33
245
|
body: body ? JSON.stringify(body) : undefined,
|
|
34
246
|
signal: controller.signal,
|
|
35
247
|
});
|
|
248
|
+
const latency = Date.now() - startTime;
|
|
36
249
|
if (!response.ok) {
|
|
37
250
|
const errorBody = await response.text().catch(() => '');
|
|
38
251
|
let errorMessage;
|
|
@@ -43,16 +256,32 @@ class HttpClient {
|
|
|
43
256
|
catch {
|
|
44
257
|
errorMessage = errorBody || `HTTP ${response.status}`;
|
|
45
258
|
}
|
|
259
|
+
this.logger.warn(`${method} ${path} -> ${response.status}`, {
|
|
260
|
+
latency,
|
|
261
|
+
status: response.status,
|
|
262
|
+
error: errorMessage,
|
|
263
|
+
});
|
|
46
264
|
throw new errors_1.NetworkError(`${method} ${path} failed: ${errorMessage}`, response.status);
|
|
47
265
|
}
|
|
48
|
-
|
|
266
|
+
const responseData = await response.json();
|
|
267
|
+
this.logger.debug(`${method} ${path} -> ${response.status}`, {
|
|
268
|
+
latency,
|
|
269
|
+
status: response.status,
|
|
270
|
+
});
|
|
271
|
+
return responseData;
|
|
49
272
|
}
|
|
50
273
|
catch (error) {
|
|
274
|
+
const latency = Date.now() - startTime;
|
|
51
275
|
if (error instanceof errors_1.NetworkError)
|
|
52
276
|
throw error;
|
|
53
277
|
if (error.name === 'AbortError') {
|
|
278
|
+
this.logger.warn(`${method} ${path} -> TIMEOUT`, { latency });
|
|
54
279
|
throw new errors_1.TimeoutError(`Request to ${path} timed out after ${this.timeout}ms`);
|
|
55
280
|
}
|
|
281
|
+
this.logger.warn(`${method} ${path} -> NETWORK_ERROR`, {
|
|
282
|
+
latency,
|
|
283
|
+
error: error.message,
|
|
284
|
+
});
|
|
56
285
|
throw new errors_1.NetworkError(`Failed to connect to ${url}: ${error.message}`);
|
|
57
286
|
}
|
|
58
287
|
finally {
|
|
@@ -61,4 +290,7 @@ class HttpClient {
|
|
|
61
290
|
}
|
|
62
291
|
}
|
|
63
292
|
exports.HttpClient = HttpClient;
|
|
293
|
+
function sleep(ms) {
|
|
294
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
295
|
+
}
|
|
64
296
|
//# sourceMappingURL=http.js.map
|
package/dist/utils/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug Logger for Sequence0 SDK
|
|
3
|
+
*
|
|
4
|
+
* Optional logging that never exposes sensitive data:
|
|
5
|
+
* - Private keys are never logged
|
|
6
|
+
* - Wallet addresses are masked: 0x1234...abcd
|
|
7
|
+
* - Full signatures are never logged
|
|
8
|
+
* - Only method, endpoint, status code, and latency are logged
|
|
9
|
+
*/
|
|
10
|
+
export interface Logger {
|
|
11
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
12
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
13
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Mask an address for safe debug logging.
|
|
17
|
+
* "0x1234567890abcdef..." -> "0x1234...cdef"
|
|
18
|
+
*/
|
|
19
|
+
export declare function maskAddress(address: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Mask sensitive fields in an object for safe logging.
|
|
22
|
+
* Returns a new object — never mutates the original.
|
|
23
|
+
*/
|
|
24
|
+
export declare function maskSensitive(data: Record<string, unknown>): Record<string, unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* Default console-based debug logger.
|
|
27
|
+
* Only logs when debug mode is enabled.
|
|
28
|
+
*/
|
|
29
|
+
export declare class DebugLogger implements Logger {
|
|
30
|
+
private enabled;
|
|
31
|
+
private prefix;
|
|
32
|
+
constructor(enabled?: boolean, prefix?: string);
|
|
33
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
34
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
35
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
36
|
+
}
|
|
37
|
+
/** No-op logger that suppresses all output */
|
|
38
|
+
export declare class NullLogger implements Logger {
|
|
39
|
+
debug(): void;
|
|
40
|
+
warn(): void;
|
|
41
|
+
error(): void;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,MAAM;IACnB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC7D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAChE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAanD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkDpF;AAED;;;GAGG;AACH,qBAAa,WAAY,YAAW,MAAM;IACtC,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,OAAO,UAAQ,EAAE,MAAM,SAAgB;IAKnD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAU5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAU3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAS/D;AAED,8CAA8C;AAC9C,qBAAa,UAAW,YAAW,MAAM;IACrC,KAAK,IAAI,IAAI;IACb,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;CAChB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Debug Logger for Sequence0 SDK
|
|
4
|
+
*
|
|
5
|
+
* Optional logging that never exposes sensitive data:
|
|
6
|
+
* - Private keys are never logged
|
|
7
|
+
* - Wallet addresses are masked: 0x1234...abcd
|
|
8
|
+
* - Full signatures are never logged
|
|
9
|
+
* - Only method, endpoint, status code, and latency are logged
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.NullLogger = exports.DebugLogger = void 0;
|
|
13
|
+
exports.maskAddress = maskAddress;
|
|
14
|
+
exports.maskSensitive = maskSensitive;
|
|
15
|
+
/**
|
|
16
|
+
* Mask an address for safe debug logging.
|
|
17
|
+
* "0x1234567890abcdef..." -> "0x1234...cdef"
|
|
18
|
+
*/
|
|
19
|
+
function maskAddress(address) {
|
|
20
|
+
if (!address || address.length < 10)
|
|
21
|
+
return '***';
|
|
22
|
+
if (address.startsWith('0x') && address.length >= 12) {
|
|
23
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
24
|
+
}
|
|
25
|
+
// Non-EVM addresses
|
|
26
|
+
if (address.length >= 12) {
|
|
27
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
28
|
+
}
|
|
29
|
+
return '***';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Mask sensitive fields in an object for safe logging.
|
|
33
|
+
* Returns a new object — never mutates the original.
|
|
34
|
+
*/
|
|
35
|
+
function maskSensitive(data) {
|
|
36
|
+
const masked = {};
|
|
37
|
+
for (const [key, value] of Object.entries(data)) {
|
|
38
|
+
const lowerKey = key.toLowerCase();
|
|
39
|
+
// Never log these
|
|
40
|
+
if (lowerKey.includes('privatekey') ||
|
|
41
|
+
lowerKey.includes('private_key') ||
|
|
42
|
+
lowerKey.includes('secret') ||
|
|
43
|
+
lowerKey.includes('mnemonic') ||
|
|
44
|
+
lowerKey.includes('seed') ||
|
|
45
|
+
lowerKey === 'apikey' ||
|
|
46
|
+
lowerKey === 'api_key') {
|
|
47
|
+
masked[key] = '[REDACTED]';
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Mask signatures (show only prefix)
|
|
51
|
+
if (lowerKey === 'signature' || lowerKey === 'sig') {
|
|
52
|
+
if (typeof value === 'string' && value.length > 16) {
|
|
53
|
+
masked[key] = `${value.slice(0, 10)}...[${value.length} chars]`;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
masked[key] = value;
|
|
57
|
+
}
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
// Mask addresses
|
|
61
|
+
if (lowerKey === 'address' || lowerKey === 'from' || lowerKey === 'to') {
|
|
62
|
+
if (typeof value === 'string') {
|
|
63
|
+
masked[key] = maskAddress(value);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
masked[key] = value;
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
// Recursively mask nested objects
|
|
71
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
72
|
+
masked[key] = maskSensitive(value);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
masked[key] = value;
|
|
76
|
+
}
|
|
77
|
+
return masked;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Default console-based debug logger.
|
|
81
|
+
* Only logs when debug mode is enabled.
|
|
82
|
+
*/
|
|
83
|
+
class DebugLogger {
|
|
84
|
+
constructor(enabled = false, prefix = '[Sequence0]') {
|
|
85
|
+
this.enabled = enabled;
|
|
86
|
+
this.prefix = prefix;
|
|
87
|
+
}
|
|
88
|
+
debug(message, meta) {
|
|
89
|
+
if (!this.enabled)
|
|
90
|
+
return;
|
|
91
|
+
const safe = meta ? maskSensitive(meta) : undefined;
|
|
92
|
+
if (safe) {
|
|
93
|
+
console.debug(`${this.prefix} ${message}`, safe);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.debug(`${this.prefix} ${message}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
warn(message, meta) {
|
|
100
|
+
if (!this.enabled)
|
|
101
|
+
return;
|
|
102
|
+
const safe = meta ? maskSensitive(meta) : undefined;
|
|
103
|
+
if (safe) {
|
|
104
|
+
console.warn(`${this.prefix} ${message}`, safe);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.warn(`${this.prefix} ${message}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
error(message, meta) {
|
|
111
|
+
// Errors are always logged, even if debug is off
|
|
112
|
+
const safe = meta ? maskSensitive(meta) : undefined;
|
|
113
|
+
if (safe) {
|
|
114
|
+
console.error(`${this.prefix} ${message}`, safe);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
console.error(`${this.prefix} ${message}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
exports.DebugLogger = DebugLogger;
|
|
122
|
+
/** No-op logger that suppresses all output */
|
|
123
|
+
class NullLogger {
|
|
124
|
+
debug() { }
|
|
125
|
+
warn() { }
|
|
126
|
+
error() { }
|
|
127
|
+
}
|
|
128
|
+
exports.NullLogger = NullLogger;
|
|
129
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-Side Rate Limiter (Token Bucket)
|
|
3
|
+
*
|
|
4
|
+
* Prevents clients from exceeding the server's rate limit (100 req/s on mainnet)
|
|
5
|
+
* by throttling outgoing requests. Excess requests are queued rather
|
|
6
|
+
* than rejected, so callers never see a rate-limit error from the SDK.
|
|
7
|
+
*/
|
|
8
|
+
export interface RateLimiterOptions {
|
|
9
|
+
/** Maximum requests per second (default: 25, under server's 100/s mainnet limit) */
|
|
10
|
+
maxRequestsPerSecond?: number;
|
|
11
|
+
/** Maximum queued requests before rejecting (default: 100) */
|
|
12
|
+
maxQueueSize?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare class RateLimiter {
|
|
15
|
+
private tokens;
|
|
16
|
+
private maxTokens;
|
|
17
|
+
private refillRate;
|
|
18
|
+
private lastRefill;
|
|
19
|
+
private queue;
|
|
20
|
+
private maxQueueSize;
|
|
21
|
+
private drainTimer;
|
|
22
|
+
constructor(options?: RateLimiterOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Acquire a token before making a request.
|
|
25
|
+
* Resolves immediately if tokens are available, otherwise queues.
|
|
26
|
+
*/
|
|
27
|
+
acquire(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Get current state for debugging.
|
|
30
|
+
*/
|
|
31
|
+
get state(): {
|
|
32
|
+
tokens: number;
|
|
33
|
+
queued: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Cancel all queued requests and stop the drain timer.
|
|
37
|
+
*/
|
|
38
|
+
destroy(): void;
|
|
39
|
+
private refill;
|
|
40
|
+
private scheduleDrain;
|
|
41
|
+
private drain;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,kBAAkB;IAC/B,oFAAoF;IACpF,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAOD,qBAAa,WAAW;IACpB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAA8C;gBAEpD,OAAO,GAAE,kBAAuB;IAS5C;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAsB9B;;OAEG;IACH,IAAI,KAAK,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAM9C;IAED;;OAEG;IACH,OAAO,IAAI,IAAI;IAcf,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,KAAK;CAchB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Client-Side Rate Limiter (Token Bucket)
|
|
4
|
+
*
|
|
5
|
+
* Prevents clients from exceeding the server's rate limit (100 req/s on mainnet)
|
|
6
|
+
* by throttling outgoing requests. Excess requests are queued rather
|
|
7
|
+
* than rejected, so callers never see a rate-limit error from the SDK.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.RateLimiter = void 0;
|
|
11
|
+
class RateLimiter {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.queue = [];
|
|
14
|
+
this.drainTimer = null;
|
|
15
|
+
const rps = options.maxRequestsPerSecond ?? 25;
|
|
16
|
+
this.maxTokens = rps;
|
|
17
|
+
this.tokens = rps;
|
|
18
|
+
this.refillRate = rps / 1000; // tokens per ms
|
|
19
|
+
this.lastRefill = Date.now();
|
|
20
|
+
this.maxQueueSize = options.maxQueueSize ?? 100;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Acquire a token before making a request.
|
|
24
|
+
* Resolves immediately if tokens are available, otherwise queues.
|
|
25
|
+
*/
|
|
26
|
+
async acquire() {
|
|
27
|
+
this.refill();
|
|
28
|
+
if (this.tokens >= 1) {
|
|
29
|
+
this.tokens -= 1;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// No tokens available — queue the request
|
|
33
|
+
if (this.queue.length >= this.maxQueueSize) {
|
|
34
|
+
throw new Error(`Rate limiter queue full (${this.maxQueueSize} pending requests). ` +
|
|
35
|
+
'Reduce request rate or increase maxQueueSize.');
|
|
36
|
+
}
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
this.queue.push({ resolve, reject });
|
|
39
|
+
this.scheduleDrain();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get current state for debugging.
|
|
44
|
+
*/
|
|
45
|
+
get state() {
|
|
46
|
+
this.refill();
|
|
47
|
+
return {
|
|
48
|
+
tokens: Math.floor(this.tokens),
|
|
49
|
+
queued: this.queue.length,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Cancel all queued requests and stop the drain timer.
|
|
54
|
+
*/
|
|
55
|
+
destroy() {
|
|
56
|
+
if (this.drainTimer) {
|
|
57
|
+
clearTimeout(this.drainTimer);
|
|
58
|
+
this.drainTimer = null;
|
|
59
|
+
}
|
|
60
|
+
const err = new Error('Rate limiter destroyed');
|
|
61
|
+
for (const entry of this.queue) {
|
|
62
|
+
entry.reject(err);
|
|
63
|
+
}
|
|
64
|
+
this.queue = [];
|
|
65
|
+
}
|
|
66
|
+
// ── Internals ──
|
|
67
|
+
refill() {
|
|
68
|
+
const now = Date.now();
|
|
69
|
+
const elapsed = now - this.lastRefill;
|
|
70
|
+
if (elapsed <= 0)
|
|
71
|
+
return;
|
|
72
|
+
this.tokens = Math.min(this.maxTokens, this.tokens + elapsed * this.refillRate);
|
|
73
|
+
this.lastRefill = now;
|
|
74
|
+
}
|
|
75
|
+
scheduleDrain() {
|
|
76
|
+
if (this.drainTimer)
|
|
77
|
+
return;
|
|
78
|
+
// Check every ~1/rps interval (e.g. 40ms for 25 rps)
|
|
79
|
+
const intervalMs = Math.max(1, Math.ceil(1000 / this.maxTokens));
|
|
80
|
+
this.drainTimer = setTimeout(() => {
|
|
81
|
+
this.drainTimer = null;
|
|
82
|
+
this.drain();
|
|
83
|
+
}, intervalMs);
|
|
84
|
+
}
|
|
85
|
+
drain() {
|
|
86
|
+
this.refill();
|
|
87
|
+
while (this.queue.length > 0 && this.tokens >= 1) {
|
|
88
|
+
this.tokens -= 1;
|
|
89
|
+
const entry = this.queue.shift();
|
|
90
|
+
entry.resolve();
|
|
91
|
+
}
|
|
92
|
+
// If there are still queued requests, schedule another drain
|
|
93
|
+
if (this.queue.length > 0) {
|
|
94
|
+
this.scheduleDrain();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.RateLimiter = RateLimiter;
|
|
99
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"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"}
|