@coinlist-co/react 0.3.0 → 0.4.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 (65) hide show
  1. package/dist/{RequirementItem-BvwsFu9e.d.cts → RequirementItem-B-MvcxSr.d.cts} +3 -3
  2. package/dist/{RequirementItem-BpkJQep8.d.ts → RequirementItem-DcYot2uC.d.ts} +3 -3
  3. package/dist/{chunk-IDCROXPS.js → chunk-EHZ6PIGN.js} +6 -4
  4. package/dist/chunk-EHZ6PIGN.js.map +1 -0
  5. package/dist/chunk-NC45IO63.js +777 -0
  6. package/dist/chunk-NC45IO63.js.map +1 -0
  7. package/dist/chunk-RIFATQB5.js +257 -0
  8. package/dist/chunk-RIFATQB5.js.map +1 -0
  9. package/dist/chunk-UGJUTRXC.js +304 -0
  10. package/dist/chunk-UGJUTRXC.js.map +1 -0
  11. package/dist/client/components/index.cjs +60 -59
  12. package/dist/client/components/index.cjs.map +1 -1
  13. package/dist/client/components/index.d.cts +40 -22
  14. package/dist/client/components/index.d.ts +40 -22
  15. package/dist/client/components/index.js +34 -62
  16. package/dist/client/components/index.js.map +1 -1
  17. package/dist/client/core/index.cjs +308 -222
  18. package/dist/client/core/index.cjs.map +1 -1
  19. package/dist/client/core/index.d.cts +4 -4
  20. package/dist/client/core/index.d.ts +4 -4
  21. package/dist/client/core/index.js +14 -14
  22. package/dist/client/hooks/index.cjs +87 -13
  23. package/dist/client/hooks/index.cjs.map +1 -1
  24. package/dist/client/hooks/index.d.cts +102 -9
  25. package/dist/client/hooks/index.d.ts +102 -9
  26. package/dist/client/hooks/index.js +9 -9
  27. package/dist/client/index.cjs +465 -237
  28. package/dist/client/index.cjs.map +1 -1
  29. package/dist/client/index.d.cts +7 -8
  30. package/dist/client/index.d.ts +7 -8
  31. package/dist/client/index.js +24 -18
  32. package/dist/{coinlist-client-B_dJkbwB.d.ts → coinlist-client-BSxpqylo.d.ts} +13 -138
  33. package/dist/{coinlist-client-DBKa6j3f.d.cts → coinlist-client-Cah5c_aF.d.cts} +13 -138
  34. package/dist/participation-DMMEDxON.d.cts +185 -0
  35. package/dist/participation-E-bT-GXJ.d.ts +185 -0
  36. package/dist/{requirement-CxbdY8l4.d.cts → requirement-XWT0T_zO.d.cts} +5 -2
  37. package/dist/{requirement-fJsQ3f9_.d.ts → requirement-XWT0T_zO.d.ts} +5 -2
  38. package/dist/server/index.cjs +519 -14
  39. package/dist/server/index.cjs.map +1 -1
  40. package/dist/server/index.d.cts +73 -4
  41. package/dist/server/index.d.ts +73 -4
  42. package/dist/server/index.js +116 -20
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/useCoinListRequirements-B5-ZPOMz.d.ts +80 -0
  45. package/dist/useCoinListRequirements-Cuc32Tqw.d.cts +80 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-GRVV7NLV.js +0 -282
  48. package/dist/chunk-GRVV7NLV.js.map +0 -1
  49. package/dist/chunk-IADBIDY6.js +0 -76
  50. package/dist/chunk-IADBIDY6.js.map +0 -1
  51. package/dist/chunk-IDCROXPS.js.map +0 -1
  52. package/dist/chunk-P4DTIPEX.js +0 -623
  53. package/dist/chunk-P4DTIPEX.js.map +0 -1
  54. package/dist/chunk-V5M7SA3C.js +0 -161
  55. package/dist/chunk-V5M7SA3C.js.map +0 -1
  56. package/dist/newtype-yKTvFdg_.d.cts +0 -6
  57. package/dist/newtype-yKTvFdg_.d.ts +0 -6
  58. package/dist/oauth-session-DgItaMKN.d.cts +0 -56
  59. package/dist/oauth-session-DnKDI5ou.d.ts +0 -56
  60. package/dist/useCoinListOffers-C5lBlzcC.d.ts +0 -27
  61. package/dist/useCoinListOffers-CguwXaCX.d.cts +0 -27
  62. package/dist/useCoinListRequirements-BECx1cIw.d.ts +0 -31
  63. package/dist/useCoinListRequirements-CX2gV9gJ.d.cts +0 -31
  64. package/dist/useCompleteCoinListOAuth-BRhAqD4_.d.cts +0 -55
  65. package/dist/useCompleteCoinListOAuth-DEZpHjd6.d.ts +0 -55
@@ -61,14 +61,94 @@ __export(client_exports, {
61
61
  createCoinListClient: () => createCoinListClient,
62
62
  fetchAllPages: () => fetchAllPages,
63
63
  useCoinList: () => useCoinList,
64
+ useCoinListOfferDetails: () => useCoinListOfferDetails,
65
+ useCoinListOffers: () => useCoinListOffers,
64
66
  useCoinListRequirements: () => useCoinListRequirements,
65
- useCompleteCoinListOAuth: () => useCompleteCoinListOAuth
67
+ useCompleteCoinListOAuth: () => useCompleteCoinListOAuth,
68
+ useParticipations: () => useParticipations
66
69
  });
67
70
  module.exports = __toCommonJS(client_exports);
68
71
 
69
72
  // src/client/CoinListProvider.tsx
70
73
  var import_react = require("react");
71
74
 
75
+ // src/shared/utils.ts
76
+ async function sha256(data) {
77
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
78
+ const buffer = bytes.buffer.slice(
79
+ bytes.byteOffset,
80
+ bytes.byteOffset + bytes.byteLength
81
+ );
82
+ return crypto.subtle.digest("SHA-256", buffer);
83
+ }
84
+ function arrayBufferToBase64Url(buffer, padding = true) {
85
+ const bytes = new Uint8Array(buffer);
86
+ let binary = "";
87
+ for (let i = 0; i < bytes.length; i++) {
88
+ binary += String.fromCharCode(bytes[i]);
89
+ }
90
+ let base64 = btoa(binary);
91
+ base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
92
+ if (!padding) {
93
+ base64 = base64.replace(/=+$/, "");
94
+ }
95
+ return base64;
96
+ }
97
+ function generateSecureRandomBase64Url(byteLength) {
98
+ const bytes = new Uint8Array(byteLength);
99
+ crypto.getRandomValues(bytes);
100
+ const buffer = bytes.buffer;
101
+ return arrayBufferToBase64Url(buffer, false);
102
+ }
103
+ function getUUIDv4() {
104
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
105
+ return crypto.randomUUID();
106
+ }
107
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
108
+ const bytes = new Uint8Array(16);
109
+ crypto.getRandomValues(bytes);
110
+ bytes[6] = bytes[6] & 15 | 64;
111
+ bytes[8] = bytes[8] & 63 | 128;
112
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
113
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
114
+ }
115
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
116
+ }
117
+ function notBlankStringOrNull(value) {
118
+ if (value?.trim()) {
119
+ return value;
120
+ } else {
121
+ return null;
122
+ }
123
+ }
124
+
125
+ // src/client/core/api/middleware/device-id.ts
126
+ var DEVICE_ID_KEY = "coinlist.device_id";
127
+ function getDeviceId() {
128
+ let deviceId = localStorage.getItem(DEVICE_ID_KEY);
129
+ if (!deviceId) {
130
+ deviceId = getUUIDv4();
131
+ localStorage.setItem(DEVICE_ID_KEY, deviceId);
132
+ }
133
+ return deviceId;
134
+ }
135
+
136
+ // src/shared/api/frontline/index.ts
137
+ var PUBLIC_API_BASE_URL = "https://api.coinlist.co";
138
+ var HEADER_API_VERSION = "X-API-Version";
139
+ var HEADER_USER_AGENT = "User-Agent";
140
+ var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
141
+ var API_VERSION = "2025-10-17";
142
+ var COINLIST_BASE_URL = "https://coinlist.co";
143
+ var OAUTH_PAGE_PATH = "/oauth/authorize";
144
+ var SUPPORT_NEW_TICKET_URL = "https://support.coinlist.co/support/tickets/new";
145
+ var VERIFY_IDENTITY_PATH = "/verify-identity";
146
+ var VERIFY_IDENTITY_VERIFIED_PATH = "/verify-identity/identity_verified";
147
+ var VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH = "/verify-identity/proof_of_address";
148
+ var VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH = "/verify-identity/source_of_funds";
149
+ var VERIFY_IDENTITY_ACCREDITATION_PATH = "/verify-identity/accreditation_full";
150
+ var WALLET_PATH = "/wallet";
151
+
72
152
  // src/shared/api/http-attributes.ts
73
153
  var empty = {};
74
154
  var concat = (left, right) => ({
@@ -114,24 +194,28 @@ var Attributes = {
114
194
  wasRenewAttempted
115
195
  };
116
196
 
117
- // src/client/core/api/middleware/attach-session-middleware.ts
118
- function attachSessionMiddleware(fetchAccessToken) {
119
- return async (request) => {
120
- if (!Attributes.isProtected(request.attributes)) {
121
- return request;
122
- }
123
- const accessToken = await fetchAccessToken(false);
124
- if (accessToken === null) {
125
- return request;
197
+ // src/client/core/api/middleware/user-agent.ts
198
+ var userAgentMiddleware = async (request) => {
199
+ if (!Attributes.needUserAgent(request.attributes)) {
200
+ return request;
201
+ }
202
+ const userAgent2 = generateUserAgent();
203
+ return {
204
+ ...request,
205
+ headers: {
206
+ ...request.headers ?? {},
207
+ [HEADER_USER_AGENT]: userAgent2
126
208
  }
127
- return {
128
- ...request,
129
- headers: {
130
- ...request.headers ?? {},
131
- Authorization: `Bearer ${accessToken.value}`
132
- }
133
- };
134
209
  };
210
+ };
211
+ function generateUserAgent() {
212
+ const appInfo = `CoinList/1.0`;
213
+ const deviceInfo = "Web Browser";
214
+ const devicePlatform = "DevicePlatform web";
215
+ const deviceAppId = "DeviceAppID co.coinlist.sdk";
216
+ const deviceId = getDeviceId();
217
+ const finalDeviceId = `DeviceID ${deviceId}`;
218
+ return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;
135
219
  }
136
220
 
137
221
  // src/shared/api/http.ts
@@ -232,124 +316,6 @@ var Request = {
232
316
  concatAttributes
233
317
  };
234
318
 
235
- // src/client/core/api/middleware/session-renewal.ts
236
- function renewSessionMiddleware(fetchAccessToken) {
237
- return async ({ request, response, retry }) => {
238
- if (response.status !== 401) {
239
- return response;
240
- }
241
- if (!Attributes.isProtected(request.attributes)) {
242
- return response;
243
- }
244
- if (Attributes.wasRenewAttempted(request.attributes)) {
245
- return response;
246
- }
247
- const newToken = await fetchAccessToken(true);
248
- if (newToken) {
249
- const nextRequest = Request.concatAttributes(
250
- request,
251
- Attributes.renewAttempted(true)
252
- );
253
- return retry(nextRequest);
254
- } else {
255
- return response;
256
- }
257
- };
258
- }
259
-
260
- // src/shared/utils.ts
261
- async function sha256(data) {
262
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
263
- const buffer = bytes.buffer.slice(
264
- bytes.byteOffset,
265
- bytes.byteOffset + bytes.byteLength
266
- );
267
- return crypto.subtle.digest("SHA-256", buffer);
268
- }
269
- function arrayBufferToBase64Url(buffer, padding = true) {
270
- const bytes = new Uint8Array(buffer);
271
- let binary = "";
272
- for (let i = 0; i < bytes.length; i++) {
273
- binary += String.fromCharCode(bytes[i]);
274
- }
275
- let base64 = btoa(binary);
276
- base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
277
- if (!padding) {
278
- base64 = base64.replace(/=+$/, "");
279
- }
280
- return base64;
281
- }
282
- function generateSecureRandomBase64Url(byteLength) {
283
- const bytes = new Uint8Array(byteLength);
284
- crypto.getRandomValues(bytes);
285
- const buffer = bytes.buffer;
286
- return arrayBufferToBase64Url(buffer, false);
287
- }
288
- function getUUIDv4() {
289
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
290
- return crypto.randomUUID();
291
- }
292
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
293
- const bytes = new Uint8Array(16);
294
- crypto.getRandomValues(bytes);
295
- bytes[6] = bytes[6] & 15 | 64;
296
- bytes[8] = bytes[8] & 63 | 128;
297
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
298
- return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
299
- }
300
- return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
301
- }
302
- function notBlankStringOrNull(value) {
303
- if (value?.trim()) {
304
- return value;
305
- } else {
306
- return null;
307
- }
308
- }
309
-
310
- // src/client/core/api/middleware/device-id.ts
311
- var DEVICE_ID_KEY = "coinlist.device_id";
312
- function getDeviceId() {
313
- let deviceId = localStorage.getItem(DEVICE_ID_KEY);
314
- if (!deviceId) {
315
- deviceId = getUUIDv4();
316
- localStorage.setItem(DEVICE_ID_KEY, deviceId);
317
- }
318
- return deviceId;
319
- }
320
-
321
- // src/shared/api/frontline.ts
322
- var PUBLIC_API_BASE_URL = "https://api.coinlist.co";
323
- var HEADER_API_VERSION = "X-API-Version";
324
- var HEADER_USER_AGENT = "User-Agent";
325
- var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
326
- var API_VERSION = "2025-10-17";
327
- var COINLIST_OAUTH_PAGE_URL = "https://coinlist.co/oauth/authorize";
328
-
329
- // src/client/core/api/middleware/user-agent.ts
330
- var userAgentMiddleware = async (request) => {
331
- if (!Attributes.needUserAgent(request.attributes)) {
332
- return request;
333
- }
334
- const userAgent2 = generateUserAgent();
335
- return {
336
- ...request,
337
- headers: {
338
- ...request.headers ?? {},
339
- [HEADER_USER_AGENT]: userAgent2
340
- }
341
- };
342
- };
343
- function generateUserAgent() {
344
- const appInfo = `CoinList/1.0`;
345
- const deviceInfo = "Web Browser";
346
- const devicePlatform = "DevicePlatform web";
347
- const deviceAppId = "DeviceAppID co.coinlist.sdk";
348
- const deviceId = getDeviceId();
349
- const finalDeviceId = `DeviceID ${deviceId}`;
350
- return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;
351
- }
352
-
353
319
  // src/shared/api/http-client.ts
354
320
  var HttpClient = class {
355
321
  constructor(config, middleware = {}) {
@@ -419,6 +385,26 @@ var HttpClient = class {
419
385
  }
420
386
  };
421
387
 
388
+ // src/shared/api/middleware/attach-session-middleware.ts
389
+ function attachSessionMiddleware(fetchAccessToken) {
390
+ return async (request) => {
391
+ if (!Attributes.isProtected(request.attributes)) {
392
+ return request;
393
+ }
394
+ const accessToken = await fetchAccessToken(false);
395
+ if (accessToken === null) {
396
+ return request;
397
+ }
398
+ return {
399
+ ...request,
400
+ headers: {
401
+ ...request.headers ?? {},
402
+ Authorization: `Bearer ${accessToken.value}`
403
+ }
404
+ };
405
+ };
406
+ }
407
+
422
408
  // src/shared/api/middleware/idempotency-key.ts
423
409
  var idempotencyKeyMiddleware = async (request) => {
424
410
  if (!Attributes.isIdempotent(request.attributes)) {
@@ -472,19 +458,42 @@ function defaultDelay(ms) {
472
458
  }
473
459
  var requestRetryMiddleware = createRequestRetryMiddleware();
474
460
 
475
- // src/client/core/api/api-client.ts
476
- var ApiClient = class {
477
- constructor(config, fetchAccessToken) {
478
- this.config = config;
479
- this.fetchAccessToken = fetchAccessToken;
480
- this.httpClient = new HttpClient(this.config, {
461
+ // src/shared/api/middleware/session-renewal.ts
462
+ function renewSessionMiddleware(fetchAccessToken) {
463
+ return async ({ request, response, retry }) => {
464
+ if (response.status !== 401) {
465
+ return response;
466
+ }
467
+ if (!Attributes.isProtected(request.attributes)) {
468
+ return response;
469
+ }
470
+ if (Attributes.wasRenewAttempted(request.attributes)) {
471
+ return response;
472
+ }
473
+ const newToken = await fetchAccessToken(true);
474
+ if (newToken) {
475
+ const nextRequest = Request.concatAttributes(
476
+ request,
477
+ Attributes.renewAttempted(true)
478
+ );
479
+ return retry(nextRequest);
480
+ } else {
481
+ return response;
482
+ }
483
+ };
484
+ }
485
+
486
+ // src/shared/api/authenticated-api-client.ts
487
+ var AuthenticatedApiClient = class {
488
+ constructor(config, fetchAccessToken, additionalBeforeRequest = []) {
489
+ this.httpClient = new HttpClient(config, {
481
490
  beforeRequest: [
482
- attachSessionMiddleware(this.fetchAccessToken),
483
- userAgentMiddleware,
491
+ attachSessionMiddleware(fetchAccessToken),
492
+ ...additionalBeforeRequest,
484
493
  idempotencyKeyMiddleware
485
494
  ],
486
495
  afterRequest: [
487
- renewSessionMiddleware(this.fetchAccessToken),
496
+ renewSessionMiddleware(fetchAccessToken),
488
497
  requestRetryMiddleware
489
498
  ]
490
499
  });
@@ -499,6 +508,18 @@ var ApiClient = class {
499
508
  }
500
509
  };
501
510
 
511
+ // src/client/core/api/api-client.ts
512
+ var ApiClient = class {
513
+ constructor(config, fetchAccessToken) {
514
+ this.client = new AuthenticatedApiClient(config, fetchAccessToken, [
515
+ userAgentMiddleware
516
+ ]);
517
+ }
518
+ async send(request) {
519
+ return this.client.send(request);
520
+ }
521
+ };
522
+
502
523
  // src/shared/api/pagination.ts
503
524
  var Cursor = (value) => value;
504
525
  async function fetchAllPages(fetchPage, baseParams) {
@@ -538,22 +559,6 @@ var PaginationParams = {
538
559
  }
539
560
  };
540
561
 
541
- // src/shared/types/errors.ts
542
- var NotAuthenticatedError = class extends Error {
543
- constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
544
- super(message);
545
- this.name = "NotAuthenticatedError";
546
- }
547
- };
548
-
549
- // src/shared/types/oauth.ts
550
- var AuthorizationCode = (value) => value;
551
- var CodeVerifier = (value) => value;
552
- var CodeChallenge = (value) => value;
553
- var RedirectUri = (value) => value;
554
- var ClientId = (value) => value;
555
- var ClientSecret = (value) => value;
556
-
557
562
  // src/shared/types/offer.ts
558
563
  var OfferId = (value) => value;
559
564
  var OfferSlug = (value) => value;
@@ -663,6 +668,29 @@ var Milestone = {
663
668
  })
664
669
  };
665
670
 
671
+ // src/shared/api/frontline/offers.ts
672
+ async function fetchAllOffers(api) {
673
+ return fetchAllPages((params) => fetchOffersPage(api, params));
674
+ }
675
+ async function fetchOffersPage(api, params) {
676
+ const queryParams = PaginationParams.toQueryParams(params);
677
+ const pageDto = await api.send({
678
+ method: "GET",
679
+ url: "/v1/offers",
680
+ queryParams,
681
+ attributes: Attributes.protected()
682
+ });
683
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
684
+ }
685
+ async function fetchOfferDetails(api, id) {
686
+ const dto = await api.send({
687
+ method: "GET",
688
+ url: `/v1/offers/${id}`,
689
+ attributes: Attributes.protected()
690
+ });
691
+ return OfferDetail.fromDto(dto);
692
+ }
693
+
666
694
  // src/shared/types/participation.ts
667
695
  var ParticipationId = (value) => value;
668
696
  var Blockchain = (value) => value;
@@ -710,6 +738,40 @@ var CreateParticipationParams = {
710
738
  })
711
739
  };
712
740
 
741
+ // src/shared/api/frontline/participations.ts
742
+ async function fetchAllParticipations(api, offerId) {
743
+ return fetchAllPages(
744
+ (params) => fetchParticipationsPage(api, params),
745
+ { offerId }
746
+ );
747
+ }
748
+ async function fetchParticipationsPage(api, params) {
749
+ const pageDto = await api.send({
750
+ method: "GET",
751
+ url: "/v1/participations",
752
+ queryParams: ParticipationsPaginationParams.toQueryParams(params),
753
+ attributes: Attributes.protected()
754
+ });
755
+ return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
756
+ }
757
+ async function fetchParticipation(api, id) {
758
+ const dto = await api.send({
759
+ method: "GET",
760
+ url: `/v1/participations/${id}`,
761
+ attributes: Attributes.protected()
762
+ });
763
+ return Participation.fromDto(dto);
764
+ }
765
+ async function createParticipation(api, params) {
766
+ const dto = await api.send({
767
+ method: "POST",
768
+ url: "/v1/participations",
769
+ body: CreateParticipationParams.toDto(params),
770
+ attributes: Attributes.protected()
771
+ });
772
+ return Participation.fromDto(dto);
773
+ }
774
+
713
775
  // src/shared/types/requirement.ts
714
776
  var RequirementId = (value) => value;
715
777
  var Requirement = {
@@ -726,6 +788,45 @@ var RequirementStatusInfo = {
726
788
  }))
727
789
  };
728
790
 
791
+ // src/shared/api/frontline/requirements.ts
792
+ async function fetchOfferRequirements(api, offerId) {
793
+ const response = await api.send({
794
+ method: "GET",
795
+ url: `/v1/offers/${offerId}/requirements`,
796
+ attributes: Attributes.protected()
797
+ });
798
+ return Object.fromEntries(
799
+ Object.entries(response.options).map(([optionId, list]) => [
800
+ optionId,
801
+ list.data.map(Requirement.fromDto)
802
+ ])
803
+ );
804
+ }
805
+ async function fetchRequirementStatuses(api, offerId) {
806
+ const response = await api.send({
807
+ method: "GET",
808
+ url: `/v1/offers/${offerId}/requirements/statuses`,
809
+ attributes: Attributes.protected()
810
+ });
811
+ return RequirementStatusInfo.fromStatusesDto(response);
812
+ }
813
+
814
+ // src/shared/types/errors.ts
815
+ var NotAuthenticatedError = class extends Error {
816
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
817
+ super(message);
818
+ this.name = "NotAuthenticatedError";
819
+ }
820
+ };
821
+
822
+ // src/shared/types/oauth.ts
823
+ var AuthorizationCode = (value) => value;
824
+ var CodeVerifier = (value) => value;
825
+ var CodeChallenge = (value) => value;
826
+ var RedirectUri = (value) => value;
827
+ var ClientId = (value) => value;
828
+ var ClientSecret = (value) => value;
829
+
729
830
  // src/client/core/coinlist-client.ts
730
831
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
731
832
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -778,8 +879,8 @@ var CoinListClientImpl = class {
778
879
  code_challenge_method: "S256",
779
880
  state
780
881
  });
781
- const oauthPageUrl = this._config.authorizationPageUrl ?? COINLIST_OAUTH_PAGE_URL;
782
- const url = `${oauthPageUrl}?${params.toString()}`;
882
+ const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
883
+ const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;
783
884
  window.location.href = url;
784
885
  }
785
886
  completeOAuth() {
@@ -815,91 +916,76 @@ var CoinListClientImpl = class {
815
916
  }
816
917
  async fetchAllOffers() {
817
918
  this.ensureAuthenticated();
818
- return await fetchAllPages(this.fetchOffersPage.bind(this));
919
+ return fetchAllOffers(this.api);
819
920
  }
820
921
  async fetchOffersPage(params) {
821
922
  this.ensureAuthenticated();
822
- const queryParams = PaginationParams.toQueryParams(params);
823
- if (this._config.sandbox) {
824
- queryParams.sandbox = true;
825
- }
826
- const pageDto = await this.api.send({
827
- method: "GET",
828
- url: "/v1/offers",
829
- queryParams,
830
- attributes: Attributes.protected()
831
- });
832
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
923
+ return fetchOffersPage(this.api, params);
833
924
  }
834
925
  async fetchOfferDetails(id) {
835
926
  this.ensureAuthenticated();
836
- const offerDetailDto = await this.api.send({
837
- method: "GET",
838
- url: `/v1/offers/${id}`,
839
- attributes: Attributes.protected()
840
- });
841
- return OfferDetail.fromDto(offerDetailDto);
927
+ return fetchOfferDetails(this.api, id);
842
928
  }
843
929
  async fetchAllParticipations(offerId) {
844
930
  this.ensureAuthenticated();
845
- return await fetchAllPages(
846
- this.fetchParticipationsPage.bind(this),
847
- { offerId }
848
- );
931
+ return fetchAllParticipations(this.api, offerId);
849
932
  }
850
933
  async fetchParticipationsPage(params) {
851
934
  this.ensureAuthenticated();
852
- const pageDto = await this.api.send(
853
- {
854
- method: "GET",
855
- url: "/v1/participations",
856
- queryParams: ParticipationsPaginationParams.toQueryParams(params),
857
- attributes: Attributes.protected()
858
- }
859
- );
860
- return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
935
+ return fetchParticipationsPage(this.api, params);
861
936
  }
862
937
  async fetchParticipation(id) {
863
938
  this.ensureAuthenticated();
864
- const participationDto = await this.api.send({
865
- method: "GET",
866
- url: `/v1/participations/${id}`,
867
- attributes: Attributes.protected()
868
- });
869
- return Participation.fromDto(participationDto);
939
+ return fetchParticipation(this.api, id);
870
940
  }
871
941
  async createParticipation(params) {
872
942
  this.ensureAuthenticated();
873
- const participationDto = await this.api.send({
874
- method: "POST",
875
- url: "/v1/participations",
876
- body: CreateParticipationParams.toDto(params),
877
- attributes: Attributes.protected()
878
- });
879
- return Participation.fromDto(participationDto);
943
+ return createParticipation(this.api, params);
880
944
  }
881
945
  async fetchOfferRequirements(offerId) {
882
946
  this.ensureAuthenticated();
883
- const response = await this.api.send({
884
- method: "GET",
885
- url: `/v1/offers/${offerId}/requirements`,
886
- attributes: Attributes.protected()
887
- });
888
- return Object.fromEntries(
889
- Object.entries(response.options).map(([optionId, list]) => [
890
- optionId,
891
- list.data.map(Requirement.fromDto)
892
- ])
893
- );
947
+ return fetchOfferRequirements(this.api, offerId);
894
948
  }
895
949
  async fetchRequirementStatuses(offerId) {
896
950
  this.ensureAuthenticated();
897
- const response = await this.api.send({
898
- method: "GET",
899
- url: `/v1/offers/${offerId}/requirements/statuses`,
900
- attributes: Attributes.protected()
901
- });
902
- return RequirementStatusInfo.fromStatusesDto(response);
951
+ return fetchRequirementStatuses(this.api, offerId);
952
+ }
953
+ handleRequirement(requirement) {
954
+ const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
955
+ let path;
956
+ switch (requirement.type) {
957
+ case "kyc_approved":
958
+ path = VERIFY_IDENTITY_PATH;
959
+ break;
960
+ case "identity_verified":
961
+ path = VERIFY_IDENTITY_VERIFIED_PATH;
962
+ break;
963
+ case "proof_of_address":
964
+ path = VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH;
965
+ break;
966
+ case "source_of_funds":
967
+ path = VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH;
968
+ break;
969
+ case "accreditation":
970
+ path = VERIFY_IDENTITY_ACCREDITATION_PATH;
971
+ break;
972
+ case "external_wallet":
973
+ case "whitelisted_wallet":
974
+ path = WALLET_PATH;
975
+ break;
976
+ case "jurisdiction":
977
+ path = null;
978
+ break;
979
+ default: {
980
+ const _exhaustive = requirement.type;
981
+ return;
982
+ }
983
+ }
984
+ if (path === null) return;
985
+ openInNewTab(new URL(path, baseUrl).toString());
986
+ }
987
+ contactSupport() {
988
+ openInNewTab(SUPPORT_NEW_TICKET_URL);
903
989
  }
904
990
  ensureAuthenticated() {
905
991
  if (this.getAuthState() !== "logged-in") {
@@ -907,6 +993,9 @@ var CoinListClientImpl = class {
907
993
  }
908
994
  }
909
995
  };
996
+ function openInNewTab(url) {
997
+ window.open(url, "_blank", "noopener,noreferrer");
998
+ }
910
999
  function createCoinListClient(config) {
911
1000
  return new CoinListClientImpl(config);
912
1001
  }
@@ -996,23 +1085,117 @@ var CoinListClientInitializationError = class extends Error {
996
1085
  }
997
1086
  };
998
1087
 
999
- // src/client/hooks/useCoinListRequirements.ts
1088
+ // src/client/hooks/useCoinListOfferDetails.ts
1000
1089
  var import_react3 = require("react");
1001
1090
  var LOADING_STATE = { type: "LOADING" };
1002
- function useCoinListRequirements(offerId) {
1091
+ function useCoinListOfferDetails(offerId, options = {}) {
1003
1092
  const { coinlist, isReady } = useCoinList();
1004
- const [requirementsState, setRequirementsState] = (0, import_react3.useState)(LOADING_STATE);
1005
- const [fetchKey, setFetchKey] = (0, import_react3.useState)(0);
1006
- const refetch = (0, import_react3.useCallback)(() => setFetchKey((k) => k + 1), []);
1093
+ const { serverData } = options;
1094
+ const [offerDetailsState, setOfferDetailsState] = (0, import_react3.useState)(
1095
+ serverData !== void 0 ? { type: "CONTENT", offerDetail: serverData } : LOADING_STATE
1096
+ );
1007
1097
  (0, import_react3.useEffect)(() => {
1008
1098
  let isCancelled = false;
1009
1099
  if (!isReady) {
1010
- setRequirementsState(LOADING_STATE);
1100
+ if (serverData === void 0) {
1101
+ setOfferDetailsState(LOADING_STATE);
1102
+ }
1103
+ return () => {
1104
+ isCancelled = true;
1105
+ };
1106
+ }
1107
+ if (serverData !== void 0) {
1108
+ return () => {
1109
+ isCancelled = true;
1110
+ };
1111
+ }
1112
+ setOfferDetailsState(LOADING_STATE);
1113
+ coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
1114
+ if (!isCancelled) {
1115
+ setOfferDetailsState({ type: "CONTENT", offerDetail });
1116
+ }
1117
+ }).catch((error) => {
1118
+ if (!isCancelled) {
1119
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1120
+ setOfferDetailsState({ type: "ERROR", reason });
1121
+ }
1122
+ });
1123
+ return () => {
1124
+ isCancelled = true;
1125
+ };
1126
+ }, [coinlist, isReady, offerId, serverData]);
1127
+ return { offerDetailsState };
1128
+ }
1129
+
1130
+ // src/client/hooks/useCoinListOffers.ts
1131
+ var import_react4 = require("react");
1132
+ var LOADING_STATE2 = { type: "LOADING" };
1133
+ function useCoinListOffers(options = {}) {
1134
+ const { coinlist, isReady } = useCoinList();
1135
+ const { serverOffers } = options;
1136
+ const [offersState, setOffersState] = (0, import_react4.useState)(
1137
+ serverOffers !== void 0 ? { type: "CONTENT", offers: serverOffers } : LOADING_STATE2
1138
+ );
1139
+ (0, import_react4.useEffect)(() => {
1140
+ let isCancelled = false;
1141
+ if (!isReady) {
1142
+ if (serverOffers === void 0) {
1143
+ setOffersState(LOADING_STATE2);
1144
+ }
1145
+ return () => {
1146
+ isCancelled = true;
1147
+ };
1148
+ }
1149
+ if (serverOffers !== void 0) {
1150
+ return () => {
1151
+ isCancelled = true;
1152
+ };
1153
+ }
1154
+ setOffersState(LOADING_STATE2);
1155
+ coinlist.fetchAllOffers().then((offers) => {
1156
+ if (!isCancelled) {
1157
+ setOffersState({ type: "CONTENT", offers });
1158
+ }
1159
+ }).catch((error) => {
1160
+ if (!isCancelled) {
1161
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1162
+ setOffersState({ type: "ERROR", reason });
1163
+ }
1164
+ });
1165
+ return () => {
1166
+ isCancelled = true;
1167
+ };
1168
+ }, [coinlist, isReady, serverOffers]);
1169
+ return { offersState };
1170
+ }
1171
+
1172
+ // src/client/hooks/useCoinListRequirements.ts
1173
+ var import_react5 = require("react");
1174
+ var LOADING_STATE3 = { type: "LOADING" };
1175
+ function useCoinListRequirements(offerId, options = {}) {
1176
+ const { coinlist, isReady } = useCoinList();
1177
+ const { serverData } = options;
1178
+ const [requirementsState, setRequirementsState] = (0, import_react5.useState)(
1179
+ serverData !== void 0 ? { type: "CONTENT", ...serverData } : LOADING_STATE3
1180
+ );
1181
+ const [fetchKey, setFetchKey] = (0, import_react5.useState)(0);
1182
+ const refetch = (0, import_react5.useCallback)(() => setFetchKey((k) => k + 1), []);
1183
+ (0, import_react5.useEffect)(() => {
1184
+ let isCancelled = false;
1185
+ if (!isReady) {
1186
+ if (serverData === void 0) {
1187
+ setRequirementsState(LOADING_STATE3);
1188
+ }
1189
+ return () => {
1190
+ isCancelled = true;
1191
+ };
1192
+ }
1193
+ if (serverData !== void 0 && fetchKey === 0) {
1011
1194
  return () => {
1012
1195
  isCancelled = true;
1013
1196
  };
1014
1197
  }
1015
- setRequirementsState(LOADING_STATE);
1198
+ setRequirementsState(LOADING_STATE3);
1016
1199
  Promise.all([
1017
1200
  coinlist.fetchOfferRequirements(offerId),
1018
1201
  coinlist.fetchRequirementStatuses(offerId)
@@ -1038,17 +1221,17 @@ function useCoinListRequirements(offerId) {
1038
1221
  }
1039
1222
 
1040
1223
  // src/client/hooks/useCompleteCoinListOAuth.ts
1041
- var import_react4 = require("react");
1224
+ var import_react6 = require("react");
1042
1225
  function useCompleteCoinListOAuth(options) {
1043
1226
  const { coinlist } = useCoinList();
1044
- const postOAuthCompleteRef = (0, import_react4.useRef)(options.postOAuthComplete);
1045
- const onFailureRef = (0, import_react4.useRef)(options.onFailure);
1046
- const onSuccessRef = (0, import_react4.useRef)(options.onSuccess);
1227
+ const postOAuthCompleteRef = (0, import_react6.useRef)(options.postOAuthComplete);
1228
+ const onFailureRef = (0, import_react6.useRef)(options.onFailure);
1229
+ const onSuccessRef = (0, import_react6.useRef)(options.onSuccess);
1047
1230
  postOAuthCompleteRef.current = options.postOAuthComplete;
1048
1231
  onFailureRef.current = options.onFailure;
1049
1232
  onSuccessRef.current = options.onSuccess;
1050
- const hasStartedExchangeRef = (0, import_react4.useRef)(false);
1051
- (0, import_react4.useEffect)(() => {
1233
+ const hasStartedExchangeRef = (0, import_react6.useRef)(false);
1234
+ (0, import_react6.useEffect)(() => {
1052
1235
  if (typeof window === "undefined") return;
1053
1236
  const params = new URLSearchParams(window.location.search);
1054
1237
  if (!params.has("code") && !params.has("error")) return;
@@ -1091,6 +1274,48 @@ function useCompleteCoinListOAuth(options) {
1091
1274
  }, [coinlist]);
1092
1275
  }
1093
1276
 
1277
+ // src/client/hooks/useParticipations.ts
1278
+ var import_react7 = require("react");
1279
+ var LOADING_STATE4 = { type: "LOADING" };
1280
+ function useParticipations(offerId, options = {}) {
1281
+ const { coinlist, isReady } = useCoinList();
1282
+ const { serverData } = options;
1283
+ const [participationsState, setParticipationsState] = (0, import_react7.useState)(
1284
+ serverData !== void 0 ? { type: "CONTENT", participations: serverData } : LOADING_STATE4
1285
+ );
1286
+ (0, import_react7.useEffect)(() => {
1287
+ let isCancelled = false;
1288
+ if (!isReady) {
1289
+ if (serverData === void 0) {
1290
+ setParticipationsState(LOADING_STATE4);
1291
+ }
1292
+ return () => {
1293
+ isCancelled = true;
1294
+ };
1295
+ }
1296
+ if (serverData !== void 0) {
1297
+ return () => {
1298
+ isCancelled = true;
1299
+ };
1300
+ }
1301
+ setParticipationsState(LOADING_STATE4);
1302
+ coinlist.fetchAllParticipations(offerId).then((participations) => {
1303
+ if (!isCancelled) {
1304
+ setParticipationsState({ type: "CONTENT", participations });
1305
+ }
1306
+ }).catch((error) => {
1307
+ if (!isCancelled) {
1308
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1309
+ setParticipationsState({ type: "ERROR", reason });
1310
+ }
1311
+ });
1312
+ return () => {
1313
+ isCancelled = true;
1314
+ };
1315
+ }, [coinlist, isReady, offerId, serverData]);
1316
+ return { participationsState };
1317
+ }
1318
+
1094
1319
  // src/shared/types/oauth-session.ts
1095
1320
  var OAuthRefreshToken = (value) => value;
1096
1321
  var OAuthSession = {
@@ -1158,7 +1383,10 @@ var User = {
1158
1383
  createCoinListClient,
1159
1384
  fetchAllPages,
1160
1385
  useCoinList,
1386
+ useCoinListOfferDetails,
1387
+ useCoinListOffers,
1161
1388
  useCoinListRequirements,
1162
- useCompleteCoinListOAuth
1389
+ useCompleteCoinListOAuth,
1390
+ useParticipations
1163
1391
  });
1164
1392
  //# sourceMappingURL=index.cjs.map