@coinlist-co/react 0.11.0 → 0.11.1-rc.10770e8
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/{chunk-UIIXXLA7.js → chunk-7CTH4KPU.js} +734 -198
- package/dist/chunk-7CTH4KPU.js.map +1 -0
- package/dist/{chunk-B2HCVPCQ.js → chunk-LSPZETDH.js} +81 -33
- package/dist/chunk-LSPZETDH.js.map +1 -0
- package/dist/chunk-UZUQALFY.js +279 -0
- package/dist/chunk-UZUQALFY.js.map +1 -0
- package/dist/client/index.cjs +5415 -2413
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +2439 -1209
- package/dist/client/index.d.ts +2439 -1209
- package/dist/client/index.js +4457 -2178
- package/dist/client/index.js.map +1 -1
- package/dist/collections-BBI_XydI.d.cts +116 -0
- package/dist/collections-BrX9rRWc.d.ts +116 -0
- package/dist/{config-B5mwS_2l.d.cts → config-CMl1bR3F.d.cts} +1183 -150
- package/dist/{config-B5mwS_2l.d.ts → config-CMl1bR3F.d.ts} +1183 -150
- package/dist/server/index.cjs +1005 -265
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +81 -4
- package/dist/server/index.d.ts +81 -4
- package/dist/server/index.js +120 -51
- package/dist/server/index.js.map +1 -1
- package/dist/shared/index.cjs +798 -204
- package/dist/shared/index.cjs.map +1 -1
- package/dist/shared/index.d.cts +98 -16
- package/dist/shared/index.d.ts +98 -16
- package/dist/shared/index.js +22 -6
- package/package.json +3 -2
- package/dist/chunk-B2HCVPCQ.js.map +0 -1
- package/dist/chunk-KDGNDAHA.js +0 -146
- package/dist/chunk-KDGNDAHA.js.map +0 -1
- package/dist/chunk-UIIXXLA7.js.map +0 -1
- package/dist/collections-BhDkYmzV.d.cts +0 -65
- package/dist/collections-CZhHoQHr.d.ts +0 -65
package/dist/server/index.cjs
CHANGED
|
@@ -24,7 +24,9 @@ __export(server_exports, {
|
|
|
24
24
|
ServerOffersNamespaceImpl: () => ServerOffersNamespaceImpl,
|
|
25
25
|
ServerRequirementsNamespaceImpl: () => ServerRequirementsNamespaceImpl,
|
|
26
26
|
WritableSessionStoreRequiredError: () => WritableSessionStoreRequiredError,
|
|
27
|
-
createCoinListServer: () => createCoinListServer
|
|
27
|
+
createCoinListServer: () => createCoinListServer,
|
|
28
|
+
emptySessionStore: () => emptySessionStore,
|
|
29
|
+
pinoServerLogger: () => pinoServerLogger
|
|
28
30
|
});
|
|
29
31
|
module.exports = __toCommonJS(server_exports);
|
|
30
32
|
|
|
@@ -55,6 +57,8 @@ var retryAttempt = (attempt) => ({
|
|
|
55
57
|
var renewAttempted = (value) => ({
|
|
56
58
|
renewAttempted: value
|
|
57
59
|
});
|
|
60
|
+
var requestId = (id) => ({ requestId: id });
|
|
61
|
+
var getRequestId = (attrs) => attrs?.requestId ?? null;
|
|
58
62
|
var isProtected = (attrs) => attrs?.protected === true;
|
|
59
63
|
var needUserAgent = (attrs) => attrs?.userAgent === true;
|
|
60
64
|
var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
|
|
@@ -76,7 +80,9 @@ var Attributes = {
|
|
|
76
80
|
renewAttempted,
|
|
77
81
|
wasRenewAttempted,
|
|
78
82
|
clientCredentials,
|
|
79
|
-
getClientCredentials
|
|
83
|
+
getClientCredentials,
|
|
84
|
+
requestId,
|
|
85
|
+
getRequestId
|
|
80
86
|
};
|
|
81
87
|
|
|
82
88
|
// src/shared/api/http.ts
|
|
@@ -86,7 +92,24 @@ var HttpError = class extends Error {
|
|
|
86
92
|
this.name = "HttpError";
|
|
87
93
|
this.response = response;
|
|
88
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Correlates this failure with the `[HTTP]` log lines for the same request,
|
|
97
|
+
* which carry the method, the URL, the duration and every retry. `null` when
|
|
98
|
+
* the response did not come from an {@link HttpClient}.
|
|
99
|
+
*
|
|
100
|
+
* Worth quoting in a bug report: it is what makes a log excerpt readable.
|
|
101
|
+
*/
|
|
102
|
+
get requestId() {
|
|
103
|
+
return this.response.requestId ?? null;
|
|
104
|
+
}
|
|
89
105
|
};
|
|
106
|
+
function apiErrorCode(error) {
|
|
107
|
+
if (!(error instanceof HttpError)) return null;
|
|
108
|
+
const body = error.response.body;
|
|
109
|
+
if (typeof body !== "object" || body === null) return null;
|
|
110
|
+
const code = body.code;
|
|
111
|
+
return typeof code === "string" ? code : null;
|
|
112
|
+
}
|
|
90
113
|
async function makeRequest(request) {
|
|
91
114
|
const headers = {
|
|
92
115
|
Accept: "application/json",
|
|
@@ -192,11 +215,194 @@ var HEADER_API_VERSION = "X-API-Version";
|
|
|
192
215
|
var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
|
|
193
216
|
var API_VERSION = "2025-10-17";
|
|
194
217
|
|
|
218
|
+
// src/shared/types/errors.ts
|
|
219
|
+
var NotImplementedError = class extends Error {
|
|
220
|
+
constructor(message = "Not implemented yet") {
|
|
221
|
+
super(message);
|
|
222
|
+
this.name = "NotImplementedError";
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
var NotAuthenticatedError = class extends Error {
|
|
226
|
+
constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
|
|
227
|
+
super(message);
|
|
228
|
+
this.name = "NotAuthenticatedError";
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
var ValidationError = class extends Error {
|
|
232
|
+
constructor(message) {
|
|
233
|
+
super(message);
|
|
234
|
+
this.name = "ValidationError";
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
var InvariantError = class extends Error {
|
|
238
|
+
constructor(message) {
|
|
239
|
+
super(message);
|
|
240
|
+
this.name = "InvariantError";
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
var MathError = class extends Error {
|
|
244
|
+
constructor(message) {
|
|
245
|
+
super(message);
|
|
246
|
+
this.name = "MathError";
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// src/shared/core/observability/log-cause.ts
|
|
251
|
+
function classifyLogCause(error) {
|
|
252
|
+
if (error instanceof HttpError) {
|
|
253
|
+
return httpCause(error);
|
|
254
|
+
}
|
|
255
|
+
if (error instanceof ValidationError) {
|
|
256
|
+
return { type: "validation", message: error.message };
|
|
257
|
+
}
|
|
258
|
+
if (error instanceof InvariantError) {
|
|
259
|
+
return { type: "invariant", message: error.message };
|
|
260
|
+
}
|
|
261
|
+
if (error instanceof MathError) {
|
|
262
|
+
return { type: "math", message: error.message };
|
|
263
|
+
}
|
|
264
|
+
if (error instanceof NotAuthenticatedError) {
|
|
265
|
+
return { type: "not-authenticated" };
|
|
266
|
+
}
|
|
267
|
+
if (error instanceof NotImplementedError) {
|
|
268
|
+
return { type: "not-implemented" };
|
|
269
|
+
}
|
|
270
|
+
return { type: "generic-error", name: errorName(error) };
|
|
271
|
+
}
|
|
272
|
+
function describeErrorUnredacted(error) {
|
|
273
|
+
if (error instanceof HttpError) {
|
|
274
|
+
return describeHttpErrorRedacted(error);
|
|
275
|
+
}
|
|
276
|
+
if (error instanceof Error) {
|
|
277
|
+
return `${error.name}: ${error.message}`;
|
|
278
|
+
}
|
|
279
|
+
return `thrown non-error: ${stringifyUnredacted(error)}`;
|
|
280
|
+
}
|
|
281
|
+
function stringifyUnredacted(value) {
|
|
282
|
+
if (value === void 0) return "";
|
|
283
|
+
try {
|
|
284
|
+
return JSON.stringify(
|
|
285
|
+
value,
|
|
286
|
+
(_key, item) => typeof item === "bigint" ? `${item}` : item
|
|
287
|
+
) ?? String(value);
|
|
288
|
+
} catch (_) {
|
|
289
|
+
return "<unserializable>";
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function describeHttpErrorRedacted(error) {
|
|
293
|
+
const code = apiErrorCode(error);
|
|
294
|
+
const status = error.response.status;
|
|
295
|
+
return code === null ? `HttpError ${status}` : `HttpError ${status} (${code})`;
|
|
296
|
+
}
|
|
297
|
+
function errorName(error) {
|
|
298
|
+
return error instanceof Error ? error.name : `non-error ${typeof error}`;
|
|
299
|
+
}
|
|
300
|
+
function httpCause(error) {
|
|
301
|
+
return {
|
|
302
|
+
type: "http",
|
|
303
|
+
requestId: error.requestId,
|
|
304
|
+
status: error.response.status,
|
|
305
|
+
code: apiErrorCode(error),
|
|
306
|
+
eventId: apiErrorEventId(error)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function apiErrorEventId(error) {
|
|
310
|
+
const body = error.response.body;
|
|
311
|
+
if (typeof body !== "object" || body === null) return null;
|
|
312
|
+
const eventId = body.event_id;
|
|
313
|
+
return typeof eventId === "string" ? eventId : null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/shared/core/observability/internal-logger.ts
|
|
317
|
+
function internalLogger(logger, scope) {
|
|
318
|
+
return logger ? scopedLogger(logger, scope, {}) : noopInternalLogger;
|
|
319
|
+
}
|
|
320
|
+
var LEVEL_RANK = {
|
|
321
|
+
none: 0,
|
|
322
|
+
error: 1,
|
|
323
|
+
warn: 2,
|
|
324
|
+
info: 3,
|
|
325
|
+
debug: 4
|
|
326
|
+
};
|
|
327
|
+
function scopedLogger(logger, scope, bindings) {
|
|
328
|
+
const admits = (level) => LEVEL_RANK[logger.level()] >= LEVEL_RANK[level];
|
|
329
|
+
const safe = (event) => ({
|
|
330
|
+
msg: event.msg,
|
|
331
|
+
scope,
|
|
332
|
+
bindings,
|
|
333
|
+
fields: event.fields ?? {},
|
|
334
|
+
...event.cause === void 0 ? {} : { cause: event.cause }
|
|
335
|
+
});
|
|
336
|
+
const unredacted = (event) => ({
|
|
337
|
+
msg: event.msg,
|
|
338
|
+
scope,
|
|
339
|
+
bindings,
|
|
340
|
+
fields: event.fields ?? {}
|
|
341
|
+
});
|
|
342
|
+
const self = {
|
|
343
|
+
child: (binding) => scopedLogger(logger, scope, { ...bindings, ...binding }),
|
|
344
|
+
debug: (event) => {
|
|
345
|
+
if (admits("debug")) logger.debug(() => unredacted(event()));
|
|
346
|
+
},
|
|
347
|
+
info: (event) => {
|
|
348
|
+
if (admits("info")) logger.info(() => safe(event()));
|
|
349
|
+
},
|
|
350
|
+
warn: (event) => {
|
|
351
|
+
if (admits("warn")) logger.warn(() => safe(event()));
|
|
352
|
+
},
|
|
353
|
+
error: (event) => {
|
|
354
|
+
if (admits("error")) logger.error(() => safe(event()));
|
|
355
|
+
},
|
|
356
|
+
failure: (event, error) => {
|
|
357
|
+
if (admits("debug"))
|
|
358
|
+
logger.debug(() => unredacted(verbatim(event(), error)));
|
|
359
|
+
if (admits("error")) logger.error(() => safe(classified(event(), error)));
|
|
360
|
+
},
|
|
361
|
+
warning: (event, error) => {
|
|
362
|
+
if (admits("debug"))
|
|
363
|
+
logger.debug(() => unredacted(verbatim(event(), error)));
|
|
364
|
+
if (admits("warn")) logger.warn(() => safe(classified(event(), error)));
|
|
365
|
+
},
|
|
366
|
+
wrap: async (op, params, run) => {
|
|
367
|
+
const opLog = self.child({ op });
|
|
368
|
+
opLog.debug(() => ({ msg: "call", fields: { params } }));
|
|
369
|
+
try {
|
|
370
|
+
return await run();
|
|
371
|
+
} catch (error) {
|
|
372
|
+
opLog.failure(() => ({ msg: "call failed" }), error);
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
return self;
|
|
378
|
+
}
|
|
379
|
+
function verbatim(event, error) {
|
|
380
|
+
return {
|
|
381
|
+
msg: event.msg,
|
|
382
|
+
fields: { ...event.fields, error: describeErrorUnredacted(error) }
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function classified(event, error) {
|
|
386
|
+
return { ...event, cause: event.cause ?? classifyLogCause(error) };
|
|
387
|
+
}
|
|
388
|
+
var noopInternalLogger = {
|
|
389
|
+
child: () => noopInternalLogger,
|
|
390
|
+
debug: () => void 0,
|
|
391
|
+
info: () => void 0,
|
|
392
|
+
warn: () => void 0,
|
|
393
|
+
error: () => void 0,
|
|
394
|
+
failure: () => void 0,
|
|
395
|
+
warning: () => void 0,
|
|
396
|
+
wrap: (_op, _params, run) => run()
|
|
397
|
+
};
|
|
398
|
+
|
|
195
399
|
// src/shared/api/http-client.ts
|
|
196
400
|
var HttpClient = class {
|
|
197
|
-
constructor(config, middleware = {}) {
|
|
401
|
+
constructor(config, middleware = {}, logger = null, options = {}) {
|
|
198
402
|
this.config = config;
|
|
199
403
|
this.middleware = middleware;
|
|
404
|
+
this.log = internalLogger(logger, "HTTP");
|
|
405
|
+
this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;
|
|
200
406
|
}
|
|
201
407
|
async send(request) {
|
|
202
408
|
return this.runRequestWithAfterMiddleware(request);
|
|
@@ -232,7 +438,13 @@ var HttpClient = class {
|
|
|
232
438
|
return {
|
|
233
439
|
...request,
|
|
234
440
|
url,
|
|
235
|
-
headers
|
|
441
|
+
headers,
|
|
442
|
+
// Only when absent: a retry or a post-renewal re-send arrives with the
|
|
443
|
+
// first attempt's id already on it, and keeping it is the whole point.
|
|
444
|
+
attributes: Attributes.getRequestId(request.attributes) === null ? Attributes.concat(
|
|
445
|
+
request.attributes ?? Attributes.empty,
|
|
446
|
+
Attributes.requestId(this.makeRequestId())
|
|
447
|
+
) : request.attributes
|
|
236
448
|
};
|
|
237
449
|
}
|
|
238
450
|
/**
|
|
@@ -256,10 +468,89 @@ var HttpClient = class {
|
|
|
256
468
|
}
|
|
257
469
|
return request;
|
|
258
470
|
}
|
|
259
|
-
|
|
260
|
-
|
|
471
|
+
/**
|
|
472
|
+
* One physical attempt, logged as one line.
|
|
473
|
+
*
|
|
474
|
+
* A non-2xx is a `warn` rather than an `error` because the wire does not
|
|
475
|
+
* know whether it is a failure: the retry middleware may turn a 503 into a
|
|
476
|
+
* success, and the token registry reads a 404 as "not listed". The namespace
|
|
477
|
+
* above decides, and logs the `error` when it does.
|
|
478
|
+
*/
|
|
479
|
+
async executeRequest(request) {
|
|
480
|
+
const requestId2 = Attributes.getRequestId(request.attributes);
|
|
481
|
+
const log = requestId2 === null ? this.log : this.log.child({ requestId: requestId2 });
|
|
482
|
+
const attempt = Attributes.getRetryAttempt(request.attributes) + 1;
|
|
483
|
+
const startedAt = Date.now();
|
|
484
|
+
log.debug(() => ({
|
|
485
|
+
msg: "request sent",
|
|
486
|
+
fields: describeRequestUnredacted(request)
|
|
487
|
+
}));
|
|
488
|
+
try {
|
|
489
|
+
const response = await makeRequest(request);
|
|
490
|
+
const elapsed = Date.now() - startedAt;
|
|
491
|
+
const outcome = () => ({
|
|
492
|
+
msg: "request completed",
|
|
493
|
+
fields: {
|
|
494
|
+
...identifyRequest(request),
|
|
495
|
+
"http.response.status_code": response.status,
|
|
496
|
+
duration_ms: elapsed,
|
|
497
|
+
attempt
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
if (response.status >= 200 && response.status < 300) {
|
|
501
|
+
log.info(outcome);
|
|
502
|
+
} else {
|
|
503
|
+
log.warn(outcome);
|
|
504
|
+
}
|
|
505
|
+
log.debug(() => ({
|
|
506
|
+
msg: "response received",
|
|
507
|
+
fields: { body: response.body }
|
|
508
|
+
}));
|
|
509
|
+
return requestId2 === null ? response : { ...response, requestId: requestId2 };
|
|
510
|
+
} catch (error) {
|
|
511
|
+
const elapsed = Date.now() - startedAt;
|
|
512
|
+
log.warning(
|
|
513
|
+
() => ({
|
|
514
|
+
msg: "request threw",
|
|
515
|
+
fields: {
|
|
516
|
+
...identifyRequest(request),
|
|
517
|
+
duration_ms: elapsed,
|
|
518
|
+
attempt
|
|
519
|
+
}
|
|
520
|
+
}),
|
|
521
|
+
error
|
|
522
|
+
);
|
|
523
|
+
throw error;
|
|
524
|
+
}
|
|
261
525
|
}
|
|
262
526
|
};
|
|
527
|
+
function identifyRequest(request) {
|
|
528
|
+
const { host, path } = splitUrl(request.url);
|
|
529
|
+
return {
|
|
530
|
+
"http.request.method": request.method,
|
|
531
|
+
"server.address": host,
|
|
532
|
+
"url.path": path
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function splitUrl(url) {
|
|
536
|
+
try {
|
|
537
|
+
const parsed = new URL(url);
|
|
538
|
+
return { host: parsed.host, path: parsed.pathname };
|
|
539
|
+
} catch (_) {
|
|
540
|
+
return { host: null, path: url };
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function defaultMakeRequestId() {
|
|
544
|
+
return Math.random().toString(36).slice(2, 10).padEnd(8, "0");
|
|
545
|
+
}
|
|
546
|
+
function describeRequestUnredacted(request) {
|
|
547
|
+
return {
|
|
548
|
+
"http.request.method": request.method,
|
|
549
|
+
"url.full": buildUrlWithQueryParams(request.url, request.queryParams),
|
|
550
|
+
headers: request.headers,
|
|
551
|
+
...request.method === "POST" ? { body: request.body } : {}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
263
554
|
|
|
264
555
|
// src/shared/api/middleware/attach-session-middleware.ts
|
|
265
556
|
function attachSessionMiddleware(fetchAccessToken) {
|
|
@@ -390,18 +681,22 @@ function renewSessionMiddleware(fetchAccessToken) {
|
|
|
390
681
|
|
|
391
682
|
// src/shared/api/authenticated-api-client.ts
|
|
392
683
|
var AuthenticatedApiClient = class {
|
|
393
|
-
constructor(config, fetchAccessToken, additionalBeforeRequest = []) {
|
|
394
|
-
this.httpClient = new HttpClient(
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
684
|
+
constructor(config, fetchAccessToken, additionalBeforeRequest = [], logger = null) {
|
|
685
|
+
this.httpClient = new HttpClient(
|
|
686
|
+
config,
|
|
687
|
+
{
|
|
688
|
+
beforeRequest: [
|
|
689
|
+
attachSessionMiddleware(fetchAccessToken),
|
|
690
|
+
...additionalBeforeRequest,
|
|
691
|
+
idempotencyKeyMiddleware
|
|
692
|
+
],
|
|
693
|
+
afterRequest: [
|
|
694
|
+
renewSessionMiddleware(fetchAccessToken),
|
|
695
|
+
requestRetryMiddleware
|
|
696
|
+
]
|
|
697
|
+
},
|
|
698
|
+
logger
|
|
699
|
+
);
|
|
405
700
|
}
|
|
406
701
|
async send(request) {
|
|
407
702
|
const response = await this.httpClient.send(request);
|
|
@@ -415,8 +710,13 @@ var AuthenticatedApiClient = class {
|
|
|
415
710
|
|
|
416
711
|
// src/server/core/api/api-client.ts
|
|
417
712
|
var ApiClient = class {
|
|
418
|
-
constructor(config, fetchAccessToken) {
|
|
419
|
-
this.client = new AuthenticatedApiClient(
|
|
713
|
+
constructor(config, fetchAccessToken, logger = null) {
|
|
714
|
+
this.client = new AuthenticatedApiClient(
|
|
715
|
+
config,
|
|
716
|
+
fetchAccessToken,
|
|
717
|
+
[],
|
|
718
|
+
logger
|
|
719
|
+
);
|
|
420
720
|
}
|
|
421
721
|
async send(request) {
|
|
422
722
|
return this.client.send(request);
|
|
@@ -448,33 +748,43 @@ var OAuthSession = {
|
|
|
448
748
|
};
|
|
449
749
|
|
|
450
750
|
// src/server/core/server-auth-namespace.ts
|
|
751
|
+
function emptySessionStore() {
|
|
752
|
+
return { getSession: async () => null };
|
|
753
|
+
}
|
|
451
754
|
var ServerAuthNamespaceImpl = class {
|
|
452
755
|
constructor(api, config) {
|
|
453
756
|
this.api = api;
|
|
454
757
|
this.config = config;
|
|
758
|
+
this.log = internalLogger(config.logger ?? null, "AUTH");
|
|
455
759
|
}
|
|
456
|
-
async completeOAuth({
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
760
|
+
async completeOAuth(params) {
|
|
761
|
+
return this.log.wrap("completeOAuth", void 0, async () => {
|
|
762
|
+
const setSession = this.writableSessionStore();
|
|
763
|
+
const sessionDto = await this.api.send({
|
|
764
|
+
method: "POST",
|
|
765
|
+
url: `/oauth/token`,
|
|
766
|
+
body: {
|
|
767
|
+
grant_type: "authorization_code",
|
|
768
|
+
code: params.code,
|
|
769
|
+
redirect_uri: this.config.redirectUri,
|
|
770
|
+
client_id: this.config.clientId,
|
|
771
|
+
client_secret: this.config.clientSecret,
|
|
772
|
+
code_verifier: params.codeVerifier
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
const session = OAuthSession.fromDto(sessionDto);
|
|
776
|
+
await setSession(session);
|
|
777
|
+
return session;
|
|
472
778
|
});
|
|
473
|
-
const session = OAuthSession.fromDto(sessionDto);
|
|
474
|
-
await setSession(session);
|
|
475
|
-
return session;
|
|
476
779
|
}
|
|
477
780
|
async getAccessToken() {
|
|
781
|
+
return this.log.wrap(
|
|
782
|
+
"getAccessToken",
|
|
783
|
+
void 0,
|
|
784
|
+
() => this.readAccessToken()
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
async readAccessToken() {
|
|
478
788
|
const sessionStore = this.config.sessionStore;
|
|
479
789
|
const session = await sessionStore.getSession();
|
|
480
790
|
if (session == null) return null;
|
|
@@ -486,12 +796,19 @@ var ServerAuthNamespaceImpl = class {
|
|
|
486
796
|
}
|
|
487
797
|
const setSession = sessionStore.setSession?.bind(sessionStore);
|
|
488
798
|
if (!setSession) {
|
|
799
|
+
this.log.child({ op: "getAccessToken" }).warn(() => ({
|
|
800
|
+
msg: "serving an expired token: the session store is read-only, so it cannot be refreshed"
|
|
801
|
+
}));
|
|
489
802
|
return session.accessToken;
|
|
490
803
|
}
|
|
491
804
|
return this.refreshSession(session.refreshToken, setSession);
|
|
492
805
|
}
|
|
493
806
|
async refreshSession(refreshToken, setSession) {
|
|
807
|
+
const log = this.log.child({ op: "refresh" });
|
|
494
808
|
if (!refreshToken) {
|
|
809
|
+
log.warn(() => ({
|
|
810
|
+
msg: "clearing the session: it carries no refresh token"
|
|
811
|
+
}));
|
|
495
812
|
await setSession(null);
|
|
496
813
|
return null;
|
|
497
814
|
}
|
|
@@ -508,26 +825,36 @@ var ServerAuthNamespaceImpl = class {
|
|
|
508
825
|
});
|
|
509
826
|
const newSession = OAuthSession.fromDto(sessionDto);
|
|
510
827
|
await setSession(newSession);
|
|
828
|
+
log.info(() => ({ msg: "session renewed" }));
|
|
511
829
|
return newSession.accessToken;
|
|
512
|
-
} catch {
|
|
830
|
+
} catch (error) {
|
|
831
|
+
log.failure(
|
|
832
|
+
() => ({ msg: "refresh failed; clearing the session" }),
|
|
833
|
+
error
|
|
834
|
+
);
|
|
513
835
|
await setSession(null);
|
|
514
836
|
return null;
|
|
515
837
|
}
|
|
516
838
|
}
|
|
517
839
|
async clientCredentials() {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
840
|
+
return this.log.wrap("clientCredentials", void 0, async () => {
|
|
841
|
+
const sessionDto = await this.api.send({
|
|
842
|
+
method: "POST",
|
|
843
|
+
url: `/oauth/token`,
|
|
844
|
+
body: {
|
|
845
|
+
grant_type: "client_credentials",
|
|
846
|
+
client_id: this.config.clientId,
|
|
847
|
+
client_secret: this.config.clientSecret
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
const session = OAuthSession.fromDto(sessionDto);
|
|
851
|
+
return ClientCredentialsOAuth(session.accessToken);
|
|
526
852
|
});
|
|
527
|
-
const session = OAuthSession.fromDto(sessionDto);
|
|
528
|
-
return ClientCredentialsOAuth(session.accessToken);
|
|
529
853
|
}
|
|
530
854
|
async logout() {
|
|
855
|
+
return this.log.wrap("logout", void 0, () => this.revokeAndClear());
|
|
856
|
+
}
|
|
857
|
+
async revokeAndClear() {
|
|
531
858
|
const setSession = this.writableSessionStore();
|
|
532
859
|
const session = await this.config.sessionStore.getSession();
|
|
533
860
|
if (session == null) return;
|
|
@@ -545,6 +872,9 @@ var ServerAuthNamespaceImpl = class {
|
|
|
545
872
|
if (!(err instanceof HttpError) || this.config.strict) {
|
|
546
873
|
throw err;
|
|
547
874
|
}
|
|
875
|
+
this.log.child({ op: "logout" }).warn(() => ({
|
|
876
|
+
msg: "the token was not revoked upstream; the local session is cleared regardless"
|
|
877
|
+
}));
|
|
548
878
|
}
|
|
549
879
|
await setSession(null);
|
|
550
880
|
}
|
|
@@ -578,52 +908,12 @@ async function fetchAllPages(fetchPage, baseParams) {
|
|
|
578
908
|
return items;
|
|
579
909
|
}
|
|
580
910
|
|
|
581
|
-
// src/shared/types/offer.ts
|
|
582
|
-
var OfferId = (value) => value;
|
|
583
|
-
var OfferSlug = (value) => value;
|
|
584
|
-
var Offer = {
|
|
585
|
-
fromDto: (dto) => ({
|
|
586
|
-
id: OfferId(dto.id),
|
|
587
|
-
slug: OfferSlug(dto.slug),
|
|
588
|
-
type: dto.type,
|
|
589
|
-
tagline: dto.tagline,
|
|
590
|
-
bannerUrl: dto.banner_url,
|
|
591
|
-
logoUrl: dto.logo_url,
|
|
592
|
-
startsAt: new Date(dto.starts_at),
|
|
593
|
-
endsAt: dto.ends_at ? new Date(dto.ends_at) : null
|
|
594
|
-
})
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
// src/shared/types/asset.ts
|
|
598
|
-
var AssetId = (value) => value;
|
|
599
|
-
var AssetCode = (value) => value;
|
|
600
|
-
var Asset = {
|
|
601
|
-
fromDto: (dto) => ({
|
|
602
|
-
id: AssetId(dto.id),
|
|
603
|
-
code: AssetCode(dto.code),
|
|
604
|
-
name: dto.name,
|
|
605
|
-
fractionalDigits: dto.fractional_digits
|
|
606
|
-
})
|
|
607
|
-
};
|
|
608
|
-
|
|
609
|
-
// src/shared/types/errors.ts
|
|
610
|
-
var NotAuthenticatedError = class extends Error {
|
|
611
|
-
constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
|
|
612
|
-
super(message);
|
|
613
|
-
this.name = "NotAuthenticatedError";
|
|
614
|
-
}
|
|
615
|
-
};
|
|
616
|
-
var ValidationError = class extends Error {
|
|
617
|
-
constructor(message) {
|
|
618
|
-
super(message);
|
|
619
|
-
this.name = "ValidationError";
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
|
|
623
911
|
// src/shared/types/blockchain/core.ts
|
|
624
912
|
var ETHEREUM_CHAINS = {
|
|
625
913
|
ethereum_mainnet: true,
|
|
626
|
-
ethereum_sepolia: true
|
|
914
|
+
ethereum_sepolia: true,
|
|
915
|
+
base_mainnet: true,
|
|
916
|
+
base_sepolia: true
|
|
627
917
|
};
|
|
628
918
|
var EthereumChain = (value) => {
|
|
629
919
|
if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
|
|
@@ -660,57 +950,133 @@ var STABLE_DECIMALS = AssetDecimals(6);
|
|
|
660
950
|
var DecimalString = (value) => value;
|
|
661
951
|
var MAX_UINT_256 = 2n ** 256n - 1n;
|
|
662
952
|
var assertUint256 = (value) => {
|
|
663
|
-
if (value
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
953
|
+
if (isUint256(value)) return value;
|
|
954
|
+
throw new InvariantError(`Value out of uint256 bounds: ${value}`);
|
|
955
|
+
};
|
|
956
|
+
var parseUint256 = (value, label) => {
|
|
957
|
+
if (isUint256(value)) return value;
|
|
958
|
+
throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
|
|
667
959
|
};
|
|
960
|
+
var isUint256 = (value) => value >= 0n && value <= MAX_UINT_256;
|
|
668
961
|
var BlockchainAmount = Object.assign(
|
|
669
962
|
(value) => value,
|
|
670
963
|
{
|
|
671
964
|
add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
|
|
672
|
-
sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
|
|
965
|
+
sub: (a, b) => combineAmounts(a, b, (x, y) => x - y),
|
|
966
|
+
mul: multiplyAmounts,
|
|
967
|
+
div: divideAmounts
|
|
673
968
|
}
|
|
674
969
|
);
|
|
970
|
+
function multiplyAmounts(a, b) {
|
|
971
|
+
const product = a.raw * b.raw;
|
|
972
|
+
return BlockchainAmount({
|
|
973
|
+
raw: product / 10n ** BigInt(b.decimals),
|
|
974
|
+
decimals: a.decimals
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
function divideAmounts(a, b) {
|
|
978
|
+
if (b.raw === 0n) {
|
|
979
|
+
throw new MathError("Cannot divide a BlockchainAmount by zero");
|
|
980
|
+
}
|
|
981
|
+
const scaled = a.raw * 10n ** BigInt(b.decimals);
|
|
982
|
+
return BlockchainAmount({ raw: scaled / b.raw, decimals: a.decimals });
|
|
983
|
+
}
|
|
675
984
|
function combineAmounts(a, b, op) {
|
|
676
985
|
if (a.decimals !== b.decimals) {
|
|
677
|
-
throw new
|
|
986
|
+
throw new InvariantError(
|
|
678
987
|
`Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
|
|
679
988
|
);
|
|
680
989
|
}
|
|
681
990
|
const raw = op(a.raw, b.raw);
|
|
682
991
|
if (raw < 0n || raw > MAX_UINT_256) {
|
|
683
|
-
throw new
|
|
992
|
+
throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);
|
|
684
993
|
}
|
|
685
994
|
return BlockchainAmount({ raw, decimals: a.decimals });
|
|
686
995
|
}
|
|
687
996
|
var AssetSymbol = (value) => value;
|
|
688
997
|
|
|
998
|
+
// src/shared/types/offer.ts
|
|
999
|
+
var OfferId = (value) => value;
|
|
1000
|
+
var OfferSlug = (value) => value;
|
|
1001
|
+
var Offer = {
|
|
1002
|
+
fromDto: (dto) => {
|
|
1003
|
+
if (!Array.isArray(dto.tokens)) {
|
|
1004
|
+
throw new ValidationError(
|
|
1005
|
+
`Offer.tokens: expected an array, got ${typeof dto.tokens}`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
id: OfferId(dto.id),
|
|
1010
|
+
slug: OfferSlug(dto.slug),
|
|
1011
|
+
type: dto.type,
|
|
1012
|
+
tagline: dto.tagline,
|
|
1013
|
+
bannerUrl: dto.banner_url,
|
|
1014
|
+
logoUrl: dto.logo_url,
|
|
1015
|
+
startsAt: new Date(dto.starts_at),
|
|
1016
|
+
endsAt: dto.ends_at ? new Date(dto.ends_at) : null,
|
|
1017
|
+
tokens: dto.tokens.map(OfferToken.fromDto)
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
var OfferToken = {
|
|
1022
|
+
fromDto: (dto) => ({
|
|
1023
|
+
role: dto.role,
|
|
1024
|
+
chain: Chain(dto.chain),
|
|
1025
|
+
address: EvmContractAddress(dto.address)
|
|
1026
|
+
})
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
// src/shared/types/asset.ts
|
|
1030
|
+
var AssetId = (value) => value;
|
|
1031
|
+
var AssetCode = (value) => value;
|
|
1032
|
+
var Asset = {
|
|
1033
|
+
fromDto: (dto) => ({
|
|
1034
|
+
id: AssetId(dto.id),
|
|
1035
|
+
code: AssetCode(dto.code),
|
|
1036
|
+
name: dto.name,
|
|
1037
|
+
fractionalDigits: dto.fractional_digits
|
|
1038
|
+
})
|
|
1039
|
+
};
|
|
1040
|
+
|
|
689
1041
|
// src/shared/types/offer-detail.ts
|
|
690
1042
|
var OfferOptionId = (value) => value;
|
|
691
1043
|
var OfferOptionSlug = (value) => value;
|
|
692
1044
|
var OfferDetail = {
|
|
693
1045
|
fromDto: (dto) => {
|
|
694
1046
|
if (!Array.isArray(dto.funding_assets)) {
|
|
695
|
-
throw new
|
|
1047
|
+
throw new ValidationError(
|
|
1048
|
+
`OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
|
|
1049
|
+
);
|
|
696
1050
|
}
|
|
697
1051
|
if (!Array.isArray(dto.options)) {
|
|
698
|
-
throw new
|
|
1052
|
+
throw new ValidationError(
|
|
1053
|
+
`OfferDetail.options: expected an array, got ${typeof dto.options}`
|
|
1054
|
+
);
|
|
699
1055
|
}
|
|
700
1056
|
if (!Array.isArray(dto.terms)) {
|
|
701
|
-
throw new
|
|
1057
|
+
throw new ValidationError(
|
|
1058
|
+
`OfferDetail.terms: expected an array, got ${typeof dto.terms}`
|
|
1059
|
+
);
|
|
702
1060
|
}
|
|
703
1061
|
if (!Array.isArray(dto.links)) {
|
|
704
|
-
throw new
|
|
1062
|
+
throw new ValidationError(
|
|
1063
|
+
`OfferDetail.links: expected an array, got ${typeof dto.links}`
|
|
1064
|
+
);
|
|
705
1065
|
}
|
|
706
1066
|
if (!Array.isArray(dto.faqs)) {
|
|
707
|
-
throw new
|
|
1067
|
+
throw new ValidationError(
|
|
1068
|
+
`OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
|
|
1069
|
+
);
|
|
708
1070
|
}
|
|
709
1071
|
if (!Array.isArray(dto.milestones)) {
|
|
710
|
-
throw new
|
|
1072
|
+
throw new ValidationError(
|
|
1073
|
+
`OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
|
|
1074
|
+
);
|
|
711
1075
|
}
|
|
712
1076
|
if (!Array.isArray(dto.tokens)) {
|
|
713
|
-
throw new
|
|
1077
|
+
throw new ValidationError(
|
|
1078
|
+
`OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
|
|
1079
|
+
);
|
|
714
1080
|
}
|
|
715
1081
|
return {
|
|
716
1082
|
id: OfferId(dto.id),
|
|
@@ -772,13 +1138,6 @@ var Milestone = {
|
|
|
772
1138
|
status: dto.status
|
|
773
1139
|
})
|
|
774
1140
|
};
|
|
775
|
-
var OfferToken = {
|
|
776
|
-
fromDto: (dto) => ({
|
|
777
|
-
role: dto.role,
|
|
778
|
-
chain: Chain(dto.chain),
|
|
779
|
-
address: EvmContractAddress(dto.address)
|
|
780
|
-
})
|
|
781
|
-
};
|
|
782
1141
|
|
|
783
1142
|
// src/shared/types/pagination.ts
|
|
784
1143
|
var Cursor = (value) => value;
|
|
@@ -838,18 +1197,25 @@ async function fetchOfferDetails(api, id, clientCreds) {
|
|
|
838
1197
|
var ServerOffersNamespaceImpl = class {
|
|
839
1198
|
constructor(ctx) {
|
|
840
1199
|
this.ctx = ctx;
|
|
1200
|
+
this.log = internalLogger(ctx.logger, "OFFERS");
|
|
841
1201
|
}
|
|
842
1202
|
async list(clientCreds) {
|
|
843
|
-
|
|
844
|
-
|
|
1203
|
+
return this.log.wrap("list", clientCreds, async () => {
|
|
1204
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1205
|
+
return fetchOffers(this.ctx.api, clientCreds);
|
|
1206
|
+
});
|
|
845
1207
|
}
|
|
846
1208
|
async listPage(params, clientCreds) {
|
|
847
|
-
|
|
848
|
-
|
|
1209
|
+
return this.log.wrap("listPage", { params, clientCreds }, async () => {
|
|
1210
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1211
|
+
return fetchOffersPage(this.ctx.api, params, clientCreds);
|
|
1212
|
+
});
|
|
849
1213
|
}
|
|
850
1214
|
async get(id, clientCreds) {
|
|
851
|
-
|
|
852
|
-
|
|
1215
|
+
return this.log.wrap("get", { id, clientCreds }, async () => {
|
|
1216
|
+
await this.ctx.ensureAuthenticated(clientCreds);
|
|
1217
|
+
return fetchOfferDetails(this.ctx.api, id, clientCreds);
|
|
1218
|
+
});
|
|
853
1219
|
}
|
|
854
1220
|
};
|
|
855
1221
|
|
|
@@ -982,38 +1348,49 @@ async function fetchPii(api) {
|
|
|
982
1348
|
var RequirementsNamespaceImpl = class {
|
|
983
1349
|
constructor(ctx) {
|
|
984
1350
|
this.ctx = ctx;
|
|
1351
|
+
this.log = internalLogger(ctx.logger, "REQUIREMENTS");
|
|
985
1352
|
}
|
|
986
1353
|
async forOffer(offerId) {
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1354
|
+
return this.log.wrap("forOffer", offerId, async () => {
|
|
1355
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1356
|
+
return fetchOfferRequirements(
|
|
1357
|
+
this.ctx.api,
|
|
1358
|
+
offerId,
|
|
1359
|
+
void 0
|
|
1360
|
+
);
|
|
1361
|
+
});
|
|
993
1362
|
}
|
|
994
1363
|
async statuses(offerId) {
|
|
995
|
-
|
|
996
|
-
|
|
1364
|
+
return this.log.wrap("statuses", offerId, async () => {
|
|
1365
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1366
|
+
return fetchRequirementStatuses(this.ctx.api, offerId);
|
|
1367
|
+
});
|
|
997
1368
|
}
|
|
998
1369
|
async createKycToken(params) {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1370
|
+
return this.log.wrap("createKycToken", params, async () => {
|
|
1371
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1372
|
+
return createKycToken(
|
|
1373
|
+
this.ctx.api,
|
|
1374
|
+
params?.levelName,
|
|
1375
|
+
params?.reset
|
|
1376
|
+
);
|
|
1377
|
+
});
|
|
1005
1378
|
}
|
|
1006
1379
|
async getPii() {
|
|
1007
|
-
|
|
1008
|
-
|
|
1380
|
+
return this.log.wrap("getPii", void 0, async () => {
|
|
1381
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1382
|
+
return fetchPii(this.ctx.api);
|
|
1383
|
+
});
|
|
1009
1384
|
}
|
|
1010
1385
|
async submitDocument(params) {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1386
|
+
return this.log.wrap("submitDocument", params, async () => {
|
|
1387
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1388
|
+
return submitDocument(
|
|
1389
|
+
this.ctx.api,
|
|
1390
|
+
params.documentType,
|
|
1391
|
+
params.fields
|
|
1392
|
+
);
|
|
1393
|
+
});
|
|
1017
1394
|
}
|
|
1018
1395
|
};
|
|
1019
1396
|
|
|
@@ -1024,12 +1401,14 @@ var ServerRequirementsNamespaceImpl = class extends RequirementsNamespaceImpl {
|
|
|
1024
1401
|
this.serverCtx = serverCtx;
|
|
1025
1402
|
}
|
|
1026
1403
|
async forOffer(offerId, clientCreds) {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1404
|
+
return this.log.wrap("forOffer", { offerId, clientCreds }, async () => {
|
|
1405
|
+
await this.serverCtx.ensureAuthenticated(clientCreds);
|
|
1406
|
+
return fetchOfferRequirements(
|
|
1407
|
+
this.serverCtx.api,
|
|
1408
|
+
offerId,
|
|
1409
|
+
clientCreds
|
|
1410
|
+
);
|
|
1411
|
+
});
|
|
1033
1412
|
}
|
|
1034
1413
|
};
|
|
1035
1414
|
|
|
@@ -1044,25 +1423,31 @@ var SwapAuthorization = {
|
|
|
1044
1423
|
};
|
|
1045
1424
|
var SwapPreview = {
|
|
1046
1425
|
fromDto: (dto) => ({
|
|
1047
|
-
inputAmount:
|
|
1048
|
-
|
|
1049
|
-
|
|
1426
|
+
inputAmount: parseUint256(
|
|
1427
|
+
BigInt(dto.pay_input_amount),
|
|
1428
|
+
"SwapPreview.pay_input_amount"
|
|
1429
|
+
),
|
|
1430
|
+
fee: parseUint256(BigInt(dto.fee), "SwapPreview.fee"),
|
|
1431
|
+
outputAmount: parseUint256(
|
|
1432
|
+
BigInt(dto.receive_output_amount),
|
|
1433
|
+
"SwapPreview.receive_output_amount"
|
|
1434
|
+
)
|
|
1050
1435
|
})
|
|
1051
1436
|
};
|
|
1052
1437
|
var SwapStatus = {
|
|
1053
1438
|
fromDto: (dto) => ({
|
|
1054
|
-
stopped:
|
|
1055
|
-
swapLevel:
|
|
1439
|
+
stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
|
|
1440
|
+
swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
|
|
1056
1441
|
})
|
|
1057
1442
|
};
|
|
1058
1443
|
var TokenAllowance = {
|
|
1059
1444
|
fromDto: (dto) => ({
|
|
1060
|
-
allowance:
|
|
1445
|
+
allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
|
|
1061
1446
|
})
|
|
1062
1447
|
};
|
|
1063
1448
|
var TokenBalance = {
|
|
1064
1449
|
fromDto: (dto) => ({
|
|
1065
|
-
balance:
|
|
1450
|
+
balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
|
|
1066
1451
|
})
|
|
1067
1452
|
};
|
|
1068
1453
|
var AllowWalletResponse = {
|
|
@@ -1191,14 +1576,19 @@ function toErc20Asset(dto) {
|
|
|
1191
1576
|
var Erc20NamespaceImpl = class {
|
|
1192
1577
|
constructor(ctx) {
|
|
1193
1578
|
this.ctx = ctx;
|
|
1579
|
+
this.log = internalLogger(ctx.logger, "ERC20");
|
|
1194
1580
|
}
|
|
1195
1581
|
async getAllowance(params) {
|
|
1196
|
-
|
|
1197
|
-
|
|
1582
|
+
return this.log.wrap("getAllowance", params, async () => {
|
|
1583
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1584
|
+
return getTokenAllowance(this.ctx.api, params);
|
|
1585
|
+
});
|
|
1198
1586
|
}
|
|
1199
1587
|
async getBalance(params) {
|
|
1200
|
-
|
|
1201
|
-
|
|
1588
|
+
return this.log.wrap("getBalance", params, async () => {
|
|
1589
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1590
|
+
return getTokenBalance(this.ctx.api, params);
|
|
1591
|
+
});
|
|
1202
1592
|
}
|
|
1203
1593
|
};
|
|
1204
1594
|
|
|
@@ -1287,22 +1677,31 @@ async function createParticipation(api, params) {
|
|
|
1287
1677
|
var CoinListTokenSaleNamespaceImpl = class {
|
|
1288
1678
|
constructor(ctx) {
|
|
1289
1679
|
this.ctx = ctx;
|
|
1680
|
+
this.log = internalLogger(ctx.logger, "TOKEN_SALE");
|
|
1290
1681
|
}
|
|
1291
1682
|
async list(offerId) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1683
|
+
return this.log.wrap("list", offerId, async () => {
|
|
1684
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1685
|
+
return fetchParticipations(this.ctx.api, offerId);
|
|
1686
|
+
});
|
|
1294
1687
|
}
|
|
1295
1688
|
async listPage(params) {
|
|
1296
|
-
|
|
1297
|
-
|
|
1689
|
+
return this.log.wrap("listPage", params, async () => {
|
|
1690
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1691
|
+
return fetchParticipationsPage(this.ctx.api, params);
|
|
1692
|
+
});
|
|
1298
1693
|
}
|
|
1299
1694
|
async get(id) {
|
|
1300
|
-
|
|
1301
|
-
|
|
1695
|
+
return this.log.wrap("get", id, async () => {
|
|
1696
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1697
|
+
return fetchParticipation(this.ctx.api, id);
|
|
1698
|
+
});
|
|
1302
1699
|
}
|
|
1303
1700
|
async createParticipation(params) {
|
|
1304
|
-
|
|
1305
|
-
|
|
1701
|
+
return this.log.wrap("createParticipation", params, async () => {
|
|
1702
|
+
await this.ctx.ensureUserAuthenticated();
|
|
1703
|
+
return createParticipation(this.ctx.api, params);
|
|
1704
|
+
});
|
|
1306
1705
|
}
|
|
1307
1706
|
};
|
|
1308
1707
|
|
|
@@ -1322,7 +1721,9 @@ var USD_FRACTION_DIGITS = AssetDecimals(2);
|
|
|
1322
1721
|
// src/shared/core/blockchain/chain.ts
|
|
1323
1722
|
var CHAIN_IDS = {
|
|
1324
1723
|
ethereum_mainnet: 1,
|
|
1325
|
-
ethereum_sepolia: 11155111
|
|
1724
|
+
ethereum_sepolia: 11155111,
|
|
1725
|
+
base_mainnet: 8453,
|
|
1726
|
+
base_sepolia: 84532
|
|
1326
1727
|
};
|
|
1327
1728
|
function chainFromId(chainId) {
|
|
1328
1729
|
const chains = Object.keys(CHAIN_IDS);
|
|
@@ -1398,47 +1799,122 @@ var OndoQuote = {
|
|
|
1398
1799
|
};
|
|
1399
1800
|
}
|
|
1400
1801
|
};
|
|
1401
|
-
var
|
|
1802
|
+
var OndoBuyTransaction = {
|
|
1402
1803
|
fromDto: (dto) => {
|
|
1403
|
-
const
|
|
1804
|
+
const spendDecimals = AssetDecimals(dto.spend_input_decimals);
|
|
1404
1805
|
const outputDecimals = AssetDecimals(dto.receive_output_decimals);
|
|
1405
1806
|
return {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
data: HexEncodedTransactionData(dto.data)
|
|
1409
|
-
},
|
|
1410
|
-
expiresAt: parseExpiresAt(dto.expires_at),
|
|
1411
|
-
payInputAmount: blockchainAmountFromRawOrThrow({
|
|
1412
|
-
label: "pay_input_amount",
|
|
1413
|
-
raw: dto.pay_input_amount,
|
|
1414
|
-
decimals: inputDecimals
|
|
1415
|
-
}),
|
|
1807
|
+
...parseSwapCore(dto, spendDecimals),
|
|
1808
|
+
side: "buy",
|
|
1416
1809
|
fee: blockchainAmountFromRawOrThrow({
|
|
1417
1810
|
label: "fee",
|
|
1418
1811
|
raw: dto.fee,
|
|
1419
|
-
decimals:
|
|
1812
|
+
decimals: spendDecimals
|
|
1420
1813
|
}),
|
|
1421
1814
|
notionalValue: blockchainAmountFromRawOrThrow({
|
|
1422
1815
|
label: "notional_value",
|
|
1423
1816
|
raw: dto.notional_value,
|
|
1424
|
-
decimals:
|
|
1817
|
+
decimals: spendDecimals
|
|
1425
1818
|
}),
|
|
1426
|
-
receiveOutputAmount:
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1819
|
+
receiveOutputAmount: parsePositiveAmount({
|
|
1820
|
+
label: "receive_output_amount",
|
|
1821
|
+
raw: dto.receive_output_amount,
|
|
1822
|
+
decimals: outputDecimals,
|
|
1823
|
+
// A transaction that yields nothing is not one to sign - the user
|
|
1824
|
+
// would pay the deposit and receive no asset - and frontline refuses
|
|
1825
|
+
// to emit one. A zero here is a changed encoding, not a small order.
|
|
1826
|
+
// Rejecting it at the boundary is also what lets `computeOndoBuyPrice`
|
|
1827
|
+
// divide by it without a fallible result: the failure surfaces as the
|
|
1828
|
+
// data hook's ERROR state rather than as a division during render.
|
|
1829
|
+
reason: "a buy that yields nothing is not fillable"
|
|
1830
|
+
})
|
|
1430
1831
|
};
|
|
1431
1832
|
}
|
|
1432
1833
|
};
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1834
|
+
var OndoSellTransaction = {
|
|
1835
|
+
fromDto: (dto) => {
|
|
1836
|
+
const spendDecimals = AssetDecimals(dto.spend_input_decimals);
|
|
1837
|
+
const outputDecimals = AssetDecimals(dto.receive_output_decimals);
|
|
1838
|
+
const expectedQuantity = parsePositiveAmount({
|
|
1839
|
+
label: "expected_quantity",
|
|
1840
|
+
raw: dto.expected_quantity,
|
|
1841
|
+
decimals: outputDecimals,
|
|
1842
|
+
reason: "a sale that yields nothing is not fillable"
|
|
1843
|
+
});
|
|
1844
|
+
return {
|
|
1845
|
+
...parseSwapCore(dto, spendDecimals),
|
|
1846
|
+
side: "sell",
|
|
1847
|
+
expected: {
|
|
1848
|
+
quantity: expectedQuantity,
|
|
1849
|
+
fee: blockchainAmountFromRawOrThrow({
|
|
1850
|
+
label: "expected_fee",
|
|
1851
|
+
raw: dto.expected_fee,
|
|
1852
|
+
decimals: outputDecimals
|
|
1853
|
+
})
|
|
1854
|
+
},
|
|
1855
|
+
minimum: {
|
|
1856
|
+
quantity: parseMinimumQuantity(
|
|
1857
|
+
dto.minimum_quantity,
|
|
1858
|
+
outputDecimals,
|
|
1859
|
+
expectedQuantity
|
|
1860
|
+
),
|
|
1861
|
+
fee: blockchainAmountFromRawOrThrow({
|
|
1862
|
+
label: "minimum_fee",
|
|
1863
|
+
raw: dto.minimum_fee,
|
|
1864
|
+
decimals: outputDecimals
|
|
1865
|
+
})
|
|
1866
|
+
}
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1869
|
+
};
|
|
1870
|
+
function parseSwapCore(dto, spendDecimals) {
|
|
1871
|
+
return {
|
|
1872
|
+
tx: {
|
|
1873
|
+
to: EvmContractAddress(dto.to),
|
|
1874
|
+
data: HexEncodedTransactionData(dto.data)
|
|
1875
|
+
},
|
|
1876
|
+
expiresAt: parseExpiresAt(dto.expires_at),
|
|
1877
|
+
spendInputAmount: parsePositiveAmount({
|
|
1878
|
+
label: "spend_input_amount",
|
|
1879
|
+
raw: dto.spend_input_amount,
|
|
1880
|
+
decimals: spendDecimals,
|
|
1881
|
+
// A transaction that takes nothing from the wallet is not one to sign:
|
|
1882
|
+
// it would settle one leg of a trade and skip the other. Frontline
|
|
1883
|
+
// refuses an `amount` of zero whichever way the trade runs, so this is a
|
|
1884
|
+
// changed encoding rather than a small order.
|
|
1885
|
+
//
|
|
1886
|
+
// Guarded on both sides rather than on the sale alone, because which
|
|
1887
|
+
// amount becomes the divisor in the price flips with the direction: a
|
|
1888
|
+
// guard placed by that would be a rule about the arithmetic rather than
|
|
1889
|
+
// about the trade.
|
|
1890
|
+
reason: "a swap that spends nothing is not fillable"
|
|
1891
|
+
})
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
function parseMinimumQuantity(raw, decimals, expectedQuantity) {
|
|
1895
|
+
const amount = parsePositiveAmount({
|
|
1896
|
+
label: "minimum_quantity",
|
|
1436
1897
|
raw,
|
|
1437
|
-
decimals
|
|
1898
|
+
decimals,
|
|
1899
|
+
reason: "a floor of zero guarantees nothing"
|
|
1438
1900
|
});
|
|
1901
|
+
if (amount.raw > expectedQuantity.raw) {
|
|
1902
|
+
throw new ValidationError(
|
|
1903
|
+
`minimum_quantity: must not exceed expected_quantity ("${raw}" > "${expectedQuantity.raw}")`
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
return amount;
|
|
1907
|
+
}
|
|
1908
|
+
function parsePositiveAmount({
|
|
1909
|
+
label,
|
|
1910
|
+
raw,
|
|
1911
|
+
decimals,
|
|
1912
|
+
reason
|
|
1913
|
+
}) {
|
|
1914
|
+
const amount = blockchainAmountFromRawOrThrow({ label, raw, decimals });
|
|
1439
1915
|
if (amount.raw <= 0n) {
|
|
1440
1916
|
throw new ValidationError(
|
|
1441
|
-
|
|
1917
|
+
`${label}: must be greater than zero ("${raw}") - ${reason}`
|
|
1442
1918
|
);
|
|
1443
1919
|
}
|
|
1444
1920
|
return amount;
|
|
@@ -1475,27 +1951,57 @@ async function getOndoQuote(api, params) {
|
|
|
1475
1951
|
});
|
|
1476
1952
|
return OndoQuote.fromDto(dto);
|
|
1477
1953
|
}
|
|
1478
|
-
async function
|
|
1954
|
+
async function buildOndoBuy(api, params) {
|
|
1479
1955
|
const dto = await api.send({
|
|
1480
1956
|
method: "POST",
|
|
1481
|
-
url: "/v1/ondo/swap/
|
|
1482
|
-
body:
|
|
1483
|
-
symbol: params.symbol,
|
|
1484
|
-
chain: params.chain,
|
|
1485
|
-
wallet_address: params.walletAddress,
|
|
1486
|
-
amount: params.amount.raw.toString()
|
|
1487
|
-
},
|
|
1957
|
+
url: "/v1/ondo/swap/buy",
|
|
1958
|
+
body: swapBody(params),
|
|
1488
1959
|
attributes: Attributes.protected()
|
|
1489
1960
|
});
|
|
1490
|
-
|
|
1491
|
-
|
|
1961
|
+
assertSpendScaleAgrees({
|
|
1962
|
+
published: dto.spend_input_decimals,
|
|
1963
|
+
sized: params.amount,
|
|
1964
|
+
trade: "purchase"
|
|
1965
|
+
});
|
|
1966
|
+
return OndoBuyTransaction.fromDto(dto);
|
|
1492
1967
|
}
|
|
1493
|
-
function
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
)
|
|
1498
|
-
|
|
1968
|
+
async function buildOndoSell(api, params) {
|
|
1969
|
+
const dto = await api.send({
|
|
1970
|
+
method: "POST",
|
|
1971
|
+
url: "/v1/ondo/swap/sell",
|
|
1972
|
+
body: swapBody(params),
|
|
1973
|
+
attributes: Attributes.protected()
|
|
1974
|
+
});
|
|
1975
|
+
assertSpendScaleAgrees({
|
|
1976
|
+
published: dto.spend_input_decimals,
|
|
1977
|
+
sized: params.amount,
|
|
1978
|
+
trade: "sale",
|
|
1979
|
+
// The two answers come from two chains, so on a testnet they can disagree
|
|
1980
|
+
// for a reason that is neither the caller's nor a corrupt response. Say so,
|
|
1981
|
+
// or a QA run reads as a puzzle rather than a diagnosis.
|
|
1982
|
+
note: "the quote resolves the asset on Ethereum mainnet while the swap executes on the chain requested, so these disagree until frontline serves a chain-scoped quote"
|
|
1983
|
+
});
|
|
1984
|
+
return OndoSellTransaction.fromDto(dto);
|
|
1985
|
+
}
|
|
1986
|
+
function swapBody(params) {
|
|
1987
|
+
return {
|
|
1988
|
+
symbol: params.symbol,
|
|
1989
|
+
chain: params.chain,
|
|
1990
|
+
wallet_address: params.walletAddress,
|
|
1991
|
+
amount: params.amount.raw.toString()
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
function assertSpendScaleAgrees({
|
|
1995
|
+
published,
|
|
1996
|
+
sized,
|
|
1997
|
+
trade,
|
|
1998
|
+
note
|
|
1999
|
+
}) {
|
|
2000
|
+
if (published === sized.decimals) return;
|
|
2001
|
+
const because = note === void 0 ? "" : ` - ${note}`;
|
|
2002
|
+
throw new ValidationError(
|
|
2003
|
+
`spend_input_decimals: the ${trade} was priced in ${published} decimals but the order was sized in ${sized.decimals}${because}`
|
|
2004
|
+
);
|
|
1499
2005
|
}
|
|
1500
2006
|
function sizeParam(params) {
|
|
1501
2007
|
const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
|
|
@@ -1520,18 +2026,31 @@ function sizeParam(params) {
|
|
|
1520
2026
|
var OndoNamespaceImpl = class {
|
|
1521
2027
|
constructor(ctx) {
|
|
1522
2028
|
this.ctx = ctx;
|
|
2029
|
+
this.log = internalLogger(ctx.logger, "ONDO");
|
|
1523
2030
|
}
|
|
1524
2031
|
async getTradingStatus(params) {
|
|
1525
|
-
|
|
1526
|
-
|
|
2032
|
+
return this.log.wrap("getTradingStatus", params, async () => {
|
|
2033
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2034
|
+
return getOndoTradingStatus(this.ctx.api, params);
|
|
2035
|
+
});
|
|
1527
2036
|
}
|
|
1528
2037
|
async getQuote(params) {
|
|
1529
|
-
|
|
1530
|
-
|
|
2038
|
+
return this.log.wrap("getQuote", params, async () => {
|
|
2039
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2040
|
+
return getOndoQuote(this.ctx.api, params);
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
2043
|
+
async buildBuyTransaction(params) {
|
|
2044
|
+
return this.log.wrap("buildBuyTransaction", params, async () => {
|
|
2045
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2046
|
+
return buildOndoBuy(this.ctx.api, params);
|
|
2047
|
+
});
|
|
1531
2048
|
}
|
|
1532
|
-
async
|
|
1533
|
-
|
|
1534
|
-
|
|
2049
|
+
async buildSellTransaction(params) {
|
|
2050
|
+
return this.log.wrap("buildSellTransaction", params, async () => {
|
|
2051
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2052
|
+
return buildOndoSell(this.ctx.api, params);
|
|
2053
|
+
});
|
|
1535
2054
|
}
|
|
1536
2055
|
};
|
|
1537
2056
|
|
|
@@ -1539,26 +2058,37 @@ var OndoNamespaceImpl = class {
|
|
|
1539
2058
|
var SuperstateSwapNamespaceImpl = class {
|
|
1540
2059
|
constructor(ctx) {
|
|
1541
2060
|
this.ctx = ctx;
|
|
2061
|
+
this.log = internalLogger(ctx.logger, "SUPERSTATE");
|
|
1542
2062
|
}
|
|
1543
2063
|
async getAuthorization(params) {
|
|
1544
|
-
|
|
1545
|
-
|
|
2064
|
+
return this.log.wrap("getAuthorization", params, async () => {
|
|
2065
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2066
|
+
return getSwapAuthorization(this.ctx.api, params);
|
|
2067
|
+
});
|
|
1546
2068
|
}
|
|
1547
2069
|
async getPreview(params) {
|
|
1548
|
-
|
|
1549
|
-
|
|
2070
|
+
return this.log.wrap("getPreview", params, async () => {
|
|
2071
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2072
|
+
return getSwapPreview(this.ctx.api, params);
|
|
2073
|
+
});
|
|
1550
2074
|
}
|
|
1551
2075
|
async getStatus(params) {
|
|
1552
|
-
|
|
1553
|
-
|
|
2076
|
+
return this.log.wrap("getStatus", params, async () => {
|
|
2077
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2078
|
+
return getSwapStatus(this.ctx.api, params);
|
|
2079
|
+
});
|
|
1554
2080
|
}
|
|
1555
2081
|
async getOutputToken(params) {
|
|
1556
|
-
|
|
1557
|
-
|
|
2082
|
+
return this.log.wrap("getOutputToken", params, async () => {
|
|
2083
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2084
|
+
return getSwapOutputToken(this.ctx.api, params);
|
|
2085
|
+
});
|
|
1558
2086
|
}
|
|
1559
2087
|
async allowWallet(params) {
|
|
1560
|
-
|
|
1561
|
-
|
|
2088
|
+
return this.log.wrap("allowWallet", params, async () => {
|
|
2089
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2090
|
+
return allowWallet(this.ctx.api, params);
|
|
2091
|
+
});
|
|
1562
2092
|
}
|
|
1563
2093
|
};
|
|
1564
2094
|
|
|
@@ -1591,27 +2121,47 @@ var TokenMetadata = {
|
|
|
1591
2121
|
logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
|
|
1592
2122
|
};
|
|
1593
2123
|
},
|
|
2124
|
+
/**
|
|
2125
|
+
* Maps the complete registry snapshot to every token it lists across the
|
|
2126
|
+
* chains this SDK models, skipping native coins and chains outside
|
|
2127
|
+
* {@link EthereumChain} (e.g. Solana) rather than failing on them — the
|
|
2128
|
+
* registry may serve chains ahead of the SDK's type surface.
|
|
2129
|
+
*/
|
|
2130
|
+
fromRegistryDto: (dto, baseUrl) => {
|
|
2131
|
+
assertSupportedSchemaVersion(dto.schema_version);
|
|
2132
|
+
return dto.chains.flatMap((chainDto) => {
|
|
2133
|
+
let chain;
|
|
2134
|
+
try {
|
|
2135
|
+
chain = EthereumChain(chainDto.chain);
|
|
2136
|
+
} catch {
|
|
2137
|
+
return [];
|
|
2138
|
+
}
|
|
2139
|
+
return tokensOfChain(chain, chainDto.assets, baseUrl);
|
|
2140
|
+
});
|
|
2141
|
+
},
|
|
1594
2142
|
/**
|
|
1595
2143
|
* Maps a chain snapshot to the tokens it lists, skipping the chain's native
|
|
1596
2144
|
* coin (`kind: 'COIN'`, no contract address).
|
|
1597
2145
|
*/
|
|
1598
2146
|
fromChainAssetsDto: (dto, baseUrl) => {
|
|
1599
2147
|
assertSupportedSchemaVersion(dto.schema_version);
|
|
1600
|
-
|
|
1601
|
-
return dto.assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
|
|
1602
|
-
identifier: {
|
|
1603
|
-
chain,
|
|
1604
|
-
// The filter above cannot narrow `address` for the type checker.
|
|
1605
|
-
address: EvmContractAddress(asset.address)
|
|
1606
|
-
},
|
|
1607
|
-
name: asset.name,
|
|
1608
|
-
symbol: AssetSymbol(asset.symbol),
|
|
1609
|
-
decimals: AssetDecimals(asset.decimals),
|
|
1610
|
-
logo: TokenLogo.fromDto(asset.logo, baseUrl),
|
|
1611
|
-
logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
|
|
1612
|
-
}));
|
|
2148
|
+
return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);
|
|
1613
2149
|
}
|
|
1614
2150
|
};
|
|
2151
|
+
function tokensOfChain(chain, assets, baseUrl) {
|
|
2152
|
+
return assets.filter((asset) => asset.kind === "TOKEN" && asset.address !== void 0).map((asset) => ({
|
|
2153
|
+
identifier: {
|
|
2154
|
+
chain,
|
|
2155
|
+
// The filter above cannot narrow `address` for the type checker.
|
|
2156
|
+
address: EvmContractAddress(asset.address)
|
|
2157
|
+
},
|
|
2158
|
+
name: asset.name,
|
|
2159
|
+
symbol: AssetSymbol(asset.symbol),
|
|
2160
|
+
decimals: AssetDecimals(asset.decimals),
|
|
2161
|
+
logo: TokenLogo.fromDto(asset.logo, baseUrl),
|
|
2162
|
+
logoDark: asset.logo_dark === void 0 ? null : TokenLogo.fromDto(asset.logo_dark, baseUrl)
|
|
2163
|
+
}));
|
|
2164
|
+
}
|
|
1615
2165
|
function assertSupportedSchemaVersion(version) {
|
|
1616
2166
|
if (version !== 1) {
|
|
1617
2167
|
throw new ValidationError(
|
|
@@ -1629,8 +2179,8 @@ var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
|
|
|
1629
2179
|
);
|
|
1630
2180
|
|
|
1631
2181
|
// src/shared/api/nabu/tokens.ts
|
|
1632
|
-
function createNabuApiClient(baseUrl) {
|
|
1633
|
-
return new HttpClient({ baseUrl });
|
|
2182
|
+
function createNabuApiClient(baseUrl, logger = null) {
|
|
2183
|
+
return new HttpClient({ baseUrl }, {}, logger);
|
|
1634
2184
|
}
|
|
1635
2185
|
async function fetchTokenMetadata(client, token) {
|
|
1636
2186
|
const address = checksummed(token.address);
|
|
@@ -1680,6 +2230,29 @@ async function fetchTokensMetadata(client, chain) {
|
|
|
1680
2230
|
}
|
|
1681
2231
|
return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
|
|
1682
2232
|
}
|
|
2233
|
+
async function fetchAllTokensMetadata(client) {
|
|
2234
|
+
let response;
|
|
2235
|
+
try {
|
|
2236
|
+
response = await client.send({
|
|
2237
|
+
method: "GET",
|
|
2238
|
+
url: `/assets.json`
|
|
2239
|
+
});
|
|
2240
|
+
} catch (error) {
|
|
2241
|
+
if (isRegistryHtmlFallback(error)) {
|
|
2242
|
+
throw new ValidationError(
|
|
2243
|
+
"Token registry returned non-JSON for the complete snapshot"
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
throw error;
|
|
2247
|
+
}
|
|
2248
|
+
assertOk(response);
|
|
2249
|
+
if (response.body === null) {
|
|
2250
|
+
throw new ValidationError(
|
|
2251
|
+
"Token registry returned an empty complete snapshot"
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);
|
|
2255
|
+
}
|
|
1683
2256
|
function isRegistryHtmlFallback(error) {
|
|
1684
2257
|
return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
|
|
1685
2258
|
}
|
|
@@ -1703,14 +2276,23 @@ var TokensNamespaceImpl = class {
|
|
|
1703
2276
|
* registry is unauthenticated and on its own host, so the frontline sender
|
|
1704
2277
|
* and the auth check would both be dead weight here.
|
|
1705
2278
|
*/
|
|
1706
|
-
constructor(baseUrl) {
|
|
1707
|
-
this.api = createNabuApiClient(baseUrl);
|
|
2279
|
+
constructor(baseUrl, logger = null) {
|
|
2280
|
+
this.api = createNabuApiClient(baseUrl, logger);
|
|
2281
|
+
this.log = internalLogger(logger, "TOKENS");
|
|
1708
2282
|
}
|
|
1709
2283
|
get(token) {
|
|
1710
|
-
return
|
|
2284
|
+
return this.log.wrap(
|
|
2285
|
+
"get",
|
|
2286
|
+
token,
|
|
2287
|
+
() => fetchTokenMetadata(this.api, token)
|
|
2288
|
+
);
|
|
1711
2289
|
}
|
|
1712
2290
|
list(chain) {
|
|
1713
|
-
return
|
|
2291
|
+
return this.log.wrap(
|
|
2292
|
+
"list",
|
|
2293
|
+
chain,
|
|
2294
|
+
() => chain === void 0 ? fetchAllTokensMetadata(this.api) : fetchTokensMetadata(this.api, chain)
|
|
2295
|
+
);
|
|
1714
2296
|
}
|
|
1715
2297
|
};
|
|
1716
2298
|
|
|
@@ -1816,33 +2398,42 @@ async function removeOptionAddress(api, offerId, addressId) {
|
|
|
1816
2398
|
var WalletsNamespaceImpl = class {
|
|
1817
2399
|
constructor(ctx) {
|
|
1818
2400
|
this.ctx = ctx;
|
|
2401
|
+
this.log = internalLogger(ctx.logger, "WALLETS");
|
|
1819
2402
|
}
|
|
1820
2403
|
async createOwnershipChallenge(params) {
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
2404
|
+
return this.log.wrap("createOwnershipChallenge", params, async () => {
|
|
2405
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2406
|
+
return createWalletOwnershipChallenge(
|
|
2407
|
+
this.ctx.api,
|
|
2408
|
+
params
|
|
2409
|
+
);
|
|
2410
|
+
});
|
|
1826
2411
|
}
|
|
1827
2412
|
async connectExternal(params) {
|
|
1828
|
-
|
|
1829
|
-
|
|
2413
|
+
return this.log.wrap("connectExternal", params, async () => {
|
|
2414
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2415
|
+
return connectExternalWallet(this.ctx.api, params);
|
|
2416
|
+
});
|
|
1830
2417
|
}
|
|
1831
2418
|
async list(params) {
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
2419
|
+
return this.log.wrap("list", params, async () => {
|
|
2420
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2421
|
+
return listOptionAddresses(
|
|
2422
|
+
this.ctx.api,
|
|
2423
|
+
params.offerId,
|
|
2424
|
+
params.offerOptionId
|
|
2425
|
+
);
|
|
2426
|
+
});
|
|
1838
2427
|
}
|
|
1839
2428
|
async remove(params) {
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
2429
|
+
return this.log.wrap("remove", params, async () => {
|
|
2430
|
+
await this.ctx.ensureUserAuthenticated();
|
|
2431
|
+
return removeOptionAddress(
|
|
2432
|
+
this.ctx.api,
|
|
2433
|
+
params.offerId,
|
|
2434
|
+
params.addressId
|
|
2435
|
+
);
|
|
2436
|
+
});
|
|
1846
2437
|
}
|
|
1847
2438
|
};
|
|
1848
2439
|
|
|
@@ -1851,6 +2442,7 @@ var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
|
|
|
1851
2442
|
var CoinListServerImpl = class {
|
|
1852
2443
|
constructor(_config) {
|
|
1853
2444
|
this._config = _config;
|
|
2445
|
+
const logger = _config.logger ?? null;
|
|
1854
2446
|
this.api = new ApiClient(
|
|
1855
2447
|
{
|
|
1856
2448
|
baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
|
|
@@ -1860,7 +2452,8 @@ var CoinListServerImpl = class {
|
|
|
1860
2452
|
// fresh token. A read-only store cannot persist a new session, so return
|
|
1861
2453
|
// null immediately — this tells the middleware to skip the retry rather
|
|
1862
2454
|
// than re-sending with the same expired token and wasting a round-trip.
|
|
1863
|
-
(refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.auth.getAccessToken()
|
|
2455
|
+
(refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.auth.getAccessToken(),
|
|
2456
|
+
logger
|
|
1864
2457
|
);
|
|
1865
2458
|
this.auth = new ServerAuthNamespaceImpl(this.api, {
|
|
1866
2459
|
..._config,
|
|
@@ -1869,6 +2462,7 @@ var CoinListServerImpl = class {
|
|
|
1869
2462
|
});
|
|
1870
2463
|
const ctx = {
|
|
1871
2464
|
api: this.api,
|
|
2465
|
+
logger,
|
|
1872
2466
|
ensureUserAuthenticated: () => this.ensureAuthenticated(void 0),
|
|
1873
2467
|
ensureAuthenticated: (clientCreds) => this.ensureAuthenticated(clientCreds)
|
|
1874
2468
|
};
|
|
@@ -1880,7 +2474,8 @@ var CoinListServerImpl = class {
|
|
|
1880
2474
|
this.superstate = new SuperstateSwapNamespaceImpl(ctx);
|
|
1881
2475
|
this.ondo = new OndoNamespaceImpl(ctx);
|
|
1882
2476
|
this.tokens = new TokensNamespaceImpl(
|
|
1883
|
-
_config.tokensBaseUrl ?? NABU_BASE_URL
|
|
2477
|
+
_config.tokensBaseUrl ?? NABU_BASE_URL,
|
|
2478
|
+
logger
|
|
1884
2479
|
);
|
|
1885
2480
|
}
|
|
1886
2481
|
/**
|
|
@@ -1898,12 +2493,157 @@ var CoinListServerImpl = class {
|
|
|
1898
2493
|
function createCoinListServer(config) {
|
|
1899
2494
|
return new CoinListServerImpl(config);
|
|
1900
2495
|
}
|
|
2496
|
+
|
|
2497
|
+
// src/server/core/observability/pino-server-logger.ts
|
|
2498
|
+
var import_pino = require("pino");
|
|
2499
|
+
|
|
2500
|
+
// src/shared/core/observability/pino-logger.ts
|
|
2501
|
+
function toPinoRecord(event) {
|
|
2502
|
+
try {
|
|
2503
|
+
const record = {};
|
|
2504
|
+
for (const key of ownKeys(event.fields)) {
|
|
2505
|
+
record[key] = readProperty(event.fields, key, 0, /* @__PURE__ */ new WeakSet());
|
|
2506
|
+
}
|
|
2507
|
+
const cause = "cause" in event ? event.cause : void 0;
|
|
2508
|
+
if (cause !== void 0) {
|
|
2509
|
+
record.cause = sanitize(cause, 0, /* @__PURE__ */ new WeakSet());
|
|
2510
|
+
}
|
|
2511
|
+
return { ...record, scope: event.scope, ...event.bindings };
|
|
2512
|
+
} catch (_) {
|
|
2513
|
+
return { "log.render": "<unrenderable event>" };
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
var PINO_LEVEL = {
|
|
2517
|
+
none: "silent",
|
|
2518
|
+
error: "error",
|
|
2519
|
+
warn: "warn",
|
|
2520
|
+
info: "info",
|
|
2521
|
+
debug: "debug"
|
|
2522
|
+
};
|
|
2523
|
+
var MAX_DEPTH = 8;
|
|
2524
|
+
function sanitize(value, depth, seen) {
|
|
2525
|
+
switch (typeof value) {
|
|
2526
|
+
case "string":
|
|
2527
|
+
case "boolean":
|
|
2528
|
+
return value;
|
|
2529
|
+
case "number":
|
|
2530
|
+
return Number.isFinite(value) ? value : String(value);
|
|
2531
|
+
case "bigint":
|
|
2532
|
+
return value.toString();
|
|
2533
|
+
case "undefined":
|
|
2534
|
+
return "<undefined>";
|
|
2535
|
+
case "function":
|
|
2536
|
+
return "<function>";
|
|
2537
|
+
case "symbol":
|
|
2538
|
+
return value.toString();
|
|
2539
|
+
case "object":
|
|
2540
|
+
return value === null ? null : sanitizeObject(value, depth, seen);
|
|
2541
|
+
default:
|
|
2542
|
+
return "<unrenderable>";
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
function sanitizeObject(value, depth, seen) {
|
|
2546
|
+
if (seen.has(value)) return "<circular>";
|
|
2547
|
+
if (depth >= MAX_DEPTH) return "<max depth>";
|
|
2548
|
+
if (value instanceof Error) return describeError(value);
|
|
2549
|
+
if (value instanceof Date) return describeDate(value);
|
|
2550
|
+
seen.add(value);
|
|
2551
|
+
try {
|
|
2552
|
+
if (Array.isArray(value)) {
|
|
2553
|
+
return value.map(
|
|
2554
|
+
(_item, index) => readProperty(value, String(index), depth, seen)
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2557
|
+
const out = {};
|
|
2558
|
+
for (const key of ownKeys(value)) {
|
|
2559
|
+
out[key] = readProperty(value, key, depth, seen);
|
|
2560
|
+
}
|
|
2561
|
+
return out;
|
|
2562
|
+
} finally {
|
|
2563
|
+
seen.delete(value);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function readProperty(owner, key, depth, seen) {
|
|
2567
|
+
try {
|
|
2568
|
+
return sanitize(owner[key], depth + 1, seen);
|
|
2569
|
+
} catch (_) {
|
|
2570
|
+
return "<unreadable>";
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
function ownKeys(value) {
|
|
2574
|
+
try {
|
|
2575
|
+
return Object.keys(value);
|
|
2576
|
+
} catch (_) {
|
|
2577
|
+
return [];
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
function describeError(error) {
|
|
2581
|
+
return {
|
|
2582
|
+
name: safeRead(() => error.name),
|
|
2583
|
+
message: safeRead(() => error.message),
|
|
2584
|
+
stack: safeRead(() => error.stack)
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
function describeDate(date) {
|
|
2588
|
+
return safeRead(() => date.toISOString());
|
|
2589
|
+
}
|
|
2590
|
+
function safeRead(read) {
|
|
2591
|
+
try {
|
|
2592
|
+
const value = read();
|
|
2593
|
+
return typeof value === "string" ? value : "<unreadable>";
|
|
2594
|
+
} catch (_) {
|
|
2595
|
+
return "<unreadable>";
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
var SDK_LOGGER_NAME = "@coinlist-co/react";
|
|
2599
|
+
function loggerOverPino(sink, level) {
|
|
2600
|
+
return {
|
|
2601
|
+
level: () => level,
|
|
2602
|
+
debug: (event) => emit(sink, "debug", event),
|
|
2603
|
+
info: (event) => emit(sink, "info", event),
|
|
2604
|
+
warn: (event) => emit(sink, "warn", event),
|
|
2605
|
+
error: (event) => emit(sink, "error", event)
|
|
2606
|
+
};
|
|
2607
|
+
}
|
|
2608
|
+
function emit(sink, method, event) {
|
|
2609
|
+
try {
|
|
2610
|
+
const value = event();
|
|
2611
|
+
sink[method](toPinoRecord(value), value.msg);
|
|
2612
|
+
} catch (error) {
|
|
2613
|
+
reportRenderFailure(sink, error);
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
function reportRenderFailure(sink, error) {
|
|
2617
|
+
try {
|
|
2618
|
+
sink.error(
|
|
2619
|
+
{ "error.type": error instanceof Error ? error.name : typeof error },
|
|
2620
|
+
"log event failed to render"
|
|
2621
|
+
);
|
|
2622
|
+
} catch (_) {
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
// src/server/core/observability/pino-server-logger.ts
|
|
2627
|
+
function pinoServerLogger(options) {
|
|
2628
|
+
return loggerOverPino(
|
|
2629
|
+
// `name` as a child binding rather than pino's `name` option: the option
|
|
2630
|
+
// is honoured by pino's node build and silently dropped by its browser
|
|
2631
|
+
// build, so a binding is the only spelling that identifies the SDK in
|
|
2632
|
+
// both environments.
|
|
2633
|
+
(0, import_pino.pino)({
|
|
2634
|
+
level: PINO_LEVEL[options.level]
|
|
2635
|
+
}).child({ name: SDK_LOGGER_NAME }),
|
|
2636
|
+
options.level
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
1901
2639
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1902
2640
|
0 && (module.exports = {
|
|
1903
2641
|
ServerAuthNamespaceImpl,
|
|
1904
2642
|
ServerOffersNamespaceImpl,
|
|
1905
2643
|
ServerRequirementsNamespaceImpl,
|
|
1906
2644
|
WritableSessionStoreRequiredError,
|
|
1907
|
-
createCoinListServer
|
|
2645
|
+
createCoinListServer,
|
|
2646
|
+
emptySessionStore,
|
|
2647
|
+
pinoServerLogger
|
|
1908
2648
|
});
|
|
1909
2649
|
//# sourceMappingURL=index.cjs.map
|