@coinlist-co/react 0.0.2 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/{chunk-S56KGI3U.js → chunk-6CG7JT7Q.js} +255 -45
  2. package/dist/chunk-6CG7JT7Q.js.map +1 -0
  3. package/dist/chunk-DLEKT4T4.js +118 -0
  4. package/dist/chunk-DLEKT4T4.js.map +1 -0
  5. package/dist/{chunk-W6ZBUBLA.js → chunk-GRVV7NLV.js} +33 -4
  6. package/dist/chunk-GRVV7NLV.js.map +1 -0
  7. package/dist/chunk-WFA6X7E2.js +76 -0
  8. package/dist/chunk-WFA6X7E2.js.map +1 -0
  9. package/dist/client/components/index.cjs +188 -2
  10. package/dist/client/components/index.cjs.map +1 -1
  11. package/dist/client/components/index.d.cts +41 -1
  12. package/dist/client/components/index.d.ts +41 -1
  13. package/dist/client/components/index.js +149 -4
  14. package/dist/client/components/index.js.map +1 -1
  15. package/dist/client/core/index.cjs +259 -6
  16. package/dist/client/core/index.cjs.map +1 -1
  17. package/dist/client/core/index.d.cts +4 -3
  18. package/dist/client/core/index.d.ts +4 -3
  19. package/dist/client/core/index.js +34 -4
  20. package/dist/client/hooks/index.cjs +136 -2
  21. package/dist/client/hooks/index.cjs.map +1 -1
  22. package/dist/client/hooks/index.d.cts +52 -11
  23. package/dist/client/hooks/index.d.ts +52 -11
  24. package/dist/client/hooks/index.js +13 -5
  25. package/dist/client/index.cjs +315 -6
  26. package/dist/client/index.cjs.map +1 -1
  27. package/dist/client/index.d.cts +6 -4
  28. package/dist/client/index.d.ts +6 -4
  29. package/dist/client/index.js +38 -6
  30. package/dist/client/styles.css +1 -1
  31. package/dist/coinlist-client-BiA8a2yU.d.ts +272 -0
  32. package/dist/coinlist-client-DXKFDGhP.d.cts +272 -0
  33. package/dist/newtype-yKTvFdg_.d.cts +6 -0
  34. package/dist/newtype-yKTvFdg_.d.ts +6 -0
  35. package/dist/{oauth-session-g0OPJNKn.d.ts → oauth-session-DgItaMKN.d.cts} +2 -5
  36. package/dist/{oauth-session-g0OPJNKn.d.cts → oauth-session-DnKDI5ou.d.ts} +2 -5
  37. package/dist/offer-D6p_Ijme.d.cts +30 -0
  38. package/dist/offer-DnFEFJw9.d.ts +30 -0
  39. package/dist/server/index.cjs +30 -1
  40. package/dist/server/index.cjs.map +1 -1
  41. package/dist/server/index.d.cts +3 -2
  42. package/dist/server/index.d.ts +3 -2
  43. package/dist/server/index.js +1 -1
  44. package/dist/useCompleteCoinListOAuth-6Z4DGuiH.d.cts +55 -0
  45. package/dist/useCompleteCoinListOAuth-C3G1Vsf8.d.ts +55 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-CGIPLHD3.js +0 -63
  48. package/dist/chunk-CGIPLHD3.js.map +0 -1
  49. package/dist/chunk-S56KGI3U.js.map +0 -1
  50. package/dist/chunk-W6ZBUBLA.js.map +0 -1
  51. package/dist/coinlist-client-BH_Cn_7u.d.cts +0 -71
  52. package/dist/coinlist-client-fkB3J-2a.d.ts +0 -71
@@ -26,14 +26,30 @@ __export(client_exports, {
26
26
  CodeChallenge: () => CodeChallenge,
27
27
  CodeVerifier: () => CodeVerifier,
28
28
  CoinListProvider: () => CoinListProvider,
29
+ Cursor: () => Cursor,
30
+ FaqItem: () => FaqItem,
31
+ Link: () => Link,
32
+ Milestone: () => Milestone,
29
33
  OAuthRefreshToken: () => OAuthRefreshToken,
30
34
  OAuthSession: () => OAuthSession,
35
+ Offer: () => Offer,
36
+ OfferDetail: () => OfferDetail,
37
+ OfferId: () => OfferId,
38
+ OfferOption: () => OfferOption,
39
+ OfferOptionId: () => OfferOptionId,
40
+ OfferOptionSlug: () => OfferOptionSlug,
41
+ OfferSlug: () => OfferSlug,
42
+ PaginatedResponse: () => PaginatedResponse,
43
+ PaginationParams: () => PaginationParams,
31
44
  RedirectUri: () => RedirectUri,
45
+ TermItem: () => TermItem,
32
46
  User: () => User,
33
47
  UserEmail: () => UserEmail,
34
48
  UserId: () => UserId,
35
49
  createCoinListClient: () => createCoinListClient,
36
- useCoinList: () => useCoinList
50
+ fetchAllPages: () => fetchAllPages,
51
+ useCoinList: () => useCoinList,
52
+ useCompleteCoinListOAuth: () => useCompleteCoinListOAuth
37
53
  });
38
54
  module.exports = __toCommonJS(client_exports);
39
55
 
@@ -127,7 +143,10 @@ async function makeRequest(request) {
127
143
  if (request.method === "POST" && request.body !== void 0) {
128
144
  init.body = JSON.stringify(request.body);
129
145
  }
130
- const response = await fetch(request.url, init);
146
+ const response = await fetch(
147
+ buildUrlWithQueryParams(request.url, request.queryParams),
148
+ init
149
+ );
131
150
  const responseHeaders = headersToRecord(response.headers);
132
151
  if (response.status === 204 || response.status === 205) {
133
152
  return {
@@ -152,6 +171,32 @@ async function makeRequest(request) {
152
171
  headers: responseHeaders
153
172
  };
154
173
  }
174
+ function buildUrlWithQueryParams(url, queryParams) {
175
+ if (!queryParams) {
176
+ return url;
177
+ }
178
+ const searchParams = new URLSearchParams();
179
+ for (const [key, value] of Object.entries(queryParams)) {
180
+ if (value === void 0 || value === null) {
181
+ continue;
182
+ }
183
+ if (Array.isArray(value)) {
184
+ for (const item of value) {
185
+ if (item === void 0 || item === null) {
186
+ continue;
187
+ }
188
+ searchParams.append(key, String(item));
189
+ }
190
+ continue;
191
+ }
192
+ searchParams.append(key, String(value));
193
+ }
194
+ const queryString = searchParams.toString();
195
+ if (!queryString) {
196
+ return url;
197
+ }
198
+ return url.includes("?") ? `${url}&${queryString}` : `${url}?${queryString}`;
199
+ }
155
200
  function headersToRecord(headers) {
156
201
  const record = {};
157
202
  headers.forEach((value, key) => {
@@ -241,6 +286,13 @@ function getUUIDv4() {
241
286
  }
242
287
  return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
243
288
  }
289
+ function notBlankStringOrNull(value) {
290
+ if (value?.trim()) {
291
+ return value;
292
+ } else {
293
+ return null;
294
+ }
295
+ }
244
296
 
245
297
  // src/client/core/api/middleware/device-id.ts
246
298
  var DEVICE_ID_KEY = "coinlist.device_id";
@@ -259,7 +311,7 @@ var HEADER_API_VERSION = "X-API-Version";
259
311
  var HEADER_USER_AGENT = "User-Agent";
260
312
  var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
261
313
  var API_VERSION = "2025-10-17";
262
- var COINLIST_OAUTH_URL = "https://coinlist.co/oauth/authorize";
314
+ var COINLIST_OAUTH_PAGE_URL = "https://coinlist.co/oauth/authorize";
263
315
 
264
316
  // src/client/core/api/middleware/user-agent.ts
265
317
  var userAgentMiddleware = async (request) => {
@@ -434,6 +486,51 @@ var ApiClient = class {
434
486
  }
435
487
  };
436
488
 
489
+ // src/shared/api/pagination.ts
490
+ var Cursor = (value) => value;
491
+ async function fetchAllPages(fetchPage) {
492
+ const items = [];
493
+ let cursor = null;
494
+ do {
495
+ const page = await fetchPage({
496
+ after: cursor ?? void 0
497
+ });
498
+ items.push(...page.data);
499
+ cursor = page.startingAfter;
500
+ } while (cursor);
501
+ return items;
502
+ }
503
+ var PaginatedResponse = {
504
+ fromDto: (dto, itemMapper) => ({
505
+ data: dto.data.map(itemMapper),
506
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
507
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
508
+ })
509
+ };
510
+ var PaginationParams = {
511
+ toQueryParams: (params) => {
512
+ const queryParams = {};
513
+ if (params.after) {
514
+ queryParams.starting_after = params.after;
515
+ }
516
+ if (params.before) {
517
+ queryParams.starting_before = params.before;
518
+ }
519
+ if (params.limit) {
520
+ queryParams.limit = params.limit;
521
+ }
522
+ return queryParams;
523
+ }
524
+ };
525
+
526
+ // src/shared/types/errors.ts
527
+ var NotAuthenticatedError = class extends Error {
528
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
529
+ super(message);
530
+ this.name = "NotAuthenticatedError";
531
+ }
532
+ };
533
+
437
534
  // src/shared/types/oauth.ts
438
535
  var AuthorizationCode = (value) => value;
439
536
  var CodeVerifier = (value) => value;
@@ -442,6 +539,115 @@ var RedirectUri = (value) => value;
442
539
  var ClientId = (value) => value;
443
540
  var ClientSecret = (value) => value;
444
541
 
542
+ // src/shared/types/offer.ts
543
+ var OfferId = (value) => value;
544
+ var OfferSlug = (value) => value;
545
+ var Offer = {
546
+ fromDto: (dto) => ({
547
+ id: OfferId(dto.id),
548
+ slug: OfferSlug(dto.slug),
549
+ tagline: notBlankStringOrNull(dto.tagline),
550
+ bannerUrl: notBlankStringOrNull(dto.banner_url),
551
+ logoUrl: notBlankStringOrNull(dto.logo_url),
552
+ startsAt: new Date(dto.starts_at),
553
+ endsAt: new Date(dto.ends_at)
554
+ })
555
+ };
556
+
557
+ // src/shared/types/asset.ts
558
+ var AssetId = (value) => value;
559
+ var AssetCode = (value) => value;
560
+ var Asset = {
561
+ fromDto: (dto) => ({
562
+ id: AssetId(dto.id),
563
+ code: AssetCode(dto.code),
564
+ name: dto.name,
565
+ fractionalDigits: dto.fractional_digits
566
+ })
567
+ };
568
+
569
+ // src/shared/types/offer-detail.ts
570
+ var OfferOptionId = (value) => value;
571
+ var OfferOptionSlug = (value) => value;
572
+ var OfferDetail = {
573
+ fromDto: (dto) => {
574
+ if (!Array.isArray(dto.funding_assets)) {
575
+ throw new Error(`funding_assets must be an array`);
576
+ }
577
+ if (!Array.isArray(dto.options)) {
578
+ throw new Error(`options must be an array`);
579
+ }
580
+ if (!Array.isArray(dto.terms)) {
581
+ throw new Error(`terms must be an array`);
582
+ }
583
+ if (!Array.isArray(dto.links)) {
584
+ throw new Error(`links must be an array`);
585
+ }
586
+ if (!Array.isArray(dto.faqs)) {
587
+ throw new Error(`faqs must be an array`);
588
+ }
589
+ if (!Array.isArray(dto.milestones)) {
590
+ throw new Error(`milestones must be an array`);
591
+ }
592
+ return {
593
+ id: OfferId(dto.id),
594
+ slug: OfferSlug(dto.slug),
595
+ name: dto.name,
596
+ asset: Asset.fromDto(dto.asset),
597
+ fundingAssets: dto.funding_assets.map(Asset.fromDto),
598
+ about: notBlankStringOrNull(dto.about),
599
+ tagline: notBlankStringOrNull(dto.tagline),
600
+ bannerUrl: notBlankStringOrNull(dto.banner_url),
601
+ logoUrl: notBlankStringOrNull(dto.logo_url),
602
+ category: notBlankStringOrNull(dto.category),
603
+ startsAt: new Date(dto.starts_at),
604
+ endsAt: new Date(dto.ends_at),
605
+ faqs: dto.faqs.map(FaqItem.fromDto),
606
+ links: dto.links.map(Link.fromDto),
607
+ milestones: dto.milestones.map(Milestone.fromDto),
608
+ options: dto.options.map(OfferOption.fromDto),
609
+ terms: dto.terms.map(TermItem.fromDto)
610
+ };
611
+ }
612
+ };
613
+ var OfferOption = {
614
+ fromDto: (dto) => ({
615
+ id: OfferOptionId(dto.id),
616
+ slug: OfferOptionSlug(dto.slug),
617
+ bidIncrement: dto.bid_increment,
618
+ floorPriceUsd: dto.floor_price_usd,
619
+ minimumPurchaseUsd: dto.minimum_purchase_usd,
620
+ priceUsd: dto.price_usd,
621
+ saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
622
+ totalTokenSupply: dto.total_token_supply
623
+ })
624
+ };
625
+ var FaqItem = {
626
+ fromDto: (dto) => ({
627
+ question: notBlankStringOrNull(dto.question),
628
+ answer: notBlankStringOrNull(dto.answer)
629
+ })
630
+ };
631
+ var Link = {
632
+ fromDto: (dto) => ({
633
+ label: notBlankStringOrNull(dto.label),
634
+ url: notBlankStringOrNull(dto.url)
635
+ })
636
+ };
637
+ var TermItem = {
638
+ fromDto: (dto) => ({
639
+ key: notBlankStringOrNull(dto.key),
640
+ value: notBlankStringOrNull(dto.value)
641
+ })
642
+ };
643
+ var Milestone = {
644
+ fromDto: (dto) => ({
645
+ name: notBlankStringOrNull(dto.name),
646
+ schedule: notBlankStringOrNull(dto.schedule),
647
+ status: dto.status
648
+ })
649
+ };
650
+
445
651
  // src/client/core/coinlist-client.ts
446
652
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
447
653
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -450,7 +656,7 @@ var CoinListClientImpl = class {
450
656
  this._config = _config;
451
657
  /** Cached access token: undefined = loading, null = no token, AccessToken = logged in */
452
658
  this._accessToken = void 0;
453
- this._api = new ApiClient(
659
+ this.api = new ApiClient(
454
660
  {
455
661
  baseUrl: _config.baseUrl || PUBLIC_API_BASE_URL,
456
662
  xApiVersion: API_VERSION
@@ -494,11 +700,16 @@ var CoinListClientImpl = class {
494
700
  code_challenge_method: "S256",
495
701
  state
496
702
  });
497
- const url = `${COINLIST_OAUTH_URL}?${params.toString()}`;
703
+ const oauthPageUrl = this._config.authorizationPageUrl ?? COINLIST_OAUTH_PAGE_URL;
704
+ const url = `${oauthPageUrl}?${params.toString()}`;
498
705
  window.location.href = url;
499
706
  }
500
707
  completeOAuth() {
501
708
  const params = new URLSearchParams(window.location.search);
709
+ const coinlistError = params.get("error");
710
+ if (coinlistError) {
711
+ return { type: "error", reason: "user_canceled" };
712
+ }
502
713
  const stateParam = params.get("state");
503
714
  if (!stateParam) {
504
715
  return { type: "error", reason: "missing_state" };
@@ -524,6 +735,34 @@ var CoinListClientImpl = class {
524
735
  logout() {
525
736
  this._accessToken = null;
526
737
  }
738
+ async fetchAllOffers() {
739
+ this.ensureAuthenticated();
740
+ return await fetchAllPages(this.fetchOffersPage.bind(this));
741
+ }
742
+ async fetchOffersPage(params) {
743
+ this.ensureAuthenticated();
744
+ const pageDto = await this.api.send({
745
+ method: "GET",
746
+ url: "/v1/offers",
747
+ queryParams: PaginationParams.toQueryParams(params),
748
+ attributes: Attributes.protected()
749
+ });
750
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
751
+ }
752
+ async fetchOfferDetails(id) {
753
+ this.ensureAuthenticated();
754
+ const offerDetailDto = await this.api.send({
755
+ method: "GET",
756
+ url: `/v1/offers/${id}`,
757
+ attributes: Attributes.protected()
758
+ });
759
+ return OfferDetail.fromDto(offerDetailDto);
760
+ }
761
+ ensureAuthenticated() {
762
+ if (this.getAuthState() !== "logged-in") {
763
+ throw new NotAuthenticatedError();
764
+ }
765
+ }
527
766
  };
528
767
  function createCoinListClient(config) {
529
768
  return new CoinListClientImpl(config);
@@ -577,6 +816,60 @@ var CoinListClientInitializationError = class extends Error {
577
816
  }
578
817
  };
579
818
 
819
+ // src/client/hooks/useCompleteCoinListOAuth.ts
820
+ var import_react3 = require("react");
821
+ function useCompleteCoinListOAuth(options) {
822
+ const { coinlist } = useCoinList();
823
+ const postOAuthCompleteRef = (0, import_react3.useRef)(options.postOAuthComplete);
824
+ const onFailureRef = (0, import_react3.useRef)(options.onFailure);
825
+ const onSuccessRef = (0, import_react3.useRef)(options.onSuccess);
826
+ postOAuthCompleteRef.current = options.postOAuthComplete;
827
+ onFailureRef.current = options.onFailure;
828
+ onSuccessRef.current = options.onSuccess;
829
+ const hasStartedExchangeRef = (0, import_react3.useRef)(false);
830
+ (0, import_react3.useEffect)(() => {
831
+ if (typeof window === "undefined") return;
832
+ const params = new URLSearchParams(window.location.search);
833
+ if (!params.has("code") && !params.has("error")) return;
834
+ if (hasStartedExchangeRef.current) return;
835
+ const oauthResult = coinlist.completeOAuth();
836
+ if (oauthResult.type === "error") {
837
+ void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(
838
+ () => {
839
+ }
840
+ );
841
+ return;
842
+ }
843
+ hasStartedExchangeRef.current = true;
844
+ let cancelled = false;
845
+ void (async () => {
846
+ try {
847
+ const ok = await postOAuthCompleteRef.current({
848
+ code: oauthResult.code,
849
+ codeVerifier: oauthResult.codeVerifier
850
+ });
851
+ if (cancelled) return;
852
+ if (!ok) {
853
+ hasStartedExchangeRef.current = false;
854
+ await onFailureRef.current("complete_request_failed");
855
+ return;
856
+ }
857
+ await coinlist.init();
858
+ if (cancelled) return;
859
+ await onSuccessRef.current();
860
+ } catch {
861
+ if (cancelled) return;
862
+ hasStartedExchangeRef.current = false;
863
+ await onFailureRef.current("complete_request_failed");
864
+ }
865
+ })();
866
+ return () => {
867
+ cancelled = true;
868
+ hasStartedExchangeRef.current = false;
869
+ };
870
+ }, [coinlist]);
871
+ }
872
+
580
873
  // src/shared/types/oauth-session.ts
581
874
  var OAuthRefreshToken = (value) => value;
582
875
  var OAuthSession = {
@@ -609,13 +902,29 @@ var User = {
609
902
  CodeChallenge,
610
903
  CodeVerifier,
611
904
  CoinListProvider,
905
+ Cursor,
906
+ FaqItem,
907
+ Link,
908
+ Milestone,
612
909
  OAuthRefreshToken,
613
910
  OAuthSession,
911
+ Offer,
912
+ OfferDetail,
913
+ OfferId,
914
+ OfferOption,
915
+ OfferOptionId,
916
+ OfferOptionSlug,
917
+ OfferSlug,
918
+ PaginatedResponse,
919
+ PaginationParams,
614
920
  RedirectUri,
921
+ TermItem,
615
922
  User,
616
923
  UserEmail,
617
924
  UserId,
618
925
  createCoinListClient,
619
- useCoinList
926
+ fetchAllPages,
927
+ useCoinList,
928
+ useCompleteCoinListOAuth
620
929
  });
621
930
  //# sourceMappingURL=index.cjs.map