@coinlist-co/react 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +32 -0
  2. package/dist/{chunk-GSSAB4K5.js → chunk-B2HCVPCQ.js} +225 -247
  3. package/dist/chunk-B2HCVPCQ.js.map +1 -0
  4. package/dist/chunk-KDGNDAHA.js +146 -0
  5. package/dist/chunk-KDGNDAHA.js.map +1 -0
  6. package/dist/chunk-UIIXXLA7.js +1863 -0
  7. package/dist/chunk-UIIXXLA7.js.map +1 -0
  8. package/dist/client/index.cjs +10559 -3442
  9. package/dist/client/index.cjs.map +1 -1
  10. package/dist/client/index.d.cts +4219 -862
  11. package/dist/client/index.d.ts +4219 -862
  12. package/dist/client/index.js +8729 -2370
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/collections-BhDkYmzV.d.cts +65 -0
  15. package/dist/collections-CZhHoQHr.d.ts +65 -0
  16. package/dist/config-B5mwS_2l.d.cts +1926 -0
  17. package/dist/config-B5mwS_2l.d.ts +1926 -0
  18. package/dist/server/index.cjs +981 -464
  19. package/dist/server/index.cjs.map +1 -1
  20. package/dist/server/index.d.cts +190 -163
  21. package/dist/server/index.d.ts +190 -163
  22. package/dist/server/index.js +151 -156
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/shared/index.cjs +1810 -907
  25. package/dist/shared/index.cjs.map +1 -1
  26. package/dist/shared/index.d.cts +243 -132
  27. package/dist/shared/index.d.ts +243 -132
  28. package/dist/shared/index.js +102 -114
  29. package/dist/shared/index.js.map +1 -1
  30. package/package.json +10 -7
  31. package/dist/chunk-7BJ2HAG7.js +0 -442
  32. package/dist/chunk-7BJ2HAG7.js.map +0 -1
  33. package/dist/chunk-AAER5LOL.js +0 -22
  34. package/dist/chunk-AAER5LOL.js.map +0 -1
  35. package/dist/chunk-GSSAB4K5.js.map +0 -1
  36. package/dist/chunk-TUZKKFNW.js +0 -836
  37. package/dist/chunk-TUZKKFNW.js.map +0 -1
  38. package/dist/collections-CJ24dOda.d.cts +0 -28
  39. package/dist/collections-ZYLKp8JB.d.ts +0 -28
  40. package/dist/requirement-CDi5NJI8.d.cts +0 -1036
  41. package/dist/requirement-CDi5NJI8.d.ts +0 -1036
@@ -20,6 +20,9 @@ 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
27
  createCoinListServer: () => createCoinListServer
25
28
  });
@@ -119,7 +122,16 @@ async function makeRequest(request) {
119
122
  };
120
123
  }
121
124
  const text = await response.text();
122
- const body = text ? JSON.parse(text) : null;
125
+ let body;
126
+ try {
127
+ body = text ? JSON.parse(text) : null;
128
+ } catch (_) {
129
+ throw new HttpError({
130
+ status: response.status,
131
+ headers: responseHeaders,
132
+ body: text
133
+ });
134
+ }
123
135
  return {
124
136
  status: response.status,
125
137
  body,
@@ -215,7 +227,7 @@ var HttpClient = class {
215
227
  const url = this.resolveUrl(request.url);
216
228
  const headers = {
217
229
  ...request.headers ?? {},
218
- [HEADER_API_VERSION]: this.config.xApiVersion
230
+ ...this.config.xApiVersion !== void 0 ? { [HEADER_API_VERSION]: this.config.xApiVersion } : {}
219
231
  };
220
232
  return {
221
233
  ...request,
@@ -275,7 +287,7 @@ function attachSessionMiddleware(fetchAccessToken) {
275
287
  };
276
288
  }
277
289
 
278
- // src/shared/utils.ts
290
+ // src/shared/core/utils/crypto.ts
279
291
  function getUUIDv4() {
280
292
  if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
281
293
  return crypto.randomUUID();
@@ -401,8 +413,8 @@ var AuthenticatedApiClient = class {
401
413
  }
402
414
  };
403
415
 
404
- // src/server/api/api.server.ts
405
- var Api = class {
416
+ // src/server/core/api/api-client.ts
417
+ var ApiClient = class {
406
418
  constructor(config, fetchAccessToken) {
407
419
  this.client = new AuthenticatedApiClient(config, fetchAccessToken);
408
420
  }
@@ -419,48 +431,138 @@ var WritableSessionStoreRequiredError = class extends Error {
419
431
  }
420
432
  };
421
433
 
422
- // src/shared/types/document-submission.ts
423
- var DocumentSubmission = {
424
- fromDto: (dto) => ({
425
- status: dto.status,
426
- formType: dto.form_type
427
- })
434
+ // src/shared/types/oauth-session.ts
435
+ var ClientCredentialsOAuth = (value) => value;
436
+ var OAuthRefreshToken = (value) => value;
437
+ var OAuthSession = {
438
+ fromDto: (dto) => {
439
+ const expiresAt = new Date(Date.now() + dto.expires_in * 1e3);
440
+ return {
441
+ accessToken: {
442
+ value: dto.access_token,
443
+ expiresAt
444
+ },
445
+ ...dto.refresh_token != null && dto.refresh_token !== "" ? { refreshToken: OAuthRefreshToken(dto.refresh_token) } : void 0
446
+ };
447
+ }
428
448
  };
429
449
 
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);
439
- }
440
-
441
- // src/shared/types/kyc.ts
442
- var KycToken = {
443
- fromDto: (dto) => ({
444
- token: dto.token
445
- })
450
+ // src/server/core/server-auth-namespace.ts
451
+ var ServerAuthNamespaceImpl = class {
452
+ constructor(api, config) {
453
+ this.api = api;
454
+ this.config = config;
455
+ }
456
+ async completeOAuth({
457
+ code,
458
+ codeVerifier
459
+ }) {
460
+ const setSession = this.writableSessionStore();
461
+ const sessionDto = await this.api.send({
462
+ method: "POST",
463
+ url: `/oauth/token`,
464
+ body: {
465
+ grant_type: "authorization_code",
466
+ code,
467
+ redirect_uri: this.config.redirectUri,
468
+ client_id: this.config.clientId,
469
+ client_secret: this.config.clientSecret,
470
+ code_verifier: codeVerifier
471
+ }
472
+ });
473
+ const session = OAuthSession.fromDto(sessionDto);
474
+ await setSession(session);
475
+ return session;
476
+ }
477
+ async getAccessToken() {
478
+ const sessionStore = this.config.sessionStore;
479
+ const session = await sessionStore.getSession();
480
+ if (session == null) return null;
481
+ const now = Date.now();
482
+ const expiresAt = session.accessToken.expiresAt.getTime();
483
+ const bufferMs = this.config.accessTokenExpiryBufferSeconds * 1e3;
484
+ if (expiresAt > now + bufferMs) {
485
+ return session.accessToken;
486
+ }
487
+ const setSession = sessionStore.setSession?.bind(sessionStore);
488
+ if (!setSession) {
489
+ return session.accessToken;
490
+ }
491
+ return this.refreshSession(session.refreshToken, setSession);
492
+ }
493
+ async refreshSession(refreshToken, setSession) {
494
+ if (!refreshToken) {
495
+ await setSession(null);
496
+ return null;
497
+ }
498
+ try {
499
+ const sessionDto = await this.api.send({
500
+ method: "POST",
501
+ url: `/oauth/token`,
502
+ body: {
503
+ grant_type: "refresh_token",
504
+ refresh_token: refreshToken,
505
+ client_id: this.config.clientId,
506
+ client_secret: this.config.clientSecret
507
+ }
508
+ });
509
+ const newSession = OAuthSession.fromDto(sessionDto);
510
+ await setSession(newSession);
511
+ return newSession.accessToken;
512
+ } catch {
513
+ await setSession(null);
514
+ return null;
515
+ }
516
+ }
517
+ async clientCredentials() {
518
+ const sessionDto = await this.api.send({
519
+ method: "POST",
520
+ url: `/oauth/token`,
521
+ body: {
522
+ grant_type: "client_credentials",
523
+ client_id: this.config.clientId,
524
+ client_secret: this.config.clientSecret
525
+ }
526
+ });
527
+ const session = OAuthSession.fromDto(sessionDto);
528
+ return ClientCredentialsOAuth(session.accessToken);
529
+ }
530
+ async logout() {
531
+ const setSession = this.writableSessionStore();
532
+ const session = await this.config.sessionStore.getSession();
533
+ if (session == null) return;
534
+ try {
535
+ await this.api.send({
536
+ method: "POST",
537
+ url: `/oauth/revoke`,
538
+ body: {
539
+ token: session.accessToken.value,
540
+ client_id: this.config.clientId,
541
+ client_secret: this.config.clientSecret
542
+ }
543
+ });
544
+ } catch (err) {
545
+ if (!(err instanceof HttpError) || this.config.strict) {
546
+ throw err;
547
+ }
548
+ }
549
+ await setSession(null);
550
+ }
551
+ /**
552
+ * Returns the store's `setSession`, or throws — the guard every
553
+ * session-writing operation shares.
554
+ */
555
+ writableSessionStore() {
556
+ const sessionStore = this.config.sessionStore;
557
+ const setSession = sessionStore.setSession?.bind(sessionStore);
558
+ if (!setSession) {
559
+ throw new WritableSessionStoreRequiredError();
560
+ }
561
+ return setSession;
562
+ }
446
563
  };
447
564
 
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
565
  // src/shared/api/pagination.ts
463
- var Cursor = (value) => value;
464
566
  async function fetchAllPages(fetchPage, baseParams) {
465
567
  const items = [];
466
568
  let cursor = null;
@@ -475,28 +577,6 @@ async function fetchAllPages(fetchPage, baseParams) {
475
577
  } while (cursor);
476
578
  return items;
477
579
  }
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
- })
484
- };
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;
498
- }
499
- };
500
580
 
501
581
  // src/shared/types/offer.ts
502
582
  var OfferId = (value) => value;
@@ -526,6 +606,86 @@ var Asset = {
526
606
  })
527
607
  };
528
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
+ // src/shared/types/blockchain/core.ts
624
+ var ETHEREUM_CHAINS = {
625
+ ethereum_mainnet: true,
626
+ ethereum_sepolia: true
627
+ };
628
+ var EthereumChain = (value) => {
629
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value)) {
630
+ throw new ValidationError(`Unsupported Ethereum chain: "${value}"`);
631
+ }
632
+ return value;
633
+ };
634
+ var SOLANA_CHAINS = {
635
+ solana_mainnet: true,
636
+ solana_devnet: true
637
+ };
638
+ var Chain = (value) => {
639
+ if (!Object.keys(ETHEREUM_CHAINS).includes(value) && !Object.keys(SOLANA_CHAINS).includes(value)) {
640
+ throw new ValidationError(`Unsupported chain: "${value}"`);
641
+ }
642
+ return value;
643
+ };
644
+ var EvmWalletAddress = (value) => value;
645
+ var EvmContractAddress = (value) => value;
646
+ var HexEncodedTransactionData = (value) => value;
647
+ var MAX_ASSET_DECIMALS = 77;
648
+ var AssetDecimals = (value) => {
649
+ if (!Number.isInteger(value)) {
650
+ throw new ValidationError(`Asset decimals must be an integer: ${value}`);
651
+ }
652
+ if (value < 0 || value > MAX_ASSET_DECIMALS) {
653
+ throw new ValidationError(
654
+ `Asset decimals out of range [0, ${MAX_ASSET_DECIMALS}]: ${value}`
655
+ );
656
+ }
657
+ return value;
658
+ };
659
+ var STABLE_DECIMALS = AssetDecimals(6);
660
+ var DecimalString = (value) => value;
661
+ var MAX_UINT_256 = 2n ** 256n - 1n;
662
+ var assertUint256 = (value) => {
663
+ if (value < 0n || value > MAX_UINT_256) {
664
+ throw new Error(`Value out of uint256 bounds: ${value}`);
665
+ }
666
+ return value;
667
+ };
668
+ var BlockchainAmount = Object.assign(
669
+ (value) => value,
670
+ {
671
+ add: (a, b) => combineAmounts(a, b, (x, y) => x + y),
672
+ sub: (a, b) => combineAmounts(a, b, (x, y) => x - y)
673
+ }
674
+ );
675
+ function combineAmounts(a, b, op) {
676
+ if (a.decimals !== b.decimals) {
677
+ throw new Error(
678
+ `Cannot combine BlockchainAmounts with different decimals: ${a.decimals} vs ${b.decimals}`
679
+ );
680
+ }
681
+ const raw = op(a.raw, b.raw);
682
+ if (raw < 0n || raw > MAX_UINT_256) {
683
+ throw new Error(`BlockchainAmount out of uint256 bounds: ${raw}`);
684
+ }
685
+ return BlockchainAmount({ raw, decimals: a.decimals });
686
+ }
687
+ var AssetSymbol = (value) => value;
688
+
529
689
  // src/shared/types/offer-detail.ts
530
690
  var OfferOptionId = (value) => value;
531
691
  var OfferOptionSlug = (value) => value;
@@ -549,6 +709,9 @@ var OfferDetail = {
549
709
  if (!Array.isArray(dto.milestones)) {
550
710
  throw new Error(`milestones must be an array`);
551
711
  }
712
+ if (!Array.isArray(dto.tokens)) {
713
+ throw new Error(`tokens must be an array`);
714
+ }
552
715
  return {
553
716
  id: OfferId(dto.id),
554
717
  slug: OfferSlug(dto.slug),
@@ -556,6 +719,7 @@ var OfferDetail = {
556
719
  name: dto.name,
557
720
  asset: Asset.fromDto(dto.asset),
558
721
  fundingAssets: dto.funding_assets.map(Asset.fromDto),
722
+ tokens: dto.tokens.map(OfferToken.fromDto),
559
723
  about: notBlankStringOrNull(dto.about),
560
724
  tagline: dto.tagline,
561
725
  bannerUrl: dto.banner_url,
@@ -608,6 +772,38 @@ var Milestone = {
608
772
  status: dto.status
609
773
  })
610
774
  };
775
+ var OfferToken = {
776
+ fromDto: (dto) => ({
777
+ role: dto.role,
778
+ chain: Chain(dto.chain),
779
+ address: EvmContractAddress(dto.address)
780
+ })
781
+ };
782
+
783
+ // src/shared/types/pagination.ts
784
+ var Cursor = (value) => value;
785
+ var PaginatedResponse = {
786
+ fromDto: (dto, itemMapper) => ({
787
+ data: dto.data.map(itemMapper),
788
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
789
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
790
+ })
791
+ };
792
+ var PaginationParams = {
793
+ toQueryParams: (params) => {
794
+ const queryParams = {};
795
+ if (params.after) {
796
+ queryParams.starting_after = params.after;
797
+ }
798
+ if (params.before) {
799
+ queryParams.starting_before = params.before;
800
+ }
801
+ if (params.limit) {
802
+ queryParams.limit = params.limit;
803
+ }
804
+ return queryParams;
805
+ }
806
+ };
611
807
 
612
808
  // src/shared/api/frontline/offers.ts
613
809
  async function fetchOffers(api, clientCreds) {
@@ -638,51 +834,32 @@ async function fetchOfferDetails(api, id, clientCreds) {
638
834
  return OfferDetail.fromDto(dto);
639
835
  }
640
836
 
641
- // src/shared/types/pii.ts
642
- var Iso2CountryCode = (value) => value;
643
- var PiiJurisdiction = {
837
+ // src/server/core/server-offers-namespace.ts
838
+ var ServerOffersNamespaceImpl = class {
839
+ constructor(ctx) {
840
+ this.ctx = ctx;
841
+ }
842
+ async list(clientCreds) {
843
+ await this.ctx.ensureAuthenticated(clientCreds);
844
+ return fetchOffers(this.ctx.api, clientCreds);
845
+ }
846
+ async listPage(params, clientCreds) {
847
+ await this.ctx.ensureAuthenticated(clientCreds);
848
+ return fetchOffersPage(this.ctx.api, params, clientCreds);
849
+ }
850
+ async get(id, clientCreds) {
851
+ await this.ctx.ensureAuthenticated(clientCreds);
852
+ return fetchOfferDetails(this.ctx.api, id, clientCreds);
853
+ }
854
+ };
855
+
856
+ // src/shared/types/requirement.ts
857
+ var RequirementId = (value) => value;
858
+ var Requirement = {
644
859
  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
- })
667
- };
668
-
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
- // src/shared/types/requirement.ts
680
- var RequirementId = (value) => value;
681
- var Requirement = {
682
- fromDto: (dto) => ({
683
- id: RequirementId(dto.id),
684
- type: dto.type,
685
- details: dto.details
860
+ id: RequirementId(dto.id),
861
+ type: dto.type,
862
+ details: dto.details
686
863
  })
687
864
  };
688
865
  var RequirementStatusInfo = {
@@ -723,138 +900,143 @@ async function fetchRequirementStatuses(api, offerId) {
723
900
  return RequirementStatusInfo.fromStatusesDto(response);
724
901
  }
725
902
 
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. */
763
- 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
778
- })
779
- };
780
-
781
- // src/shared/types/wallet-ownership-challenge.ts
782
- var WalletOwnershipChallenge = {
783
- /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
903
+ // src/shared/types/document-submission.ts
904
+ var DocumentSubmission = {
784
905
  fromDto: (dto) => ({
785
- message: dto.message,
786
- expiresAt: new Date(dto.expires_at)
906
+ status: dto.status,
907
+ formType: dto.form_type
787
908
  })
788
909
  };
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
910
 
820
- // src/shared/api/frontline/wallet-connect.ts
821
- async function createWalletOwnershipChallenge(api, params) {
911
+ // src/shared/api/frontline/documents.ts
912
+ async function submitDocument(api, documentType, fields) {
822
913
  const dto = await api.send({
823
914
  method: "POST",
824
- url: "/v1/wallet-ownership",
825
- body: CreateWalletOwnershipChallengeParams.toDto(params),
915
+ url: `/v1/documents/${documentType}/submission`,
916
+ body: fields,
826
917
  attributes: Attributes.protected()
827
918
  });
828
- return WalletOwnershipChallenge.fromDto(dto);
919
+ return DocumentSubmission.fromDto(dto);
829
920
  }
830
- async function connectExternalWallet(api, offerId, params) {
921
+
922
+ // src/shared/types/kyc.ts
923
+ var KycToken = {
924
+ fromDto: (dto) => ({
925
+ token: dto.token
926
+ })
927
+ };
928
+
929
+ // src/shared/api/frontline/kyc.ts
930
+ async function createKycToken(api, levelName, reset) {
831
931
  const dto = await api.send({
832
932
  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 },
933
+ url: "/v1/kyc-token",
934
+ body: {
935
+ ...levelName === void 0 ? {} : { level_name: levelName },
936
+ ...reset === void 0 ? {} : { reset }
937
+ },
844
938
  attributes: Attributes.protected()
845
939
  });
846
- return data.map(OfferOptionAddress.fromDto);
940
+ return KycToken.fromDto(dto);
847
941
  }
848
- async function removeOptionAddress(api, offerId, addressId) {
942
+
943
+ // src/shared/types/pii.ts
944
+ var Iso2CountryCode = (value) => value;
945
+ var PiiJurisdiction = {
946
+ fromDto: (dto) => ({
947
+ iso2: Iso2CountryCode(dto.iso_2),
948
+ name: dto.name
949
+ })
950
+ };
951
+ var PiiAddress = {
952
+ fromDto: (dto) => ({
953
+ street: dto.street,
954
+ city: dto.city,
955
+ state: dto.state,
956
+ postalCode: dto.postal_code,
957
+ country: dto.country
958
+ })
959
+ };
960
+ var Pii = {
961
+ fromDto: (dto) => ({
962
+ kind: dto.kind,
963
+ fullLegalName: dto.full_legal_name,
964
+ dateOfBirth: dto.date_of_birth,
965
+ jurisdiction: dto.jurisdiction ? PiiJurisdiction.fromDto(dto.jurisdiction) : null,
966
+ taxId: dto.tax_id,
967
+ permanentAddress: PiiAddress.fromDto(dto.permanent_address)
968
+ })
969
+ };
970
+
971
+ // src/shared/api/frontline/pii.ts
972
+ async function fetchPii(api) {
849
973
  const dto = await api.send({
850
- method: "DELETE",
851
- url: `/v1/offers/${offerId}/addresses/${addressId}`,
974
+ method: "GET",
975
+ url: "/v1/pii",
852
976
  attributes: Attributes.protected()
853
977
  });
854
- return OfferOptionAddress.fromDto(dto);
978
+ return Pii.fromDto(dto);
855
979
  }
856
980
 
857
- // src/shared/types/swap.ts
981
+ // src/shared/core/requirements/requirements-namespace.ts
982
+ var RequirementsNamespaceImpl = class {
983
+ constructor(ctx) {
984
+ this.ctx = ctx;
985
+ }
986
+ async forOffer(offerId) {
987
+ await this.ctx.ensureUserAuthenticated();
988
+ return fetchOfferRequirements(
989
+ this.ctx.api,
990
+ offerId,
991
+ void 0
992
+ );
993
+ }
994
+ async statuses(offerId) {
995
+ await this.ctx.ensureUserAuthenticated();
996
+ return fetchRequirementStatuses(this.ctx.api, offerId);
997
+ }
998
+ async createKycToken(params) {
999
+ await this.ctx.ensureUserAuthenticated();
1000
+ return createKycToken(
1001
+ this.ctx.api,
1002
+ params?.levelName,
1003
+ params?.reset
1004
+ );
1005
+ }
1006
+ async getPii() {
1007
+ await this.ctx.ensureUserAuthenticated();
1008
+ return fetchPii(this.ctx.api);
1009
+ }
1010
+ async submitDocument(params) {
1011
+ await this.ctx.ensureUserAuthenticated();
1012
+ return submitDocument(
1013
+ this.ctx.api,
1014
+ params.documentType,
1015
+ params.fields
1016
+ );
1017
+ }
1018
+ };
1019
+
1020
+ // src/server/core/server-requirements-namespace.ts
1021
+ var ServerRequirementsNamespaceImpl = class extends RequirementsNamespaceImpl {
1022
+ constructor(serverCtx) {
1023
+ super(serverCtx);
1024
+ this.serverCtx = serverCtx;
1025
+ }
1026
+ async forOffer(offerId, clientCreds) {
1027
+ await this.serverCtx.ensureAuthenticated(clientCreds);
1028
+ return fetchOfferRequirements(
1029
+ this.serverCtx.api,
1030
+ offerId,
1031
+ clientCreds
1032
+ );
1033
+ }
1034
+ };
1035
+
1036
+ // src/shared/api/nabu/config.ts
1037
+ var NABU_BASE_URL = "https://asset.coinlist.co";
1038
+
1039
+ // src/shared/types/providers/superstate/swap.ts
858
1040
  var SwapAuthorization = {
859
1041
  fromDto: (dto) => ({
860
1042
  authorized: dto.authorized
@@ -905,7 +1087,7 @@ var AllowWalletResponse = {
905
1087
  }
906
1088
  };
907
1089
 
908
- // src/shared/api/frontline/swap.ts
1090
+ // src/shared/api/frontline/providers/superstate/swap.ts
909
1091
  async function getSwapAuthorization(api, params) {
910
1092
  const dto = await api.send({
911
1093
  method: "GET",
@@ -1005,65 +1187,34 @@ function toErc20Asset(dto) {
1005
1187
  };
1006
1188
  }
1007
1189
 
1008
- // src/shared/core/erc20-namespace.ts
1190
+ // src/shared/core/blockchain/erc20/erc20-namespace.ts
1009
1191
  var Erc20NamespaceImpl = class {
1010
1192
  constructor(ctx) {
1011
1193
  this.ctx = ctx;
1012
1194
  }
1013
- async getTokenAllowance(params) {
1195
+ async getAllowance(params) {
1014
1196
  await this.ctx.ensureUserAuthenticated();
1015
1197
  return getTokenAllowance(this.ctx.api, params);
1016
1198
  }
1017
- async getTokenBalance(params) {
1199
+ async getBalance(params) {
1018
1200
  await this.ctx.ensureUserAuthenticated();
1019
1201
  return getTokenBalance(this.ctx.api, params);
1020
1202
  }
1021
1203
  };
1022
1204
 
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);
1047
- }
1048
- async allowWallet(params) {
1049
- await this.ctx.ensureUserAuthenticated();
1050
- return allowWallet(this.ctx.api, params);
1051
- }
1052
- };
1053
-
1054
- // src/shared/types/participation.ts
1055
- var ParticipationId = (value) => value;
1056
- var Blockchain = (value) => value;
1057
- var WalletAddress = (value) => value;
1058
- var ParticipationsPaginationParams = {
1059
- toQueryParams: (params) => {
1060
- const queryParams = PaginationParams.toQueryParams(params);
1061
- if (params.offerId) {
1062
- queryParams["filters[0][field]"] = "offer_id";
1063
- queryParams["filters[0][op]"] = "==";
1064
- queryParams["filters[0][value]"] = params.offerId;
1065
- }
1066
- return queryParams;
1205
+ // src/shared/types/providers/coin-list/token-sale.ts
1206
+ var ParticipationId = (value) => value;
1207
+ var Blockchain = (value) => value;
1208
+ var WalletAddress = (value) => value;
1209
+ var ParticipationsPaginationParams = {
1210
+ toQueryParams: (params) => {
1211
+ const queryParams = PaginationParams.toQueryParams(params);
1212
+ if (params.offerId) {
1213
+ queryParams["filters[0][field]"] = "offer_id";
1214
+ queryParams["filters[0][op]"] = "==";
1215
+ queryParams["filters[0][value]"] = params.offerId;
1216
+ }
1217
+ return queryParams;
1067
1218
  }
1068
1219
  };
1069
1220
  var Participation = {
@@ -1098,7 +1249,7 @@ var CreateParticipationParams = {
1098
1249
  })
1099
1250
  };
1100
1251
 
1101
- // src/shared/api/frontline/participations.ts
1252
+ // src/shared/api/frontline/providers/coin-list/token-sale.ts
1102
1253
  async function fetchParticipations(api, offerId) {
1103
1254
  return fetchAllPages(
1104
1255
  (params) => fetchParticipationsPage(api, params),
@@ -1132,20 +1283,20 @@ async function createParticipation(api, params) {
1132
1283
  return Participation.fromDto(dto);
1133
1284
  }
1134
1285
 
1135
- // src/shared/core/token-sale-namespace.ts
1136
- var TokenSaleNamespaceImpl = class {
1286
+ // src/shared/core/checkout/coin-list/token-sale-namespace.ts
1287
+ var CoinListTokenSaleNamespaceImpl = class {
1137
1288
  constructor(ctx) {
1138
1289
  this.ctx = ctx;
1139
1290
  }
1140
- async fetchParticipations(offerId) {
1291
+ async list(offerId) {
1141
1292
  await this.ctx.ensureUserAuthenticated();
1142
1293
  return fetchParticipations(this.ctx.api, offerId);
1143
1294
  }
1144
- async fetchParticipationsPage(params) {
1295
+ async listPage(params) {
1145
1296
  await this.ctx.ensureUserAuthenticated();
1146
1297
  return fetchParticipationsPage(this.ctx.api, params);
1147
1298
  }
1148
- async fetchParticipation(id) {
1299
+ async get(id) {
1149
1300
  await this.ctx.ensureUserAuthenticated();
1150
1301
  return fetchParticipation(this.ctx.api, id);
1151
1302
  }
@@ -1155,237 +1306,603 @@ var TokenSaleNamespaceImpl = class {
1155
1306
  }
1156
1307
  };
1157
1308
 
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
- }
1309
+ // src/shared/core/blockchain/formatters.ts
1310
+ var import_viem = require("viem");
1311
+
1312
+ // src/shared/types/blockchain/ui.ts
1313
+ var FormattedAmountAssetUi = (value) => value;
1314
+
1315
+ // src/shared/core/blockchain/formatters.ts
1316
+ function formatRawAmount(amount) {
1317
+ return (0, import_viem.formatUnits)(amount.raw, amount.decimals);
1318
+ }
1319
+ var NA_AMOUNT_ASSET_UI = FormattedAmountAssetUi("-");
1320
+ var USD_FRACTION_DIGITS = AssetDecimals(2);
1321
+
1322
+ // src/shared/core/blockchain/chain.ts
1323
+ var CHAIN_IDS = {
1324
+ ethereum_mainnet: 1,
1325
+ ethereum_sepolia: 11155111
1164
1326
  };
1327
+ function chainFromId(chainId) {
1328
+ const chains = Object.keys(CHAIN_IDS);
1329
+ const chain = chains.find((c) => String(CHAIN_IDS[c]) === chainId);
1330
+ if (!chain) {
1331
+ throw new ValidationError(`Unsupported EIP-155 chain id: "${chainId}"`);
1332
+ }
1333
+ return chain;
1334
+ }
1165
1335
 
1166
- // src/shared/types/oauth-session.ts
1167
- var ClientCredentialsOAuth = (value) => value;
1168
- var OAuthRefreshToken = (value) => value;
1169
- var OAuthSession = {
1336
+ // src/shared/core/blockchain/math.ts
1337
+ var import_viem2 = require("viem");
1338
+ function blockchainAmountFromRawOrThrow({
1339
+ label,
1340
+ raw,
1341
+ decimals
1342
+ }) {
1343
+ const trimmed = raw.trim();
1344
+ if (trimmed === "") {
1345
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1346
+ }
1347
+ let value;
1348
+ try {
1349
+ value = BigInt(trimmed);
1350
+ } catch {
1351
+ throw new ValidationError(`${label}: not a uint256 integer ("${raw}")`);
1352
+ }
1353
+ try {
1354
+ return BlockchainAmount({ raw: assertUint256(value), decimals });
1355
+ } catch {
1356
+ throw new ValidationError(`${label}: out of uint256 bounds (${value})`);
1357
+ }
1358
+ }
1359
+
1360
+ // src/shared/types/trading.ts
1361
+ var Ticker = (value) => value;
1362
+
1363
+ // src/shared/types/providers/ondo/ondo.ts
1364
+ var OndoTradingStatus = {
1170
1365
  fromDto: (dto) => {
1171
- const expiresAt = new Date(Date.now() + dto.expires_in * 1e3);
1366
+ if (!dto.tradable) return { type: "not-tradable", side: dto.side };
1172
1367
  return {
1173
- accessToken: {
1174
- value: dto.access_token,
1175
- expiresAt
1368
+ type: "tradable",
1369
+ side: dto.side,
1370
+ grossMaxTokens: decimalOrNull(dto.gross_max_tokens),
1371
+ grossMaxNotionalValue: decimalOrNull(dto.gross_max_notional_value),
1372
+ grossMaxActiveNotionalValue: decimalOrNull(
1373
+ dto.gross_max_active_notional_value
1374
+ )
1375
+ };
1376
+ }
1377
+ };
1378
+ var decimalOrNull = (value) => value === null ? null : DecimalString(value);
1379
+ var OndoQuote = {
1380
+ fromDto: (dto) => {
1381
+ const assetDecimals = AssetDecimals(dto.asset_decimals);
1382
+ return {
1383
+ chain: chainFromId(dto.chain_id),
1384
+ ticker: Ticker(dto.ticker),
1385
+ assetAddress: EvmContractAddress(dto.asset_address),
1386
+ asset: {
1387
+ name: dto.ticker,
1388
+ symbol: AssetSymbol(dto.symbol),
1389
+ decimals: assetDecimals
1176
1390
  },
1177
- ...dto.refresh_token != null && dto.refresh_token !== "" ? { refreshToken: OAuthRefreshToken(dto.refresh_token) } : void 0
1391
+ side: dto.side,
1392
+ tokenBaseUnits: blockchainAmountFromRawOrThrow({
1393
+ label: "tokenBaseUnits",
1394
+ raw: dto.token_base_units,
1395
+ decimals: assetDecimals
1396
+ }),
1397
+ price: DecimalString(dto.price)
1178
1398
  };
1179
1399
  }
1180
1400
  };
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
1401
+ var OndoSwapTransaction = {
1402
+ fromDto: (dto) => {
1403
+ const inputDecimals = AssetDecimals(dto.pay_input_decimals);
1404
+ const outputDecimals = AssetDecimals(dto.receive_output_decimals);
1405
+ return {
1406
+ tx: {
1407
+ to: EvmContractAddress(dto.to),
1408
+ data: HexEncodedTransactionData(dto.data)
1194
1409
  },
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()
1410
+ expiresAt: parseExpiresAt(dto.expires_at),
1411
+ payInputAmount: blockchainAmountFromRawOrThrow({
1412
+ label: "pay_input_amount",
1413
+ raw: dto.pay_input_amount,
1414
+ decimals: inputDecimals
1415
+ }),
1416
+ fee: blockchainAmountFromRawOrThrow({
1417
+ label: "fee",
1418
+ raw: dto.fee,
1419
+ decimals: inputDecimals
1420
+ }),
1421
+ notionalValue: blockchainAmountFromRawOrThrow({
1422
+ label: "notional_value",
1423
+ raw: dto.notional_value,
1424
+ decimals: inputDecimals
1425
+ }),
1426
+ receiveOutputAmount: parseReceiveOutputAmount(
1427
+ dto.receive_output_amount,
1428
+ outputDecimals
1429
+ )
1204
1430
  };
1205
- this.erc20 = new Erc20NamespaceImpl(ctx);
1206
- this.tokenSale = new TokenSaleNamespaceImpl(ctx);
1207
- this.swap = new SwapNamespaceImpl(ctx);
1208
1431
  }
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();
1214
- }
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
- }
1226
- });
1227
- const session = OAuthSession.fromDto(sessionDto);
1228
- await setSession(session);
1229
- return session;
1432
+ };
1433
+ function parseReceiveOutputAmount(raw, decimals) {
1434
+ const amount = blockchainAmountFromRawOrThrow({
1435
+ label: "receive_output_amount",
1436
+ raw,
1437
+ decimals
1438
+ });
1439
+ if (amount.raw <= 0n) {
1440
+ throw new ValidationError(
1441
+ `receive_output_amount: must be greater than zero ("${raw}")`
1442
+ );
1230
1443
  }
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
- }
1240
- });
1241
- const session = OAuthSession.fromDto(sessionDto);
1242
- return ClientCredentialsOAuth(session.accessToken);
1444
+ return amount;
1445
+ }
1446
+ function parseExpiresAt(value) {
1447
+ const date = new Date(value);
1448
+ if (Number.isNaN(date.getTime())) {
1449
+ throw new ValidationError(`expires_at: not a date ("${value}")`);
1243
1450
  }
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
- }
1451
+ return date;
1452
+ }
1453
+
1454
+ // src/shared/api/frontline/providers/ondo/ondo.ts
1455
+ async function getOndoTradingStatus(api, params) {
1456
+ const dto = await api.send({
1457
+ method: "GET",
1458
+ url: "/v1/ondo/swap/trading-status",
1459
+ queryParams: { symbol: params.symbol, side: params.side },
1460
+ attributes: Attributes.protected()
1461
+ });
1462
+ return OndoTradingStatus.fromDto(dto);
1463
+ }
1464
+ async function getOndoQuote(api, params) {
1465
+ const dto = await api.send({
1466
+ method: "GET",
1467
+ url: "/v1/ondo/swap/quote",
1468
+ queryParams: {
1469
+ symbol: params.symbol,
1470
+ side: params.side,
1471
+ duration: params.duration,
1472
+ ...sizeParam(params)
1473
+ },
1474
+ attributes: Attributes.protected()
1475
+ });
1476
+ return OndoQuote.fromDto(dto);
1477
+ }
1478
+ async function buildOndoSwapTransaction(api, params) {
1479
+ const dto = await api.send({
1480
+ method: "POST",
1481
+ url: "/v1/ondo/swap/transaction",
1482
+ body: {
1483
+ symbol: params.symbol,
1484
+ chain: params.chain,
1485
+ wallet_address: params.walletAddress,
1486
+ amount: params.amount.raw.toString()
1487
+ },
1488
+ attributes: Attributes.protected()
1489
+ });
1490
+ assertFundingScaleAgrees(dto, params);
1491
+ return OndoSwapTransaction.fromDto(dto);
1492
+ }
1493
+ function assertFundingScaleAgrees(dto, params) {
1494
+ if (dto.pay_input_decimals !== params.amount.decimals) {
1495
+ throw new ValidationError(
1496
+ `pay_input_decimals: the swap was priced in ${dto.pay_input_decimals} decimals but the order was sized in ${params.amount.decimals}`
1497
+ );
1260
1498
  }
1261
- async refreshSession(refreshToken, setSession) {
1262
- if (!refreshToken) {
1263
- await setSession(null);
1264
- return null;
1499
+ }
1500
+ function sizeParam(params) {
1501
+ const tokenAmount = "tokenAmount" in params ? params.tokenAmount : void 0;
1502
+ const notionalValue = "notionalValue" in params ? params.notionalValue : void 0;
1503
+ if (tokenAmount !== void 0) {
1504
+ if (notionalValue !== void 0) {
1505
+ throw new ValidationError(
1506
+ "An Ondo quote takes tokenAmount or notionalValue, not both"
1507
+ );
1265
1508
  }
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);
1509
+ return { token_amount: formatRawAmount(tokenAmount) };
1510
+ }
1511
+ if (notionalValue === void 0) {
1512
+ throw new ValidationError(
1513
+ "An Ondo quote must be sized by tokenAmount or notionalValue"
1514
+ );
1515
+ }
1516
+ return { notional_value: notionalValue };
1517
+ }
1518
+
1519
+ // src/shared/core/checkout/ondo/ondo-namespace.ts
1520
+ var OndoNamespaceImpl = class {
1521
+ constructor(ctx) {
1522
+ this.ctx = ctx;
1523
+ }
1524
+ async getTradingStatus(params) {
1525
+ await this.ctx.ensureUserAuthenticated();
1526
+ return getOndoTradingStatus(this.ctx.api, params);
1527
+ }
1528
+ async getQuote(params) {
1529
+ await this.ctx.ensureUserAuthenticated();
1530
+ return getOndoQuote(this.ctx.api, params);
1531
+ }
1532
+ async buildSwapTransaction(params) {
1533
+ await this.ctx.ensureUserAuthenticated();
1534
+ return buildOndoSwapTransaction(this.ctx.api, params);
1535
+ }
1536
+ };
1537
+
1538
+ // src/shared/core/checkout/superstate/swap-namespace.ts
1539
+ var SuperstateSwapNamespaceImpl = class {
1540
+ constructor(ctx) {
1541
+ this.ctx = ctx;
1542
+ }
1543
+ async getAuthorization(params) {
1544
+ await this.ctx.ensureUserAuthenticated();
1545
+ return getSwapAuthorization(this.ctx.api, params);
1546
+ }
1547
+ async getPreview(params) {
1548
+ await this.ctx.ensureUserAuthenticated();
1549
+ return getSwapPreview(this.ctx.api, params);
1550
+ }
1551
+ async getStatus(params) {
1552
+ await this.ctx.ensureUserAuthenticated();
1553
+ return getSwapStatus(this.ctx.api, params);
1554
+ }
1555
+ async getOutputToken(params) {
1556
+ await this.ctx.ensureUserAuthenticated();
1557
+ return getSwapOutputToken(this.ctx.api, params);
1558
+ }
1559
+ async allowWallet(params) {
1560
+ await this.ctx.ensureUserAuthenticated();
1561
+ return allowWallet(this.ctx.api, params);
1562
+ }
1563
+ };
1564
+
1565
+ // src/shared/api/nabu/tokens.ts
1566
+ var import_viem3 = require("viem");
1567
+
1568
+ // src/shared/types/token-metadata.ts
1569
+ var TokenLogoUrl = (value) => value;
1570
+ var TokenLogo = {
1571
+ /** `baseUrl` is the registry origin; registry URLs are root-relative. */
1572
+ fromDto: (dto, baseUrl) => dto.kind === "VECTOR" ? { kind: "VECTOR", url: resolveLogoUrl(dto.url, baseUrl) } : {
1573
+ kind: "RASTER",
1574
+ original: logoImageFromDto(dto.original, baseUrl),
1575
+ variants: dto.variants.map((v) => logoImageFromDto(v, baseUrl))
1576
+ }
1577
+ };
1578
+ var TokenMetadata = {
1579
+ /** `baseUrl` is the registry origin; registry logo URLs are root-relative. */
1580
+ fromDto: (dto, baseUrl) => {
1581
+ assertSupportedSchemaVersion(dto.schema_version);
1582
+ return {
1583
+ identifier: {
1584
+ chain: EthereumChain(dto.chain),
1585
+ address: EvmContractAddress(dto.address)
1586
+ },
1587
+ name: dto.name,
1588
+ symbol: AssetSymbol(dto.symbol),
1589
+ decimals: AssetDecimals(dto.decimals),
1590
+ logo: TokenLogo.fromDto(dto.logo, baseUrl),
1591
+ logoDark: dto.logo_dark === void 0 ? null : TokenLogo.fromDto(dto.logo_dark, baseUrl)
1592
+ };
1593
+ },
1594
+ /**
1595
+ * Maps a chain snapshot to the tokens it lists, skipping the chain's native
1596
+ * coin (`kind: 'COIN'`, no contract address).
1597
+ */
1598
+ fromChainAssetsDto: (dto, baseUrl) => {
1599
+ assertSupportedSchemaVersion(dto.schema_version);
1600
+ const chain = EthereumChain(dto.chain);
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
+ }));
1613
+ }
1614
+ };
1615
+ function assertSupportedSchemaVersion(version) {
1616
+ if (version !== 1) {
1617
+ throw new ValidationError(
1618
+ `Unsupported token registry schema_version: ${version}`
1619
+ );
1620
+ }
1621
+ }
1622
+ var logoImageFromDto = (dto, baseUrl) => ({
1623
+ url: resolveLogoUrl(dto.url, baseUrl),
1624
+ width: dto.width,
1625
+ height: dto.height
1626
+ });
1627
+ var resolveLogoUrl = (url, baseUrl) => TokenLogoUrl(
1628
+ url.startsWith("http") ? url : `${baseUrl.replace(/\/$/, "")}${url}`
1629
+ );
1630
+
1631
+ // src/shared/api/nabu/tokens.ts
1632
+ function createNabuApiClient(baseUrl) {
1633
+ return new HttpClient({ baseUrl });
1634
+ }
1635
+ async function fetchTokenMetadata(client, token) {
1636
+ const address = checksummed(token.address);
1637
+ let response;
1638
+ try {
1639
+ response = await client.send({
1640
+ method: "GET",
1641
+ url: `/${token.chain}/token/${address}`
1642
+ });
1643
+ } catch (error) {
1644
+ if (isRegistryHtmlFallback(error)) {
1282
1645
  return null;
1283
1646
  }
1647
+ throw error;
1284
1648
  }
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;
1294
- 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
- }
1312
- }
1313
- await setSession(null);
1649
+ if (response.status === 404) {
1650
+ return null;
1651
+ }
1652
+ assertOk(response);
1653
+ if (response.body === null) {
1654
+ throw new ValidationError(
1655
+ `Token registry returned an empty body for token "${address}" on "${token.chain}"`
1656
+ );
1657
+ }
1658
+ return TokenMetadata.fromDto(response.body, client.config.baseUrl);
1659
+ }
1660
+ async function fetchTokensMetadata(client, chain) {
1661
+ let response;
1662
+ try {
1663
+ response = await client.send({
1664
+ method: "GET",
1665
+ url: `/${chain}/assets.json`
1666
+ });
1667
+ } catch (error) {
1668
+ if (isRegistryHtmlFallback(error)) {
1669
+ throw new ValidationError(
1670
+ `Token registry returned non-JSON for the "${chain}" snapshot`
1671
+ );
1314
1672
  }
1673
+ throw error;
1315
1674
  }
1316
- async fetchOffers(clientCreds) {
1317
- await this.ensureAuthenticated(clientCreds);
1318
- return fetchOffers(this.api, clientCreds);
1675
+ assertOk(response);
1676
+ if (response.body === null) {
1677
+ throw new ValidationError(
1678
+ `Token registry returned an empty "${chain}" snapshot`
1679
+ );
1319
1680
  }
1320
- async fetchOffersPage(params, clientCreds) {
1321
- await this.ensureAuthenticated(clientCreds);
1322
- return fetchOffersPage(this.api, params, clientCreds);
1681
+ return TokenMetadata.fromChainAssetsDto(response.body, client.config.baseUrl);
1682
+ }
1683
+ function isRegistryHtmlFallback(error) {
1684
+ return error instanceof HttpError && error.response.status >= 200 && error.response.status < 300;
1685
+ }
1686
+ function assertOk(response) {
1687
+ if (response.status < 200 || response.status >= 300) {
1688
+ throw new HttpError(response);
1323
1689
  }
1324
- async fetchOfferDetails(id, clientCreds) {
1325
- await this.ensureAuthenticated(clientCreds);
1326
- return fetchOfferDetails(this.api, id, clientCreds);
1690
+ }
1691
+ function checksummed(address) {
1692
+ try {
1693
+ return (0, import_viem3.getAddress)(address);
1694
+ } catch (_) {
1695
+ throw new ValidationError(`Invalid EVM contract address: "${address}"`);
1327
1696
  }
1328
- async createWalletOwnershipChallenge(params) {
1329
- await this.ensureUserAuthenticated();
1330
- return createWalletOwnershipChallenge(this.api, params);
1697
+ }
1698
+
1699
+ // src/shared/core/tokens/tokens-namespace.ts
1700
+ var TokensNamespaceImpl = class {
1701
+ /**
1702
+ * Takes the registry origin rather than a `SharedNamespaceContext`: the
1703
+ * registry is unauthenticated and on its own host, so the frontline sender
1704
+ * and the auth check would both be dead weight here.
1705
+ */
1706
+ constructor(baseUrl) {
1707
+ this.api = createNabuApiClient(baseUrl);
1331
1708
  }
1332
- async connectExternalWallet(offerId, params) {
1333
- await this.ensureUserAuthenticated();
1334
- return connectExternalWallet(this.api, offerId, params);
1709
+ get(token) {
1710
+ return fetchTokenMetadata(this.api, token);
1335
1711
  }
1336
- async listOptionAddresses(offerId, offerOptionId) {
1337
- await this.ensureUserAuthenticated();
1338
- return listOptionAddresses(
1339
- this.api,
1340
- offerId,
1341
- offerOptionId
1712
+ list(chain) {
1713
+ return fetchTokensMetadata(this.api, chain);
1714
+ }
1715
+ };
1716
+
1717
+ // src/shared/types/offer-option-address.ts
1718
+ var OfferOptionAddressId = (value) => value;
1719
+ var OfferOptionAddress = {
1720
+ /** Maps the API DTO into the SDK offer-option-address domain model. */
1721
+ fromDto: (dto) => ({
1722
+ id: OfferOptionAddressId(dto.id),
1723
+ offerOptionId: OfferOptionId(dto.offer_option_id),
1724
+ address: EvmWalletAddress(dto.address),
1725
+ protocol: dto.protocol,
1726
+ createdAt: new Date(dto.created_at)
1727
+ })
1728
+ };
1729
+ var ConnectExternalWalletParams = {
1730
+ /** Maps connect-wallet params into the API DTO payload. */
1731
+ toDto: (params) => ({
1732
+ offer_option_id: params.offerOptionId,
1733
+ wallet_address: params.walletAddress,
1734
+ chain: params.chain,
1735
+ signature: params.signature
1736
+ })
1737
+ };
1738
+
1739
+ // src/shared/types/wallet-ownership-challenge.ts
1740
+ var WalletOwnershipChallenge = {
1741
+ /** Maps the API DTO into the SDK wallet-ownership-challenge domain model. */
1742
+ fromDto: (dto) => ({
1743
+ message: dto.message,
1744
+ expiresAt: new Date(dto.expires_at)
1745
+ })
1746
+ };
1747
+ var CreateWalletOwnershipChallengeParams = {
1748
+ /**
1749
+ * Maps challenge-request params into the API DTO payload. The discriminated
1750
+ * union guarantees SIWE fields are present exactly when `challengeType` is
1751
+ * `siwe`, so the mapping narrows on the discriminant.
1752
+ */
1753
+ toDto: (params) => {
1754
+ switch (params.challengeType) {
1755
+ case "plain":
1756
+ return {
1757
+ wallet_address: params.walletAddress,
1758
+ chain: params.chain,
1759
+ challenge_type: "plain"
1760
+ };
1761
+ case "siwe":
1762
+ return {
1763
+ wallet_address: params.walletAddress,
1764
+ chain: params.chain,
1765
+ challenge_type: "siwe",
1766
+ domain: params.domain,
1767
+ uri: params.uri,
1768
+ statement: params.statement
1769
+ };
1770
+ default: {
1771
+ const _exhaustive = params;
1772
+ return _exhaustive;
1773
+ }
1774
+ }
1775
+ }
1776
+ };
1777
+
1778
+ // src/shared/api/frontline/wallet-connect.ts
1779
+ async function createWalletOwnershipChallenge(api, params) {
1780
+ const dto = await api.send({
1781
+ method: "POST",
1782
+ url: "/v1/wallet-ownership",
1783
+ body: CreateWalletOwnershipChallengeParams.toDto(params),
1784
+ attributes: Attributes.protected()
1785
+ });
1786
+ return WalletOwnershipChallenge.fromDto(dto);
1787
+ }
1788
+ async function connectExternalWallet(api, params) {
1789
+ const dto = await api.send({
1790
+ method: "POST",
1791
+ url: `/v1/offers/${params.offerId}/addresses`,
1792
+ body: ConnectExternalWalletParams.toDto(params),
1793
+ attributes: Attributes.protected()
1794
+ });
1795
+ return OfferOptionAddress.fromDto(dto);
1796
+ }
1797
+ async function listOptionAddresses(api, offerId, offerOptionId) {
1798
+ const { data } = await api.send({
1799
+ method: "GET",
1800
+ url: `/v1/offers/${offerId}/addresses`,
1801
+ queryParams: { offer_option_id: offerOptionId },
1802
+ attributes: Attributes.protected()
1803
+ });
1804
+ return data.map(OfferOptionAddress.fromDto);
1805
+ }
1806
+ async function removeOptionAddress(api, offerId, addressId) {
1807
+ const dto = await api.send({
1808
+ method: "DELETE",
1809
+ url: `/v1/offers/${offerId}/addresses/${addressId}`,
1810
+ attributes: Attributes.protected()
1811
+ });
1812
+ return OfferOptionAddress.fromDto(dto);
1813
+ }
1814
+
1815
+ // src/shared/core/wallets/wallets-namespace.ts
1816
+ var WalletsNamespaceImpl = class {
1817
+ constructor(ctx) {
1818
+ this.ctx = ctx;
1819
+ }
1820
+ async createOwnershipChallenge(params) {
1821
+ await this.ctx.ensureUserAuthenticated();
1822
+ return createWalletOwnershipChallenge(
1823
+ this.ctx.api,
1824
+ params
1342
1825
  );
1343
1826
  }
1344
- async removeOptionAddress(offerId, addressId) {
1345
- await this.ensureUserAuthenticated();
1346
- return removeOptionAddress(this.api, offerId, addressId);
1827
+ async connectExternal(params) {
1828
+ await this.ctx.ensureUserAuthenticated();
1829
+ return connectExternalWallet(this.ctx.api, params);
1347
1830
  }
1348
- async fetchOfferRequirements(offerId, clientCreds) {
1349
- await this.ensureAuthenticated(clientCreds);
1350
- return fetchOfferRequirements(
1351
- this.api,
1352
- offerId,
1353
- clientCreds
1831
+ async list(params) {
1832
+ await this.ctx.ensureUserAuthenticated();
1833
+ return listOptionAddresses(
1834
+ this.ctx.api,
1835
+ params.offerId,
1836
+ params.offerOptionId
1354
1837
  );
1355
1838
  }
1356
- async fetchRequirementStatuses(offerId) {
1357
- await this.ensureUserAuthenticated();
1358
- return fetchRequirementStatuses(this.api, offerId);
1839
+ async remove(params) {
1840
+ await this.ctx.ensureUserAuthenticated();
1841
+ return removeOptionAddress(
1842
+ this.ctx.api,
1843
+ params.offerId,
1844
+ params.addressId
1845
+ );
1359
1846
  }
1360
- async ensureAuthenticated(clientCreds) {
1361
- if (!clientCreds) {
1362
- await this.ensureUserAuthenticated();
1363
- }
1847
+ };
1848
+
1849
+ // src/server/core/coinlist-server.ts
1850
+ var ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;
1851
+ var CoinListServerImpl = class {
1852
+ constructor(_config) {
1853
+ this._config = _config;
1854
+ this.api = new ApiClient(
1855
+ {
1856
+ baseUrl: _config.baseUrl ?? PUBLIC_API_BASE_URL,
1857
+ xApiVersion: API_VERSION
1858
+ },
1859
+ // When refresh=true the renewal middleware has received a 401 and wants a
1860
+ // fresh token. A read-only store cannot persist a new session, so return
1861
+ // null immediately — this tells the middleware to skip the retry rather
1862
+ // 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()
1864
+ );
1865
+ this.auth = new ServerAuthNamespaceImpl(this.api, {
1866
+ ..._config,
1867
+ accessTokenExpiryBufferSeconds: _config.accessTokenExpiryBufferSeconds ?? ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS,
1868
+ strict: _config.strict ?? false
1869
+ });
1870
+ const ctx = {
1871
+ api: this.api,
1872
+ ensureUserAuthenticated: () => this.ensureAuthenticated(void 0),
1873
+ ensureAuthenticated: (clientCreds) => this.ensureAuthenticated(clientCreds)
1874
+ };
1875
+ this.offers = new ServerOffersNamespaceImpl(ctx);
1876
+ this.requirements = new ServerRequirementsNamespaceImpl(ctx);
1877
+ this.wallets = new WalletsNamespaceImpl(ctx);
1878
+ this.erc20 = new Erc20NamespaceImpl(ctx);
1879
+ this.tokenSale = new CoinListTokenSaleNamespaceImpl(ctx);
1880
+ this.superstate = new SuperstateSwapNamespaceImpl(ctx);
1881
+ this.ondo = new OndoNamespaceImpl(ctx);
1882
+ this.tokens = new TokensNamespaceImpl(
1883
+ _config.tokensBaseUrl ?? NABU_BASE_URL
1884
+ );
1364
1885
  }
1365
- async ensureUserAuthenticated() {
1366
- const token = await this.accessToken();
1886
+ /**
1887
+ * An app-level token authenticates a request on its own; without one the
1888
+ * caller needs a user session.
1889
+ */
1890
+ async ensureAuthenticated(clientCreds) {
1891
+ if (clientCreds) return;
1892
+ const token = await this.auth.getAccessToken();
1367
1893
  if (token === null) {
1368
1894
  throw new NotAuthenticatedError();
1369
1895
  }
1370
1896
  }
1371
- async fetchPii() {
1372
- await this.ensureUserAuthenticated();
1373
- return fetchPii(this.api);
1374
- }
1375
- async submitDocument(documentType, fields) {
1376
- await this.ensureUserAuthenticated();
1377
- return submitDocument(this.api, documentType, fields);
1378
- }
1379
- async createKycToken(levelName, reset) {
1380
- await this.ensureUserAuthenticated();
1381
- return createKycToken(this.api, levelName, reset);
1382
- }
1383
1897
  };
1384
1898
  function createCoinListServer(config) {
1385
1899
  return new CoinListServerImpl(config);
1386
1900
  }
1387
1901
  // Annotate the CommonJS export names for ESM import in node:
1388
1902
  0 && (module.exports = {
1903
+ ServerAuthNamespaceImpl,
1904
+ ServerOffersNamespaceImpl,
1905
+ ServerRequirementsNamespaceImpl,
1389
1906
  WritableSessionStoreRequiredError,
1390
1907
  createCoinListServer
1391
1908
  });