@coinlist-co/react 0.10.1 → 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.
Files changed (38) hide show
  1. package/README.md +32 -0
  2. package/dist/chunk-7CTH4KPU.js +2399 -0
  3. package/dist/chunk-7CTH4KPU.js.map +1 -0
  4. package/dist/{chunk-AQVCOWOV.js → chunk-LSPZETDH.js} +249 -317
  5. package/dist/chunk-LSPZETDH.js.map +1 -0
  6. package/dist/chunk-UZUQALFY.js +279 -0
  7. package/dist/chunk-UZUQALFY.js.map +1 -0
  8. package/dist/client/index.cjs +13430 -3308
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +5486 -899
  11. package/dist/client/index.d.ts +5486 -899
  12. package/dist/client/index.js +11025 -2388
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/collections-BBI_XydI.d.cts +116 -0
  15. package/dist/collections-BrX9rRWc.d.ts +116 -0
  16. package/dist/config-CMl1bR3F.d.cts +2959 -0
  17. package/dist/config-CMl1bR3F.d.ts +2959 -0
  18. package/dist/server/index.cjs +1768 -511
  19. package/dist/server/index.cjs.map +1 -1
  20. package/dist/server/index.d.cts +266 -162
  21. package/dist/server/index.d.ts +266 -162
  22. package/dist/server/index.js +235 -169
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/shared/index.cjs +2423 -926
  25. package/dist/shared/index.cjs.map +1 -1
  26. package/dist/shared/index.d.cts +325 -132
  27. package/dist/shared/index.d.ts +325 -132
  28. package/dist/shared/index.js +112 -28
  29. package/package.json +12 -8
  30. package/dist/chunk-AQVCOWOV.js.map +0 -1
  31. package/dist/chunk-TBU3EBNM.js +0 -442
  32. package/dist/chunk-TBU3EBNM.js.map +0 -1
  33. package/dist/chunk-UOHD7US2.js +0 -855
  34. package/dist/chunk-UOHD7US2.js.map +0 -1
  35. package/dist/collections-Bv1Oxzu_.d.ts +0 -28
  36. package/dist/collections-DDyxbOPZ.d.cts +0 -28
  37. package/dist/requirement-oVZA1INj.d.cts +0 -1040
  38. package/dist/requirement-oVZA1INj.d.ts +0 -1040
@@ -20,8 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/server/index.ts
21
21
  var server_exports = {};
22
22
  __export(server_exports, {
23
+ ServerAuthNamespaceImpl: () => ServerAuthNamespaceImpl,
24
+ ServerOffersNamespaceImpl: () => ServerOffersNamespaceImpl,
25
+ ServerRequirementsNamespaceImpl: () => ServerRequirementsNamespaceImpl,
23
26
  WritableSessionStoreRequiredError: () => WritableSessionStoreRequiredError,
24
- createCoinListServer: () => createCoinListServer
27
+ createCoinListServer: () => createCoinListServer,
28
+ emptySessionStore: () => emptySessionStore,
29
+ pinoServerLogger: () => pinoServerLogger
25
30
  });
26
31
  module.exports = __toCommonJS(server_exports);
27
32
 
@@ -52,6 +57,8 @@ var retryAttempt = (attempt) => ({
52
57
  var renewAttempted = (value) => ({
53
58
  renewAttempted: value
54
59
  });
60
+ var requestId = (id) => ({ requestId: id });
61
+ var getRequestId = (attrs) => attrs?.requestId ?? null;
55
62
  var isProtected = (attrs) => attrs?.protected === true;
56
63
  var needUserAgent = (attrs) => attrs?.userAgent === true;
57
64
  var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
@@ -73,7 +80,9 @@ var Attributes = {
73
80
  renewAttempted,
74
81
  wasRenewAttempted,
75
82
  clientCredentials,
76
- getClientCredentials
83
+ getClientCredentials,
84
+ requestId,
85
+ getRequestId
77
86
  };
78
87
 
79
88
  // src/shared/api/http.ts
@@ -83,7 +92,24 @@ var HttpError = class extends Error {
83
92
  this.name = "HttpError";
84
93
  this.response = response;
85
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
+ }
86
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
+ }
87
113
  async function makeRequest(request) {
88
114
  const headers = {
89
115
  Accept: "application/json",
@@ -119,7 +145,16 @@ async function makeRequest(request) {
119
145
  };
120
146
  }
121
147
  const text = await response.text();
122
- const body = text ? JSON.parse(text) : null;
148
+ let body;
149
+ try {
150
+ body = text ? JSON.parse(text) : null;
151
+ } catch (_) {
152
+ throw new HttpError({
153
+ status: response.status,
154
+ headers: responseHeaders,
155
+ body: text
156
+ });
157
+ }
123
158
  return {
124
159
  status: response.status,
125
160
  body,
@@ -180,11 +215,194 @@ var HEADER_API_VERSION = "X-API-Version";
180
215
  var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
181
216
  var API_VERSION = "2025-10-17";
182
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
+
183
399
  // src/shared/api/http-client.ts
184
400
  var HttpClient = class {
185
- constructor(config, middleware = {}) {
401
+ constructor(config, middleware = {}, logger = null, options = {}) {
186
402
  this.config = config;
187
403
  this.middleware = middleware;
404
+ this.log = internalLogger(logger, "HTTP");
405
+ this.makeRequestId = options.makeRequestId ?? defaultMakeRequestId;
188
406
  }
189
407
  async send(request) {
190
408
  return this.runRequestWithAfterMiddleware(request);
@@ -215,12 +433,18 @@ var HttpClient = class {
215
433
  const url = this.resolveUrl(request.url);
216
434
  const headers = {
217
435
  ...request.headers ?? {},
218
- [HEADER_API_VERSION]: this.config.xApiVersion
436
+ ...this.config.xApiVersion !== void 0 ? { [HEADER_API_VERSION]: this.config.xApiVersion } : {}
219
437
  };
220
438
  return {
221
439
  ...request,
222
440
  url,
223
- 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
224
448
  };
225
449
  }
226
450
  /**
@@ -244,10 +468,89 @@ var HttpClient = class {
244
468
  }
245
469
  return request;
246
470
  }
247
- executeRequest(request) {
248
- return makeRequest(request);
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
+ }
249
525
  }
250
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
+ }
251
554
 
252
555
  // src/shared/api/middleware/attach-session-middleware.ts
253
556
  function attachSessionMiddleware(fetchAccessToken) {
@@ -275,7 +578,7 @@ function attachSessionMiddleware(fetchAccessToken) {
275
578
  };
276
579
  }
277
580
 
278
- // src/shared/utils.ts
581
+ // src/shared/core/utils/crypto.ts
279
582
  function getUUIDv4() {
280
583
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
281
584
  return crypto.randomUUID();
@@ -378,18 +681,22 @@ function renewSessionMiddleware(fetchAccessToken) {
378
681
 
379
682
  // src/shared/api/authenticated-api-client.ts
380
683
  var AuthenticatedApiClient = class {
381
- constructor(config, fetchAccessToken, additionalBeforeRequest = []) {
382
- this.httpClient = new HttpClient(config, {
383
- beforeRequest: [
384
- attachSessionMiddleware(fetchAccessToken),
385
- ...additionalBeforeRequest,
386
- idempotencyKeyMiddleware
387
- ],
388
- afterRequest: [
389
- renewSessionMiddleware(fetchAccessToken),
390
- requestRetryMiddleware
391
- ]
392
- });
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
+ );
393
700
  }
394
701
  async send(request) {
395
702
  const response = await this.httpClient.send(request);
@@ -401,10 +708,15 @@ var AuthenticatedApiClient = class {
401
708
  }
402
709
  };
403
710
 
404
- // src/server/api/api.server.ts
405
- var Api = class {
406
- constructor(config, fetchAccessToken) {
407
- this.client = new AuthenticatedApiClient(config, fetchAccessToken);
711
+ // src/server/core/api/api-client.ts
712
+ var ApiClient = class {
713
+ constructor(config, fetchAccessToken, logger = null) {
714
+ this.client = new AuthenticatedApiClient(
715
+ config,
716
+ fetchAccessToken,
717
+ [],
718
+ logger
719
+ );
408
720
  }
409
721
  async send(request) {
410
722
  return this.client.send(request);
@@ -419,48 +731,168 @@ var WritableSessionStoreRequiredError = class extends Error {
419
731
  }
420
732
  };
421
733
 
422
- // src/shared/types/document-submission.ts
423
- var DocumentSubmission = {
424
- fromDto: (dto) => ({
425
- status: dto.status,
426
- formType: dto.form_type
427
- })
734
+ // src/shared/types/oauth-session.ts
735
+ var ClientCredentialsOAuth = (value) => value;
736
+ var OAuthRefreshToken = (value) => value;
737
+ var OAuthSession = {
738
+ fromDto: (dto) => {
739
+ const expiresAt = new Date(Date.now() + dto.expires_in * 1e3);
740
+ return {
741
+ accessToken: {
742
+ value: dto.access_token,
743
+ expiresAt
744
+ },
745
+ ...dto.refresh_token != null && dto.refresh_token !== "" ? { refreshToken: OAuthRefreshToken(dto.refresh_token) } : void 0
746
+ };
747
+ }
428
748
  };
429
749
 
430
- // src/shared/api/frontline/documents.ts
431
- async function submitDocument(api, documentType, fields) {
432
- const dto = await api.send({
433
- method: "POST",
434
- url: `/v1/documents/${documentType}/submission`,
435
- body: fields,
436
- attributes: Attributes.protected()
437
- });
438
- return DocumentSubmission.fromDto(dto);
750
+ // src/server/core/server-auth-namespace.ts
751
+ function emptySessionStore() {
752
+ return { getSession: async () => null };
439
753
  }
440
-
441
- // src/shared/types/kyc.ts
442
- var KycToken = {
443
- fromDto: (dto) => ({
444
- token: dto.token
445
- })
754
+ var ServerAuthNamespaceImpl = class {
755
+ constructor(api, config) {
756
+ this.api = api;
757
+ this.config = config;
758
+ this.log = internalLogger(config.logger ?? null, "AUTH");
759
+ }
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;
778
+ });
779
+ }
780
+ async getAccessToken() {
781
+ return this.log.wrap(
782
+ "getAccessToken",
783
+ void 0,
784
+ () => this.readAccessToken()
785
+ );
786
+ }
787
+ async readAccessToken() {
788
+ const sessionStore = this.config.sessionStore;
789
+ const session = await sessionStore.getSession();
790
+ if (session == null) return null;
791
+ const now = Date.now();
792
+ const expiresAt = session.accessToken.expiresAt.getTime();
793
+ const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1e3;
794
+ if (expiresAt > now + bufferMs) {
795
+ return session.accessToken;
796
+ }
797
+ const setSession = sessionStore.setSession?.bind(sessionStore);
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
+ }));
802
+ return session.accessToken;
803
+ }
804
+ return this.refreshSession(session.refreshToken, setSession);
805
+ }
806
+ async refreshSession(refreshToken, setSession) {
807
+ const log = this.log.child({ op: "refresh" });
808
+ if (!refreshToken) {
809
+ log.warn(() => ({
810
+ msg: "clearing the session: it carries no refresh token"
811
+ }));
812
+ await setSession(null);
813
+ return null;
814
+ }
815
+ try {
816
+ const sessionDto = await this.api.send({
817
+ method: "POST",
818
+ url: `/oauth/token`,
819
+ body: {
820
+ grant_type: "refresh_token",
821
+ refresh_token: refreshToken,
822
+ client_id: this.config.clientId,
823
+ client_secret: this.config.clientSecret
824
+ }
825
+ });
826
+ const newSession = OAuthSession.fromDto(sessionDto);
827
+ await setSession(newSession);
828
+ log.info(() => ({ msg: "session renewed" }));
829
+ return newSession.accessToken;
830
+ } catch (error) {
831
+ log.failure(
832
+ () => ({ msg: "refresh failed; clearing the session" }),
833
+ error
834
+ );
835
+ await setSession(null);
836
+ return null;
837
+ }
838
+ }
839
+ async clientCredentials() {
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);
852
+ });
853
+ }
854
+ async logout() {
855
+ return this.log.wrap("logout", void 0, () => this.revokeAndClear());
856
+ }
857
+ async revokeAndClear() {
858
+ const setSession = this.writableSessionStore();
859
+ const session = await this.config.sessionStore.getSession();
860
+ if (session == null) return;
861
+ try {
862
+ await this.api.send({
863
+ method: "POST",
864
+ url: `/oauth/revoke`,
865
+ body: {
866
+ token: session.accessToken.value,
867
+ client_id: this.config.clientId,
868
+ client_secret: this.config.clientSecret
869
+ }
870
+ });
871
+ } catch (err) {
872
+ if (!(err instanceof HttpError) || this.config.strict) {
873
+ throw err;
874
+ }
875
+ this.log.child({ op: "logout" }).warn(() => ({
876
+ msg: "the token was not revoked upstream; the local session is cleared regardless"
877
+ }));
878
+ }
879
+ await setSession(null);
880
+ }
881
+ /**
882
+ * Returns the store's `setSession`, or throws — the guard every
883
+ * session-writing operation shares.
884
+ */
885
+ writableSessionStore() {
886
+ const sessionStore = this.config.sessionStore;
887
+ const setSession = sessionStore.setSession?.bind(sessionStore);
888
+ if (!setSession) {
889
+ throw new WritableSessionStoreRequiredError();
890
+ }
891
+ return setSession;
892
+ }
446
893
  };
447
894
 
448
- // src/shared/api/frontline/kyc.ts
449
- async function createKycToken(api, levelName, reset) {
450
- const dto = await api.send({
451
- method: "POST",
452
- url: "/v1/kyc-token",
453
- body: {
454
- ...levelName === void 0 ? {} : { level_name: levelName },
455
- ...reset === void 0 ? {} : { reset }
456
- },
457
- attributes: Attributes.protected()
458
- });
459
- return KycToken.fromDto(dto);
460
- }
461
-
462
895
  // src/shared/api/pagination.ts
463
- var Cursor = (value) => value;
464
896
  async function fetchAllPages(fetchPage, baseParams) {
465
897
  const items = [];
466
898
  let cursor = null;
@@ -475,55 +907,135 @@ async function fetchAllPages(fetchPage, baseParams) {
475
907
  } while (cursor);
476
908
  return items;
477
909
  }
478
- var PaginatedResponse = {
479
- fromDto: (dto, itemMapper) => ({
480
- data: dto.data.map(itemMapper),
481
- startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
482
- startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
483
- })
910
+
911
+ // src/shared/types/blockchain/core.ts
912
+ var ETHEREUM_CHAINS = {
913
+ ethereum_mainnet: true,
914
+ ethereum_sepolia: true,
915
+ base_mainnet: true,
916
+ base_sepolia: true
484
917
  };
485
- var PaginationParams = {
486
- toQueryParams: (params) => {
487
- const queryParams = {};
488
- if (params.after) {
489
- queryParams.starting_after = params.after;
490
- }
491
- if (params.before) {
492
- queryParams.starting_before = params.before;
493
- }
494
- if (params.limit) {
495
- queryParams.limit = params.limit;
496
- }
497
- return queryParams;
918
+ var EthereumChain = (value) => {
919
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
920
+ throw new ValidationError(`Unsupported Ethereum chain: "${value}"`);
498
921
  }
922
+ return value;
499
923
  };
500
-
501
- // src/shared/types/offer.ts
502
- var OfferId = (value) => value;
503
- var OfferSlug = (value) => value;
504
- var Offer = {
505
- fromDto: (dto) => ({
506
- id: OfferId(dto.id),
507
- slug: OfferSlug(dto.slug),
508
- type: dto.type,
509
- tagline: dto.tagline,
510
- bannerUrl: dto.banner_url,
511
- logoUrl: dto.logo_url,
512
- startsAt: new Date(dto.starts_at),
513
- endsAt: dto.ends_at ? new Date(dto.ends_at) : null
514
- })
924
+ var SOLANA_CHAINS = {
925
+ solana_mainnet: true,
926
+ solana_devnet: true
515
927
  };
516
-
517
- // src/shared/types/asset.ts
518
- var AssetId = (value) => value;
519
- var AssetCode = (value) => value;
520
- var Asset = {
521
- fromDto: (dto) => ({
522
- id: AssetId(dto.id),
523
- code: AssetCode(dto.code),
524
- name: dto.name,
525
- fractionalDigits: dto.fractional_digits
526
- })
928
+ var Chain = (value) => {
929
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value) && !Object.keys(SOLANA_CHAINS).includes(value)) {
930
+ throw new ValidationError(`Unsupported chain: "${value}"`);
931
+ }
932
+ return value;
933
+ };
934
+ var EvmWalletAddress = (value) => value;
935
+ var EvmContractAddress = (value) => value;
936
+ var HexEncodedTransactionData = (value) => value;
937
+ var MAX_ASSET_DECIMALS = 77;
938
+ var AssetDecimals = (value) => {
939
+ if (!Number.isInteger(value)) {
940
+ throw new ValidationError(`Asset decimals must be an integer: ${value}`);
941
+ }
942
+ if (value < 0 || value > MAX_ASSET_DECIMALS) {
943
+ throw new ValidationError(
944
+ `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`
945
+ );
946
+ }
947
+ return value;
948
+ };
949
+ var STABLE_DECIMALS = AssetDecimals(6);
950
+ var DecimalString = (value) => value;
951
+ var MAX_UINT_256 = 2n ** 256n - 1n;
952
+ var assertUint256 = (value) => {
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})`);
959
+ };
960
+ var isUint256 = (value) => value >= 0n && value <= MAX_UINT_256;
961
+ var BlockchainAmount = Object.assign(
962
+ (value) => value,
963
+ {
964
+ add: (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
968
+ }
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
+ }
984
+ function combineAmounts(a, b, op) {
985
+ if (a.decimals !== b.decimals) {
986
+ throw new InvariantError(
987
+ `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
988
+ );
989
+ }
990
+ const raw = op(a.raw, b.raw);
991
+ if (raw < 0n || raw > MAX_UINT_256) {
992
+ throw new InvariantError(`BlockchainAmount out of uint256 bounds: ${raw}`);
993
+ }
994
+ return BlockchainAmount({ raw, decimals: a.decimals });
995
+ }
996
+ var AssetSymbol = (value) => value;
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
+ })
527
1039
  };
528
1040
 
529
1041
  // src/shared/types/offer-detail.ts
@@ -532,22 +1044,39 @@ var OfferOptionSlug = (value) => value;
532
1044
  var OfferDetail = {
533
1045
  fromDto: (dto) => {
534
1046
  if (!Array.isArray(dto.funding_assets)) {
535
- throw new Error(`funding_assets must be an array`);
1047
+ throw new ValidationError(
1048
+ `OfferDetail.funding_assets: expected an array, got ${typeof dto.funding_assets}`
1049
+ );
536
1050
  }
537
1051
  if (!Array.isArray(dto.options)) {
538
- throw new Error(`options must be an array`);
1052
+ throw new ValidationError(
1053
+ `OfferDetail.options: expected an array, got ${typeof dto.options}`
1054
+ );
539
1055
  }
540
1056
  if (!Array.isArray(dto.terms)) {
541
- throw new Error(`terms must be an array`);
1057
+ throw new ValidationError(
1058
+ `OfferDetail.terms: expected an array, got ${typeof dto.terms}`
1059
+ );
542
1060
  }
543
1061
  if (!Array.isArray(dto.links)) {
544
- throw new Error(`links must be an array`);
1062
+ throw new ValidationError(
1063
+ `OfferDetail.links: expected an array, got ${typeof dto.links}`
1064
+ );
545
1065
  }
546
1066
  if (!Array.isArray(dto.faqs)) {
547
- throw new Error(`faqs must be an array`);
1067
+ throw new ValidationError(
1068
+ `OfferDetail.faqs: expected an array, got ${typeof dto.faqs}`
1069
+ );
548
1070
  }
549
1071
  if (!Array.isArray(dto.milestones)) {
550
- throw new Error(`milestones must be an array`);
1072
+ throw new ValidationError(
1073
+ `OfferDetail.milestones: expected an array, got ${typeof dto.milestones}`
1074
+ );
1075
+ }
1076
+ if (!Array.isArray(dto.tokens)) {
1077
+ throw new ValidationError(
1078
+ `OfferDetail.tokens: expected an array, got ${typeof dto.tokens}`
1079
+ );
551
1080
  }
552
1081
  return {
553
1082
  id: OfferId(dto.id),
@@ -556,6 +1085,7 @@ var OfferDetail = {
556
1085
  name: dto.name,
557
1086
  asset: Asset.fromDto(dto.asset),
558
1087
  fundingAssets: dto.funding_assets.map(Asset.fromDto),
1088
+ tokens: dto.tokens.map(OfferToken.fromDto),
559
1089
  about: notBlankStringOrNull(dto.about),
560
1090
  tagline: dto.tagline,
561
1091
  bannerUrl: dto.banner_url,
@@ -609,6 +1139,31 @@ var Milestone = {
609
1139
  })
610
1140
  };
611
1141
 
1142
+ // src/shared/types/pagination.ts
1143
+ var Cursor = (value) => value;
1144
+ var PaginatedResponse = {
1145
+ fromDto: (dto, itemMapper) => ({
1146
+ data: dto.data.map(itemMapper),
1147
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
1148
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
1149
+ })
1150
+ };
1151
+ var PaginationParams = {
1152
+ toQueryParams: (params) => {
1153
+ const queryParams = {};
1154
+ if (params.after) {
1155
+ queryParams.starting_after = params.after;
1156
+ }
1157
+ if (params.before) {
1158
+ queryParams.starting_before = params.before;
1159
+ }
1160
+ if (params.limit) {
1161
+ queryParams.limit = params.limit;
1162
+ }
1163
+ return queryParams;
1164
+ }
1165
+ };
1166
+
612
1167
  // src/shared/api/frontline/offers.ts
613
1168
  async function fetchOffers(api, clientCreds) {
614
1169
  return fetchAllPages((params) => fetchOffersPage(api, params, clientCreds));
@@ -638,44 +1193,32 @@ async function fetchOfferDetails(api, id, clientCreds) {
638
1193
  return OfferDetail.fromDto(dto);
639
1194
  }
640
1195
 
641
- // src/shared/types/pii.ts
642
- var Iso2CountryCode = (value) => value;
643
- var PiiJurisdiction = {
644
- fromDto: (dto) => ({
645
- iso2: Iso2CountryCode(dto.iso_2),
646
- name: dto.name
647
- })
648
- };
649
- var PiiAddress = {
650
- fromDto: (dto) => ({
651
- street: dto.street,
652
- city: dto.city,
653
- state: dto.state,
654
- postalCode: dto.postal_code,
655
- country: dto.country
656
- })
657
- };
658
- var Pii = {
659
- fromDto: (dto) => ({
660
- kind: dto.kind,
661
- fullLegalName: dto.full_legal_name,
662
- dateOfBirth: dto.date_of_birth,
663
- jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
664
- taxId: dto.tax_id,
665
- permanentAddress: PiiAddress.fromDto(dto.permanent_address)
666
- })
1196
+ // src/server/core/server-offers-namespace.ts
1197
+ var ServerOffersNamespaceImpl = class {
1198
+ constructor(ctx) {
1199
+ this.ctx = ctx;
1200
+ this.log = internalLogger(ctx.logger, "OFFERS");
1201
+ }
1202
+ async list(clientCreds) {
1203
+ return this.log.wrap("list", clientCreds, async () => {
1204
+ await this.ctx.ensureAuthenticated(clientCreds);
1205
+ return fetchOffers(this.ctx.api, clientCreds);
1206
+ });
1207
+ }
1208
+ async listPage(params, clientCreds) {
1209
+ return this.log.wrap("listPage", { params, clientCreds }, async () => {
1210
+ await this.ctx.ensureAuthenticated(clientCreds);
1211
+ return fetchOffersPage(this.ctx.api, params, clientCreds);
1212
+ });
1213
+ }
1214
+ async get(id, clientCreds) {
1215
+ return this.log.wrap("get", { id, clientCreds }, async () => {
1216
+ await this.ctx.ensureAuthenticated(clientCreds);
1217
+ return fetchOfferDetails(this.ctx.api, id, clientCreds);
1218
+ });
1219
+ }
667
1220
  };
668
1221
 
669
- // src/shared/api/frontline/pii.ts
670
- async function fetchPii(api) {
671
- const dto = await api.send({
672
- method: "GET",
673
- url: "/v1/pii",
674
- attributes: Attributes.protected()
675
- });
676
- return Pii.fromDto(dto);
677
- }
678
-
679
1222
  // src/shared/types/requirement.ts
680
1223
  var RequirementId = (value) => value;
681
1224
  var Requirement = {
@@ -723,138 +1266,156 @@ async function fetchRequirementStatuses(api, offerId) {
723
1266
  return RequirementStatusInfo.fromStatusesDto(response);
724
1267
  }
725
1268
 
726
- // src/shared/types/blockchain/core.ts
727
- var EvmWalletAddress = (value) => value;
728
- var EvmContractAddress = (value) => value;
729
- var HexEncodedTransactionData = (value) => value;
730
- var AssetDecimals = (value) => value;
731
- var MAX_UINT_256 = 2n ** 256n - 1n;
732
- var assertUint256 = (value) => {
733
- if (value < 0n || value > MAX_UINT_256) {
734
- throw new Error(`Value out of uint256 bounds: ${value}`);
735
- }
736
- return value;
737
- };
738
- var BlockchainAmount = Object.assign(
739
- (value) => value,
740
- {
741
- add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
742
- sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
743
- }
744
- );
745
- function combineAmounts(a, b, op) {
746
- if (a.decimals !== b.decimals) {
747
- throw new Error(
748
- `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
749
- );
750
- }
751
- const raw = op(a.raw, b.raw);
752
- if (raw < 0n || raw > MAX_UINT_256) {
753
- throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
754
- }
755
- return BlockchainAmount({ raw, decimals: a.decimals });
756
- }
757
- var AssetSymbol = (value) => value;
758
-
759
- // src/shared/types/offer-option-address.ts
760
- var OfferOptionAddressId = (value) => value;
761
- var OfferOptionAddress = {
762
- /** Maps the API DTO into the SDK offer-option-address domain model. */
1269
+ // src/shared/types/document-submission.ts
1270
+ var DocumentSubmission = {
763
1271
  fromDto: (dto) => ({
764
- id: OfferOptionAddressId(dto.id),
765
- offerOptionId: OfferOptionId(dto.offer_option_id),
766
- address: EvmWalletAddress(dto.address),
767
- protocol: dto.protocol,
768
- createdAt: new Date(dto.created_at)
769
- })
770
- };
771
- var ConnectExternalWalletParams = {
772
- /** Maps connect-wallet params into the API DTO payload. */
773
- toDto: (params) => ({
774
- offer_option_id: params.offerOptionId,
775
- wallet_address: params.walletAddress,
776
- chain: params.chain,
777
- signature: params.signature
1272
+ status: dto.status,
1273
+ formType: dto.form_type
778
1274
  })
779
1275
  };
780
1276
 
781
- // src/shared/types/wallet-ownership-challenge.ts
782
- var WalletOwnershipChallenge = {
783
- /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
1277
+ // src/shared/api/frontline/documents.ts
1278
+ async function submitDocument(api, documentType, fields) {
1279
+ const dto = await api.send({
1280
+ method: "POST",
1281
+ url: `/v1/documents/${documentType}/submission`,
1282
+ body: fields,
1283
+ attributes: Attributes.protected()
1284
+ });
1285
+ return DocumentSubmission.fromDto(dto);
1286
+ }
1287
+
1288
+ // src/shared/types/kyc.ts
1289
+ var KycToken = {
784
1290
  fromDto: (dto) => ({
785
- message: dto.message,
786
- expiresAt: new Date(dto.expires_at)
1291
+ token: dto.token
787
1292
  })
788
1293
  };
789
- var CreateWalletOwnershipChallengeParams = {
790
- /**
791
- * Maps challenge-request params into the API DTO payload. The discriminated
792
- * union guarantees SIWE fields are present exactly when `challengeType` is
793
- * `siwe`, so the mapping narrows on the discriminant.
794
- */
795
- toDto: (params) => {
796
- switch (params.challengeType) {
797
- case "plain":
798
- return {
799
- wallet_address: params.walletAddress,
800
- chain: params.chain,
801
- challenge_type: "plain"
802
- };
803
- case "siwe":
804
- return {
805
- wallet_address: params.walletAddress,
806
- chain: params.chain,
807
- challenge_type: "siwe",
808
- domain: params.domain,
809
- uri: params.uri,
810
- statement: params.statement
811
- };
812
- default: {
813
- const _exhaustive = params;
814
- return _exhaustive;
815
- }
816
- }
817
- }
818
- };
819
1294
 
820
- // src/shared/api/frontline/wallet-connect.ts
821
- async function createWalletOwnershipChallenge(api, params) {
1295
+ // src/shared/api/frontline/kyc.ts
1296
+ async function createKycToken(api, levelName, reset) {
822
1297
  const dto = await api.send({
823
1298
  method: "POST",
824
- url: "/v1/wallet-ownership",
825
- body: CreateWalletOwnershipChallengeParams.toDto(params),
1299
+ url: "/v1/kyc-token",
1300
+ body: {
1301
+ ...levelName === void 0 ? {} : { level_name: levelName },
1302
+ ...reset === void 0 ? {} : { reset }
1303
+ },
826
1304
  attributes: Attributes.protected()
827
1305
  });
828
- return WalletOwnershipChallenge.fromDto(dto);
1306
+ return KycToken.fromDto(dto);
829
1307
  }
830
- async function connectExternalWallet(api, offerId, params) {
831
- const dto = await api.send({
832
- method: "POST",
833
- url: `/v1/offers/${offerId}/addresses`,
834
- body: ConnectExternalWalletParams.toDto(params),
835
- attributes: Attributes.protected()
836
- });
837
- return OfferOptionAddress.fromDto(dto);
838
- }
839
- async function listOptionAddresses(api, offerId, offerOptionId) {
840
- const { data } = await api.send({
841
- method: "GET",
842
- url: `/v1/offers/${offerId}/addresses`,
843
- queryParams: { offer_option_id: offerOptionId },
844
- attributes: Attributes.protected()
845
- });
846
- return data.map(OfferOptionAddress.fromDto);
847
- }
848
- async function removeOptionAddress(api, offerId, addressId) {
1308
+
1309
+ // src/shared/types/pii.ts
1310
+ var Iso2CountryCode = (value) => value;
1311
+ var PiiJurisdiction = {
1312
+ fromDto: (dto) => ({
1313
+ iso2: Iso2CountryCode(dto.iso_2),
1314
+ name: dto.name
1315
+ })
1316
+ };
1317
+ var PiiAddress = {
1318
+ fromDto: (dto) => ({
1319
+ street: dto.street,
1320
+ city: dto.city,
1321
+ state: dto.state,
1322
+ postalCode: dto.postal_code,
1323
+ country: dto.country
1324
+ })
1325
+ };
1326
+ var Pii = {
1327
+ fromDto: (dto) => ({
1328
+ kind: dto.kind,
1329
+ fullLegalName: dto.full_legal_name,
1330
+ dateOfBirth: dto.date_of_birth,
1331
+ jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
1332
+ taxId: dto.tax_id,
1333
+ permanentAddress: PiiAddress.fromDto(dto.permanent_address)
1334
+ })
1335
+ };
1336
+
1337
+ // src/shared/api/frontline/pii.ts
1338
+ async function fetchPii(api) {
849
1339
  const dto = await api.send({
850
- method: "DELETE",
851
- url: `/v1/offers/${offerId}/addresses/${addressId}`,
1340
+ method: "GET",
1341
+ url: "/v1/pii",
852
1342
  attributes: Attributes.protected()
853
1343
  });
854
- return OfferOptionAddress.fromDto(dto);
1344
+ return Pii.fromDto(dto);
855
1345
  }
856
1346
 
857
- // src/shared/types/swap.ts
1347
+ // src/shared/core/requirements/requirements-namespace.ts
1348
+ var RequirementsNamespaceImpl = class {
1349
+ constructor(ctx) {
1350
+ this.ctx = ctx;
1351
+ this.log = internalLogger(ctx.logger, "REQUIREMENTS");
1352
+ }
1353
+ async forOffer(offerId) {
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
+ });
1362
+ }
1363
+ async statuses(offerId) {
1364
+ return this.log.wrap("statuses", offerId, async () => {
1365
+ await this.ctx.ensureUserAuthenticated();
1366
+ return fetchRequirementStatuses(this.ctx.api, offerId);
1367
+ });
1368
+ }
1369
+ async createKycToken(params) {
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
+ });
1378
+ }
1379
+ async getPii() {
1380
+ return this.log.wrap("getPii", void 0, async () => {
1381
+ await this.ctx.ensureUserAuthenticated();
1382
+ return fetchPii(this.ctx.api);
1383
+ });
1384
+ }
1385
+ async submitDocument(params) {
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
+ });
1394
+ }
1395
+ };
1396
+
1397
+ // src/server/core/server-requirements-namespace.ts
1398
+ var ServerRequirementsNamespaceImpl = class extends RequirementsNamespaceImpl {
1399
+ constructor(serverCtx) {
1400
+ super(serverCtx);
1401
+ this.serverCtx = serverCtx;
1402
+ }
1403
+ async forOffer(offerId, clientCreds) {
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
+ });
1412
+ }
1413
+ };
1414
+
1415
+ // src/shared/api/nabu/config.ts
1416
+ var NABU_BASE_URL = "https://asset.coinlist.co";
1417
+
1418
+ // src/shared/types/providers/superstate/swap.ts
858
1419
  var SwapAuthorization = {
859
1420
  fromDto: (dto) => ({
860
1421
  authorized: dto.authorized
@@ -862,25 +1423,31 @@ var SwapAuthorization = {
862
1423
  };
863
1424
  var SwapPreview = {
864
1425
  fromDto: (dto) => ({
865
- inputAmount: assertUint256(BigInt(dto.pay_input_amount)),
866
- fee: assertUint256(BigInt(dto.fee)),
867
- outputAmount: assertUint256(BigInt(dto.receive_output_amount))
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
+ )
868
1435
  })
869
1436
  };
870
1437
  var SwapStatus = {
871
1438
  fromDto: (dto) => ({
872
- stopped: assertUint256(BigInt(dto.stopped)),
873
- swapLevel: assertUint256(BigInt(dto.swap_level))
1439
+ stopped: parseUint256(BigInt(dto.stopped), "SwapStatus.stopped"),
1440
+ swapLevel: parseUint256(BigInt(dto.swap_level), "SwapStatus.swap_level")
874
1441
  })
875
1442
  };
876
1443
  var TokenAllowance = {
877
1444
  fromDto: (dto) => ({
878
- allowance: assertUint256(BigInt(dto.allowance))
1445
+ allowance: parseUint256(BigInt(dto.allowance), "TokenAllowance.allowance")
879
1446
  })
880
1447
  };
881
1448
  var TokenBalance = {
882
1449
  fromDto: (dto) => ({
883
- balance: assertUint256(BigInt(dto.balance))
1450
+ balance: parseUint256(BigInt(dto.balance), "TokenBalance.balance")
884
1451
  })
885
1452
  };
886
1453
  var AllowWalletResponse = {
@@ -905,7 +1472,7 @@ var AllowWalletResponse = {
905
1472
  }
906
1473
  };
907
1474
 
908
- // src/shared/api/frontline/swap.ts
1475
+ // src/shared/api/frontline/providers/superstate/swap.ts
909
1476
  async function getSwapAuthorization(api, params) {
910
1477
  const dto = await api.send({
911
1478
  method: "GET",
@@ -1005,53 +1572,27 @@ function toErc20Asset(dto) {
1005
1572
  };
1006
1573
  }
1007
1574
 
1008
- // src/shared/core/erc20-namespace.ts
1575
+ // src/shared/core/blockchain/erc20/erc20-namespace.ts
1009
1576
  var Erc20NamespaceImpl = class {
1010
1577
  constructor(ctx) {
1011
1578
  this.ctx = ctx;
1579
+ this.log = internalLogger(ctx.logger, "ERC20");
1012
1580
  }
1013
- async getTokenAllowance(params) {
1014
- await this.ctx.ensureUserAuthenticated();
1015
- return getTokenAllowance(this.ctx.api, params);
1016
- }
1017
- async getTokenBalance(params) {
1018
- await this.ctx.ensureUserAuthenticated();
1019
- return getTokenBalance(this.ctx.api, params);
1020
- }
1021
- };
1022
-
1023
- // src/shared/core/swap-namespace.ts
1024
- var SwapNamespaceImpl = class {
1025
- constructor(ctx) {
1026
- this.ctx = ctx;
1027
- }
1028
- async getAuthorization(params) {
1029
- await this.ctx.ensureUserAuthenticated();
1030
- return getSwapAuthorization(this.ctx.api, params);
1031
- }
1032
- async getPreview(params) {
1033
- await this.ctx.ensureUserAuthenticated();
1034
- return getSwapPreview(this.ctx.api, params);
1035
- }
1036
- async getStatus(params) {
1037
- await this.ctx.ensureUserAuthenticated();
1038
- return getSwapStatus(this.ctx.api, params);
1039
- }
1040
- async getOutputToken(params) {
1041
- await this.ctx.ensureUserAuthenticated();
1042
- return getSwapOutputToken(this.ctx.api, params);
1043
- }
1044
- async requestWalletOwnershipChallenge(params) {
1045
- await this.ctx.ensureUserAuthenticated();
1046
- return createWalletOwnershipChallenge(this.ctx.api, params);
1581
+ async getAllowance(params) {
1582
+ return this.log.wrap("getAllowance", params, async () => {
1583
+ await this.ctx.ensureUserAuthenticated();
1584
+ return getTokenAllowance(this.ctx.api, params);
1585
+ });
1047
1586
  }
1048
- async allowWallet(params) {
1049
- await this.ctx.ensureUserAuthenticated();
1050
- return allowWallet(this.ctx.api, params);
1587
+ async getBalance(params) {
1588
+ return this.log.wrap("getBalance", params, async () => {
1589
+ await this.ctx.ensureUserAuthenticated();
1590
+ return getTokenBalance(this.ctx.api, params);
1591
+ });
1051
1592
  }
1052
1593
  };
1053
1594
 
1054
- // src/shared/types/participation.ts
1595
+ // src/shared/types/providers/coin-list/token-sale.ts
1055
1596
  var ParticipationId = (value) => value;
1056
1597
  var Blockchain = (value) => value;
1057
1598
  var WalletAddress = (value) => value;
@@ -1098,7 +1639,7 @@ var CreateParticipationParams = {
1098
1639
  })
1099
1640
  };
1100
1641
 
1101
- // src/shared/api/frontline/participations.ts
1642
+ // src/shared/api/frontline/providers/coin-list/token-sale.ts
1102
1643
  async function fetchParticipations(api, offerId) {
1103
1644
  return fetchAllPages(
1104
1645
  (params) => fetchParticipationsPage(api, params),
@@ -1132,261 +1673,977 @@ async function createParticipation(api, params) {
1132
1673
  return Participation.fromDto(dto);
1133
1674
  }
1134
1675
 
1135
- // src/shared/core/token-sale-namespace.ts
1136
- var TokenSaleNamespaceImpl = class {
1676
+ // src/shared/core/checkout/coin-list/token-sale-namespace.ts
1677
+ var CoinListTokenSaleNamespaceImpl = class {
1137
1678
  constructor(ctx) {
1138
1679
  this.ctx = ctx;
1680
+ this.log = internalLogger(ctx.logger, "TOKEN_SALE");
1139
1681
  }
1140
- async fetchParticipations(offerId) {
1141
- await this.ctx.ensureUserAuthenticated();
1142
- return fetchParticipations(this.ctx.api, offerId);
1682
+ async list(offerId) {
1683
+ return this.log.wrap("list", offerId, async () => {
1684
+ await this.ctx.ensureUserAuthenticated();
1685
+ return fetchParticipations(this.ctx.api, offerId);
1686
+ });
1143
1687
  }
1144
- async fetchParticipationsPage(params) {
1145
- await this.ctx.ensureUserAuthenticated();
1146
- return fetchParticipationsPage(this.ctx.api, params);
1688
+ async listPage(params) {
1689
+ return this.log.wrap("listPage", params, async () => {
1690
+ await this.ctx.ensureUserAuthenticated();
1691
+ return fetchParticipationsPage(this.ctx.api, params);
1692
+ });
1147
1693
  }
1148
- async fetchParticipation(id) {
1149
- await this.ctx.ensureUserAuthenticated();
1150
- return fetchParticipation(this.ctx.api, id);
1694
+ async get(id) {
1695
+ return this.log.wrap("get", id, async () => {
1696
+ await this.ctx.ensureUserAuthenticated();
1697
+ return fetchParticipation(this.ctx.api, id);
1698
+ });
1151
1699
  }
1152
1700
  async createParticipation(params) {
1153
- await this.ctx.ensureUserAuthenticated();
1154
- return createParticipation(this.ctx.api, params);
1701
+ return this.log.wrap("createParticipation", params, async () => {
1702
+ await this.ctx.ensureUserAuthenticated();
1703
+ return createParticipation(this.ctx.api, params);
1704
+ });
1155
1705
  }
1156
1706
  };
1157
1707
 
1158
- // src/shared/types/errors.ts
1159
- var NotAuthenticatedError = class extends Error {
1160
- constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
1161
- super(message);
1162
- this.name = "NotAuthenticatedError";
1163
- }
1708
+ // src/shared/core/blockchain/formatters.ts
1709
+ var import_viem = require("viem");
1710
+
1711
+ // src/shared/types/blockchain/ui.ts
1712
+ var FormattedAmountAssetUi = (value) => value;
1713
+
1714
+ // src/shared/core/blockchain/formatters.ts
1715
+ function formatRawAmount(amount) {
1716
+ return (0, import_viem.formatUnits)(amount.raw, amount.decimals);
1717
+ }
1718
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1719
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
1720
+
1721
+ // src/shared/core/blockchain/chain.ts
1722
+ var CHAIN_IDS = {
1723
+ ethereum_mainnet: 1,
1724
+ ethereum_sepolia: 11155111,
1725
+ base_mainnet: 8453,
1726
+ base_sepolia: 84532
1164
1727
  };
1728
+ function chainFromId(chainId) {
1729
+ const chains = Object.keys(CHAIN_IDS);
1730
+ const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
1731
+ if (!chain) {
1732
+ throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
1733
+ }
1734
+ return chain;
1735
+ }
1165
1736
 
1166
- // src/shared/types/oauth-session.ts
1167
- var ClientCredentialsOAuth = (value) => value;
1168
- var OAuthRefreshToken = (value) => value;
1169
- var OAuthSession = {
1737
+ // src/shared/core/blockchain/math.ts
1738
+ var import_viem2 = require("viem");
1739
+ function blockchainAmountFromRawOrThrow({
1740
+ label,
1741
+ raw,
1742
+ decimals
1743
+ }) {
1744
+ const trimmed = raw.trim();
1745
+ if (trimmed === "") {
1746
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1747
+ }
1748
+ let value;
1749
+ try {
1750
+ value = BigInt(trimmed);
1751
+ } catch {
1752
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1753
+ }
1754
+ try {
1755
+ return BlockchainAmount({ raw: assertUint256(value), decimals });
1756
+ } catch {
1757
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1758
+ }
1759
+ }
1760
+
1761
+ // src/shared/types/trading.ts
1762
+ var Ticker = (value) => value;
1763
+
1764
+ // src/shared/types/providers/ondo/ondo.ts
1765
+ var OndoTradingStatus = {
1170
1766
  fromDto: (dto) => {
1171
- const expiresAt = new Date(Date.now() + dto.expires_in * 1e3);
1767
+ if (!dto.tradable) return { type: "not-tradable", side: dto.side };
1172
1768
  return {
1173
- accessToken: {
1174
- value: dto.access_token,
1175
- expiresAt
1769
+ type: "tradable",
1770
+ side: dto.side,
1771
+ grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
1772
+ grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
1773
+ grossMaxActiveNotionalValue: decimalOrNull(
1774
+ dto.gross_max_active_notional_value
1775
+ )
1776
+ };
1777
+ }
1778
+ };
1779
+ var decimalOrNull = (value) => value === null ? null : DecimalString(value);
1780
+ var OndoQuote = {
1781
+ fromDto: (dto) => {
1782
+ const assetDecimals = AssetDecimals(dto.asset_decimals);
1783
+ return {
1784
+ chain: chainFromId(dto.chain_id),
1785
+ ticker: Ticker(dto.ticker),
1786
+ assetAddress: EvmContractAddress(dto.asset_address),
1787
+ asset: {
1788
+ name: dto.ticker,
1789
+ symbol: AssetSymbol(dto.symbol),
1790
+ decimals: assetDecimals
1176
1791
  },
1177
- ...dto.refresh_token != null && dto.refresh_token !== "" ? { refreshToken: OAuthRefreshToken(dto.refresh_token) } : void 0
1792
+ side: dto.side,
1793
+ tokenBaseUnits: blockchainAmountFromRawOrThrow({
1794
+ label: "tokenBaseUnits",
1795
+ raw: dto.token_base_units,
1796
+ decimals: assetDecimals
1797
+ }),
1798
+ price: DecimalString(dto.price)
1178
1799
  };
1179
1800
  }
1180
1801
  };
1181
-
1182
- // src/server/coinlist.server.ts
1183
- var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
1184
- var CoinListServerImpl = class {
1185
- constructor(_config) {
1186
- this._config = _config;
1187
- this.baseUrl = _config.baseUrl ?? PUBLIC_API_BASE_URL;
1188
- this.accessTokenExpiryBufferSeconds = _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS;
1189
- this.strict = _config.strict ?? false;
1190
- this.api = new Api(
1191
- {
1192
- baseUrl: this.baseUrl,
1193
- xApiVersion: API_VERSION
1802
+ var OndoBuyTransaction = {
1803
+ fromDto: (dto) => {
1804
+ const spendDecimals = AssetDecimals(dto.spend_input_decimals);
1805
+ const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1806
+ return {
1807
+ ...parseSwapCore(dto, spendDecimals),
1808
+ side: "buy",
1809
+ fee: blockchainAmountFromRawOrThrow({
1810
+ label: "fee",
1811
+ raw: dto.fee,
1812
+ decimals: spendDecimals
1813
+ }),
1814
+ notionalValue: blockchainAmountFromRawOrThrow({
1815
+ label: "notional_value",
1816
+ raw: dto.notional_value,
1817
+ decimals: spendDecimals
1818
+ }),
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
+ })
1831
+ };
1832
+ }
1833
+ };
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
+ })
1194
1854
  },
1195
- // When refresh=true the renewal middleware has received a 401 and wants a
1196
- // fresh token. A read-only store cannot persist a new session, so return
1197
- // null immediately — this tells the middleware to skip the retry rather
1198
- // than re-sending with the same expired token and wasting a round-trip.
1199
- (refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.accessToken()
1200
- );
1201
- const ctx = {
1202
- api: this.api,
1203
- ensureUserAuthenticated: () => this.ensureUserAuthenticated()
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
+ }
1204
1867
  };
1205
- this.erc20 = new Erc20NamespaceImpl(ctx);
1206
- this.tokenSale = new TokenSaleNamespaceImpl(ctx);
1207
- this.swap = new SwapNamespaceImpl(ctx);
1208
1868
  }
1209
- async completeOAuth(code, codeVerifier) {
1210
- const sessionStore = this._config.sessionStore;
1211
- const setSession = sessionStore.setSession?.bind(sessionStore);
1212
- if (!setSession) {
1213
- throw new WritableSessionStoreRequiredError();
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",
1897
+ raw,
1898
+ decimals,
1899
+ reason: "a floor of zero guarantees nothing"
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 });
1915
+ if (amount.raw <= 0n) {
1916
+ throw new ValidationError(
1917
+ `${label}: must be greater than zero ("${raw}") - ${reason}`
1918
+ );
1919
+ }
1920
+ return amount;
1921
+ }
1922
+ function parseExpiresAt(value) {
1923
+ const date = new Date(value);
1924
+ if (Number.isNaN(date.getTime())) {
1925
+ throw new ValidationError(`expires_at: not a date ("${value}")`);
1926
+ }
1927
+ return date;
1928
+ }
1929
+
1930
+ // src/shared/api/frontline/providers/ondo/ondo.ts
1931
+ async function getOndoTradingStatus(api, params) {
1932
+ const dto = await api.send({
1933
+ method: "GET",
1934
+ url: "/v1/ondo/swap/trading-status",
1935
+ queryParams: { symbol: params.symbol, side: params.side },
1936
+ attributes: Attributes.protected()
1937
+ });
1938
+ return OndoTradingStatus.fromDto(dto);
1939
+ }
1940
+ async function getOndoQuote(api, params) {
1941
+ const dto = await api.send({
1942
+ method: "GET",
1943
+ url: "/v1/ondo/swap/quote",
1944
+ queryParams: {
1945
+ symbol: params.symbol,
1946
+ side: params.side,
1947
+ duration: params.duration,
1948
+ ...sizeParam(params)
1949
+ },
1950
+ attributes: Attributes.protected()
1951
+ });
1952
+ return OndoQuote.fromDto(dto);
1953
+ }
1954
+ async function buildOndoBuy(api, params) {
1955
+ const dto = await api.send({
1956
+ method: "POST",
1957
+ url: "/v1/ondo/swap/buy",
1958
+ body: swapBody(params),
1959
+ attributes: Attributes.protected()
1960
+ });
1961
+ assertSpendScaleAgrees({
1962
+ published: dto.spend_input_decimals,
1963
+ sized: params.amount,
1964
+ trade: "purchase"
1965
+ });
1966
+ return OndoBuyTransaction.fromDto(dto);
1967
+ }
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
+ );
2005
+ }
2006
+ function sizeParam(params) {
2007
+ const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
2008
+ const notionalValue = "notionalValue" in params ? params.notionalValue : void 0;
2009
+ if (tokenAmount !== void 0) {
2010
+ if (notionalValue !== void 0) {
2011
+ throw new ValidationError(
2012
+ "An Ondo quote takes tokenAmount or notionalValue, not both"
2013
+ );
1214
2014
  }
1215
- const sessionDto = await this.api.send({
1216
- method: "POST",
1217
- url: `/oauth/token`,
1218
- body: {
1219
- grant_type: "authorization_code",
1220
- code,
1221
- redirect_uri: this._config.redirectUri,
1222
- client_id: this._config.clientId,
1223
- client_secret: this._config.clientSecret,
1224
- code_verifier: codeVerifier
1225
- }
2015
+ return { token_amount: formatRawAmount(tokenAmount) };
2016
+ }
2017
+ if (notionalValue === void 0) {
2018
+ throw new ValidationError(
2019
+ "An Ondo quote must be sized by tokenAmount or notionalValue"
2020
+ );
2021
+ }
2022
+ return { notional_value: notionalValue };
2023
+ }
2024
+
2025
+ // src/shared/core/checkout/ondo/ondo-namespace.ts
2026
+ var OndoNamespaceImpl = class {
2027
+ constructor(ctx) {
2028
+ this.ctx = ctx;
2029
+ this.log = internalLogger(ctx.logger, "ONDO");
2030
+ }
2031
+ async getTradingStatus(params) {
2032
+ return this.log.wrap("getTradingStatus", params, async () => {
2033
+ await this.ctx.ensureUserAuthenticated();
2034
+ return getOndoTradingStatus(this.ctx.api, params);
1226
2035
  });
1227
- const session = OAuthSession.fromDto(sessionDto);
1228
- await setSession(session);
1229
- return session;
1230
- }
1231
- async clientCredentialsOAuth() {
1232
- const sessionDto = await this.api.send({
1233
- method: "POST",
1234
- url: `/oauth/token`,
1235
- body: {
1236
- grant_type: "client_credentials",
1237
- client_id: this._config.clientId,
1238
- client_secret: this._config.clientSecret
1239
- }
2036
+ }
2037
+ async getQuote(params) {
2038
+ return this.log.wrap("getQuote", params, async () => {
2039
+ await this.ctx.ensureUserAuthenticated();
2040
+ return getOndoQuote(this.ctx.api, params);
1240
2041
  });
1241
- const session = OAuthSession.fromDto(sessionDto);
1242
- return ClientCredentialsOAuth(session.accessToken);
1243
2042
  }
1244
- async accessToken() {
1245
- const sessionStore = this._config.sessionStore;
1246
- const session = await sessionStore.getSession();
1247
- if (session == null) return null;
1248
- const now = Date.now();
1249
- const expiresAt = session.accessToken.expiresAt.getTime();
1250
- const bufferMs = this.accessTokenExpiryBufferSeconds * 1e3;
1251
- if (expiresAt > now + bufferMs) {
1252
- return session.accessToken;
1253
- }
1254
- const setSession = sessionStore.setSession?.bind(sessionStore);
1255
- if (!setSession) {
1256
- return session.accessToken;
1257
- } else {
1258
- return this.refreshSession(session.refreshToken, setSession);
1259
- }
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
+ });
1260
2048
  }
1261
- async refreshSession(refreshToken, setSession) {
1262
- if (!refreshToken) {
1263
- await setSession(null);
1264
- return null;
1265
- }
1266
- try {
1267
- const sessionDto = await this.api.send({
1268
- method: "POST",
1269
- url: `/oauth/token`,
1270
- body: {
1271
- grant_type: "refresh_token",
1272
- refresh_token: refreshToken,
1273
- client_id: this._config.clientId,
1274
- client_secret: this._config.clientSecret
1275
- }
1276
- });
1277
- const newSession = OAuthSession.fromDto(sessionDto);
1278
- await setSession(newSession);
1279
- return newSession.accessToken;
1280
- } catch {
1281
- await setSession(null);
1282
- return null;
1283
- }
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
+ });
1284
2054
  }
1285
- async logout() {
1286
- const sessionStore = this._config.sessionStore;
1287
- const setSession = sessionStore.setSession?.bind(sessionStore);
1288
- if (!setSession) {
1289
- throw new WritableSessionStoreRequiredError();
1290
- }
1291
- const session = await sessionStore.getSession();
1292
- if (session != null) {
1293
- const tokenToRevoke = session.accessToken.value;
2055
+ };
2056
+
2057
+ // src/shared/core/checkout/superstate/swap-namespace.ts
2058
+ var SuperstateSwapNamespaceImpl = class {
2059
+ constructor(ctx) {
2060
+ this.ctx = ctx;
2061
+ this.log = internalLogger(ctx.logger, "SUPERSTATE");
2062
+ }
2063
+ async getAuthorization(params) {
2064
+ return this.log.wrap("getAuthorization", params, async () => {
2065
+ await this.ctx.ensureUserAuthenticated();
2066
+ return getSwapAuthorization(this.ctx.api, params);
2067
+ });
2068
+ }
2069
+ async getPreview(params) {
2070
+ return this.log.wrap("getPreview", params, async () => {
2071
+ await this.ctx.ensureUserAuthenticated();
2072
+ return getSwapPreview(this.ctx.api, params);
2073
+ });
2074
+ }
2075
+ async getStatus(params) {
2076
+ return this.log.wrap("getStatus", params, async () => {
2077
+ await this.ctx.ensureUserAuthenticated();
2078
+ return getSwapStatus(this.ctx.api, params);
2079
+ });
2080
+ }
2081
+ async getOutputToken(params) {
2082
+ return this.log.wrap("getOutputToken", params, async () => {
2083
+ await this.ctx.ensureUserAuthenticated();
2084
+ return getSwapOutputToken(this.ctx.api, params);
2085
+ });
2086
+ }
2087
+ async allowWallet(params) {
2088
+ return this.log.wrap("allowWallet", params, async () => {
2089
+ await this.ctx.ensureUserAuthenticated();
2090
+ return allowWallet(this.ctx.api, params);
2091
+ });
2092
+ }
2093
+ };
2094
+
2095
+ // src/shared/api/nabu/tokens.ts
2096
+ var import_viem3 = require("viem");
2097
+
2098
+ // src/shared/types/token-metadata.ts
2099
+ var TokenLogoUrl = (value) => value;
2100
+ var TokenLogo = {
2101
+ /** `baseUrl` is the registry origin; registry URLs are root-relative. */
2102
+ fromDto: (dto, baseUrl) => dto.kind === "VECTOR" ? { kind: "VECTOR", url: resolveLogoUrl(dto.url, baseUrl) } : {
2103
+ kind: "RASTER",
2104
+ original: logoImageFromDto(dto.original, baseUrl),
2105
+ variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl))
2106
+ }
2107
+ };
2108
+ var TokenMetadata = {
2109
+ /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */
2110
+ fromDto: (dto, baseUrl) => {
2111
+ assertSupportedSchemaVersion(dto.schema_version);
2112
+ return {
2113
+ identifier: {
2114
+ chain: EthereumChain(dto.chain),
2115
+ address: EvmContractAddress(dto.address)
2116
+ },
2117
+ name: dto.name,
2118
+ symbol: AssetSymbol(dto.symbol),
2119
+ decimals: AssetDecimals(dto.decimals),
2120
+ logo: TokenLogo.fromDto(dto.logo, baseUrl),
2121
+ logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
2122
+ };
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;
1294
2134
  try {
1295
- await this.api.send({
1296
- method: "POST",
1297
- url: `/oauth/revoke`,
1298
- body: {
1299
- token: tokenToRevoke,
1300
- client_id: this._config.clientId,
1301
- client_secret: this._config.clientSecret
1302
- }
1303
- });
1304
- } catch (err) {
1305
- if (err instanceof HttpError) {
1306
- if (this.strict) {
1307
- throw err;
1308
- }
1309
- } else {
1310
- throw err;
1311
- }
2135
+ chain = EthereumChain(chainDto.chain);
2136
+ } catch {
2137
+ return [];
1312
2138
  }
1313
- await setSession(null);
2139
+ return tokensOfChain(chain, chainDto.assets, baseUrl);
2140
+ });
2141
+ },
2142
+ /**
2143
+ * Maps a chain snapshot to the tokens it lists, skipping the chain's native
2144
+ * coin (`kind: 'COIN'`, no contract address).
2145
+ */
2146
+ fromChainAssetsDto: (dto, baseUrl) => {
2147
+ assertSupportedSchemaVersion(dto.schema_version);
2148
+ return tokensOfChain(EthereumChain(dto.chain), dto.assets, baseUrl);
2149
+ }
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
+ }
2165
+ function assertSupportedSchemaVersion(version) {
2166
+ if (version !== 1) {
2167
+ throw new ValidationError(
2168
+ `Unsupported token registry schema_version: ${version}`
2169
+ );
2170
+ }
2171
+ }
2172
+ var logoImageFromDto = (dto, baseUrl) => ({
2173
+ url: resolveLogoUrl(dto.url, baseUrl),
2174
+ width: dto.width,
2175
+ height: dto.height
2176
+ });
2177
+ var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
2178
+ url.startsWith("http") ? url : `${baseUrl.replace(/\/$/, "")}${url}`
2179
+ );
2180
+
2181
+ // src/shared/api/nabu/tokens.ts
2182
+ function createNabuApiClient(baseUrl, logger = null) {
2183
+ return new HttpClient({ baseUrl }, {}, logger);
2184
+ }
2185
+ async function fetchTokenMetadata(client, token) {
2186
+ const address = checksummed(token.address);
2187
+ let response;
2188
+ try {
2189
+ response = await client.send({
2190
+ method: "GET",
2191
+ url: `/${token.chain}/token/${address}`
2192
+ });
2193
+ } catch (error) {
2194
+ if (isRegistryHtmlFallback(error)) {
2195
+ return null;
1314
2196
  }
2197
+ throw error;
1315
2198
  }
1316
- async fetchOffers(clientCreds) {
1317
- await this.ensureAuthenticated(clientCreds);
1318
- return fetchOffers(this.api, clientCreds);
2199
+ if (response.status === 404) {
2200
+ return null;
1319
2201
  }
1320
- async fetchOffersPage(params, clientCreds) {
1321
- await this.ensureAuthenticated(clientCreds);
1322
- return fetchOffersPage(this.api, params, clientCreds);
2202
+ assertOk(response);
2203
+ if (response.body === null) {
2204
+ throw new ValidationError(
2205
+ `Token registry returned an empty body for token "${address}" on "${token.chain}"`
2206
+ );
1323
2207
  }
1324
- async fetchOfferDetails(id, clientCreds) {
1325
- await this.ensureAuthenticated(clientCreds);
1326
- return fetchOfferDetails(this.api, id, clientCreds);
2208
+ return TokenMetadata.fromDto(response.body, client.config.baseUrl);
2209
+ }
2210
+ async function fetchTokensMetadata(client, chain) {
2211
+ let response;
2212
+ try {
2213
+ response = await client.send({
2214
+ method: "GET",
2215
+ url: `/${chain}/assets.json`
2216
+ });
2217
+ } catch (error) {
2218
+ if (isRegistryHtmlFallback(error)) {
2219
+ throw new ValidationError(
2220
+ `Token registry returned non-JSON for the "${chain}" snapshot`
2221
+ );
2222
+ }
2223
+ throw error;
1327
2224
  }
1328
- async createWalletOwnershipChallenge(params) {
1329
- await this.ensureUserAuthenticated();
1330
- return createWalletOwnershipChallenge(this.api, params);
2225
+ assertOk(response);
2226
+ if (response.body === null) {
2227
+ throw new ValidationError(
2228
+ `Token registry returned an empty "${chain}" snapshot`
2229
+ );
1331
2230
  }
1332
- async connectExternalWallet(offerId, params) {
1333
- await this.ensureUserAuthenticated();
1334
- return connectExternalWallet(this.api, offerId, params);
2231
+ return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
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;
1335
2247
  }
1336
- async listOptionAddresses(offerId, offerOptionId) {
1337
- await this.ensureUserAuthenticated();
1338
- return listOptionAddresses(
1339
- this.api,
1340
- offerId,
1341
- offerOptionId
2248
+ assertOk(response);
2249
+ if (response.body === null) {
2250
+ throw new ValidationError(
2251
+ "Token registry returned an empty complete snapshot"
1342
2252
  );
1343
2253
  }
1344
- async removeOptionAddress(offerId, addressId) {
1345
- await this.ensureUserAuthenticated();
1346
- return removeOptionAddress(this.api, offerId, addressId);
2254
+ return TokenMetadata.fromRegistryDto(response.body, client.config.baseUrl);
2255
+ }
2256
+ function isRegistryHtmlFallback(error) {
2257
+ return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
2258
+ }
2259
+ function assertOk(response) {
2260
+ if (response.status < 200 || response.status >= 300) {
2261
+ throw new HttpError(response);
2262
+ }
2263
+ }
2264
+ function checksummed(address) {
2265
+ try {
2266
+ return (0, import_viem3.getAddress)(address);
2267
+ } catch (_) {
2268
+ throw new ValidationError(`Invalid EVM contract address: "${address}"`);
1347
2269
  }
1348
- async fetchOfferRequirements(offerId, clientCreds) {
1349
- await this.ensureAuthenticated(clientCreds);
1350
- return fetchOfferRequirements(
1351
- this.api,
1352
- offerId,
1353
- clientCreds
2270
+ }
2271
+
2272
+ // src/shared/core/tokens/tokens-namespace.ts
2273
+ var TokensNamespaceImpl = class {
2274
+ /**
2275
+ * Takes the registry origin rather than a `SharedNamespaceContext`: the
2276
+ * registry is unauthenticated and on its own host, so the frontline sender
2277
+ * and the auth check would both be dead weight here.
2278
+ */
2279
+ constructor(baseUrl, logger = null) {
2280
+ this.api = createNabuApiClient(baseUrl, logger);
2281
+ this.log = internalLogger(logger, "TOKENS");
2282
+ }
2283
+ get(token) {
2284
+ return this.log.wrap(
2285
+ "get",
2286
+ token,
2287
+ () => fetchTokenMetadata(this.api, token)
1354
2288
  );
1355
2289
  }
1356
- async fetchRequirementStatuses(offerId) {
1357
- await this.ensureUserAuthenticated();
1358
- return fetchRequirementStatuses(this.api, offerId);
2290
+ list(chain) {
2291
+ return this.log.wrap(
2292
+ "list",
2293
+ chain,
2294
+ () => chain === void 0 ? fetchAllTokensMetadata(this.api) : fetchTokensMetadata(this.api, chain)
2295
+ );
1359
2296
  }
1360
- async ensureAuthenticated(clientCreds) {
1361
- if (!clientCreds) {
1362
- await this.ensureUserAuthenticated();
2297
+ };
2298
+
2299
+ // src/shared/types/offer-option-address.ts
2300
+ var OfferOptionAddressId = (value) => value;
2301
+ var OfferOptionAddress = {
2302
+ /** Maps the API DTO into the SDK offer-option-address domain model. */
2303
+ fromDto: (dto) => ({
2304
+ id: OfferOptionAddressId(dto.id),
2305
+ offerOptionId: OfferOptionId(dto.offer_option_id),
2306
+ address: EvmWalletAddress(dto.address),
2307
+ protocol: dto.protocol,
2308
+ createdAt: new Date(dto.created_at)
2309
+ })
2310
+ };
2311
+ var ConnectExternalWalletParams = {
2312
+ /** Maps connect-wallet params into the API DTO payload. */
2313
+ toDto: (params) => ({
2314
+ offer_option_id: params.offerOptionId,
2315
+ wallet_address: params.walletAddress,
2316
+ chain: params.chain,
2317
+ signature: params.signature
2318
+ })
2319
+ };
2320
+
2321
+ // src/shared/types/wallet-ownership-challenge.ts
2322
+ var WalletOwnershipChallenge = {
2323
+ /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
2324
+ fromDto: (dto) => ({
2325
+ message: dto.message,
2326
+ expiresAt: new Date(dto.expires_at)
2327
+ })
2328
+ };
2329
+ var CreateWalletOwnershipChallengeParams = {
2330
+ /**
2331
+ * Maps challenge-request params into the API DTO payload. The discriminated
2332
+ * union guarantees SIWE fields are present exactly when `challengeType` is
2333
+ * `siwe`, so the mapping narrows on the discriminant.
2334
+ */
2335
+ toDto: (params) => {
2336
+ switch (params.challengeType) {
2337
+ case "plain":
2338
+ return {
2339
+ wallet_address: params.walletAddress,
2340
+ chain: params.chain,
2341
+ challenge_type: "plain"
2342
+ };
2343
+ case "siwe":
2344
+ return {
2345
+ wallet_address: params.walletAddress,
2346
+ chain: params.chain,
2347
+ challenge_type: "siwe",
2348
+ domain: params.domain,
2349
+ uri: params.uri,
2350
+ statement: params.statement
2351
+ };
2352
+ default: {
2353
+ const _exhaustive = params;
2354
+ return _exhaustive;
2355
+ }
1363
2356
  }
1364
2357
  }
1365
- async ensureUserAuthenticated() {
1366
- const token = await this.accessToken();
1367
- if (token === null) {
1368
- throw new NotAuthenticatedError();
1369
- }
2358
+ };
2359
+
2360
+ // src/shared/api/frontline/wallet-connect.ts
2361
+ async function createWalletOwnershipChallenge(api, params) {
2362
+ const dto = await api.send({
2363
+ method: "POST",
2364
+ url: "/v1/wallet-ownership",
2365
+ body: CreateWalletOwnershipChallengeParams.toDto(params),
2366
+ attributes: Attributes.protected()
2367
+ });
2368
+ return WalletOwnershipChallenge.fromDto(dto);
2369
+ }
2370
+ async function connectExternalWallet(api, params) {
2371
+ const dto = await api.send({
2372
+ method: "POST",
2373
+ url: `/v1/offers/${params.offerId}/addresses`,
2374
+ body: ConnectExternalWalletParams.toDto(params),
2375
+ attributes: Attributes.protected()
2376
+ });
2377
+ return OfferOptionAddress.fromDto(dto);
2378
+ }
2379
+ async function listOptionAddresses(api, offerId, offerOptionId) {
2380
+ const { data } = await api.send({
2381
+ method: "GET",
2382
+ url: `/v1/offers/${offerId}/addresses`,
2383
+ queryParams: { offer_option_id: offerOptionId },
2384
+ attributes: Attributes.protected()
2385
+ });
2386
+ return data.map(OfferOptionAddress.fromDto);
2387
+ }
2388
+ async function removeOptionAddress(api, offerId, addressId) {
2389
+ const dto = await api.send({
2390
+ method: "DELETE",
2391
+ url: `/v1/offers/${offerId}/addresses/${addressId}`,
2392
+ attributes: Attributes.protected()
2393
+ });
2394
+ return OfferOptionAddress.fromDto(dto);
2395
+ }
2396
+
2397
+ // src/shared/core/wallets/wallets-namespace.ts
2398
+ var WalletsNamespaceImpl = class {
2399
+ constructor(ctx) {
2400
+ this.ctx = ctx;
2401
+ this.log = internalLogger(ctx.logger, "WALLETS");
2402
+ }
2403
+ async createOwnershipChallenge(params) {
2404
+ return this.log.wrap("createOwnershipChallenge", params, async () => {
2405
+ await this.ctx.ensureUserAuthenticated();
2406
+ return createWalletOwnershipChallenge(
2407
+ this.ctx.api,
2408
+ params
2409
+ );
2410
+ });
1370
2411
  }
1371
- async fetchPii() {
1372
- await this.ensureUserAuthenticated();
1373
- return fetchPii(this.api);
2412
+ async connectExternal(params) {
2413
+ return this.log.wrap("connectExternal", params, async () => {
2414
+ await this.ctx.ensureUserAuthenticated();
2415
+ return connectExternalWallet(this.ctx.api, params);
2416
+ });
2417
+ }
2418
+ async list(params) {
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
+ });
2427
+ }
2428
+ async remove(params) {
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
+ });
1374
2437
  }
1375
- async submitDocument(documentType, fields) {
1376
- await this.ensureUserAuthenticated();
1377
- return submitDocument(this.api, documentType, fields);
2438
+ };
2439
+
2440
+ // src/server/core/coinlist-server.ts
2441
+ var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
2442
+ var CoinListServerImpl = class {
2443
+ constructor(_config) {
2444
+ this._config = _config;
2445
+ const logger = _config.logger ?? null;
2446
+ this.api = new ApiClient(
2447
+ {
2448
+ baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
2449
+ xApiVersion: API_VERSION
2450
+ },
2451
+ // When refresh=true the renewal middleware has received a 401 and wants a
2452
+ // fresh token. A read-only store cannot persist a new session, so return
2453
+ // null immediately — this tells the middleware to skip the retry rather
2454
+ // than re-sending with the same expired token and wasting a round-trip.
2455
+ (refresh) => refresh && !this._config.sessionStore.setSession ? Promise.resolve(null) : this.auth.getAccessToken(),
2456
+ logger
2457
+ );
2458
+ this.auth = new ServerAuthNamespaceImpl(this.api, {
2459
+ ..._config,
2460
+ accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,
2461
+ strict: _config.strict ?? false
2462
+ });
2463
+ const ctx = {
2464
+ api: this.api,
2465
+ logger,
2466
+ ensureUserAuthenticated: () => this.ensureAuthenticated(void 0),
2467
+ ensureAuthenticated: (clientCreds) => this.ensureAuthenticated(clientCreds)
2468
+ };
2469
+ this.offers = new ServerOffersNamespaceImpl(ctx);
2470
+ this.requirements = new ServerRequirementsNamespaceImpl(ctx);
2471
+ this.wallets = new WalletsNamespaceImpl(ctx);
2472
+ this.erc20 = new Erc20NamespaceImpl(ctx);
2473
+ this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);
2474
+ this.superstate = new SuperstateSwapNamespaceImpl(ctx);
2475
+ this.ondo = new OndoNamespaceImpl(ctx);
2476
+ this.tokens = new TokensNamespaceImpl(
2477
+ _config.tokensBaseUrl ?? NABU_BASE_URL,
2478
+ logger
2479
+ );
1378
2480
  }
1379
- async createKycToken(levelName, reset) {
1380
- await this.ensureUserAuthenticated();
1381
- return createKycToken(this.api, levelName, reset);
2481
+ /**
2482
+ * An app-level token authenticates a request on its own; without one the
2483
+ * caller needs a user session.
2484
+ */
2485
+ async ensureAuthenticated(clientCreds) {
2486
+ if (clientCreds) return;
2487
+ const token = await this.auth.getAccessToken();
2488
+ if (token === null) {
2489
+ throw new NotAuthenticatedError();
2490
+ }
1382
2491
  }
1383
2492
  };
1384
2493
  function createCoinListServer(config) {
1385
2494
  return new CoinListServerImpl(config);
1386
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
+ }
1387
2639
  // Annotate the CommonJS export names for ESM import in node:
1388
2640
  0 && (module.exports = {
2641
+ ServerAuthNamespaceImpl,
2642
+ ServerOffersNamespaceImpl,
2643
+ ServerRequirementsNamespaceImpl,
1389
2644
  WritableSessionStoreRequiredError,
1390
- createCoinListServer
2645
+ createCoinListServer,
2646
+ emptySessionStore,
2647
+ pinoServerLogger
1391
2648
  });
1392
2649
  //# sourceMappingURL=index.cjs.map