@coinlist-co/react 0.2.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 (67) hide show
  1. package/dist/RequirementItem-B-MvcxSr.d.cts +37 -0
  2. package/dist/RequirementItem-DcYot2uC.d.ts +37 -0
  3. package/dist/chunk-EHZ6PIGN.js +414 -0
  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 +473 -10
  12. package/dist/client/components/index.cjs.map +1 -1
  13. package/dist/client/components/index.d.cts +80 -12
  14. package/dist/client/components/index.d.ts +80 -12
  15. package/dist/client/components/index.js +243 -243
  16. package/dist/client/components/index.js.map +1 -1
  17. package/dist/client/core/index.cjs +349 -202
  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 +16 -14
  22. package/dist/client/hooks/index.cjs +133 -16
  23. package/dist/client/hooks/index.cjs.map +1 -1
  24. package/dist/client/hooks/index.d.cts +102 -8
  25. package/dist/client/hooks/index.d.ts +102 -8
  26. package/dist/client/hooks/index.js +11 -9
  27. package/dist/client/index.cjs +591 -210
  28. package/dist/client/index.cjs.map +1 -1
  29. package/dist/client/index.d.cts +7 -6
  30. package/dist/client/index.d.ts +7 -6
  31. package/dist/client/index.js +41 -17
  32. package/dist/client/styles.css +1 -1
  33. package/dist/coinlist-client-BSxpqylo.d.ts +158 -0
  34. package/dist/coinlist-client-Cah5c_aF.d.cts +158 -0
  35. package/dist/participation-DMMEDxON.d.cts +185 -0
  36. package/dist/participation-E-bT-GXJ.d.ts +185 -0
  37. package/dist/requirement-XWT0T_zO.d.cts +205 -0
  38. package/dist/requirement-XWT0T_zO.d.ts +205 -0
  39. package/dist/server/index.cjs +519 -14
  40. package/dist/server/index.cjs.map +1 -1
  41. package/dist/server/index.d.cts +73 -4
  42. package/dist/server/index.d.ts +73 -4
  43. package/dist/server/index.js +116 -20
  44. package/dist/server/index.js.map +1 -1
  45. package/dist/useCoinListRequirements-B5-ZPOMz.d.ts +80 -0
  46. package/dist/useCoinListRequirements-Cuc32Tqw.d.cts +80 -0
  47. package/package.json +4 -4
  48. package/dist/chunk-32GOUV3L.js +0 -118
  49. package/dist/chunk-32GOUV3L.js.map +0 -1
  50. package/dist/chunk-G3B4RLXP.js +0 -76
  51. package/dist/chunk-G3B4RLXP.js.map +0 -1
  52. package/dist/chunk-GRVV7NLV.js +0 -282
  53. package/dist/chunk-GRVV7NLV.js.map +0 -1
  54. package/dist/chunk-Z5RFQOMS.js +0 -560
  55. package/dist/chunk-Z5RFQOMS.js.map +0 -1
  56. package/dist/coinlist-client-20v7fJSW.d.ts +0 -394
  57. package/dist/coinlist-client-Ds86ycAg.d.cts +0 -394
  58. package/dist/newtype-yKTvFdg_.d.cts +0 -6
  59. package/dist/newtype-yKTvFdg_.d.ts +0 -6
  60. package/dist/oauth-session-DgItaMKN.d.cts +0 -56
  61. package/dist/oauth-session-DnKDI5ou.d.ts +0 -56
  62. package/dist/offer-D6p_Ijme.d.cts +0 -30
  63. package/dist/offer-DnFEFJw9.d.ts +0 -30
  64. package/dist/useCoinListOffers-DIdOb5hB.d.ts +0 -27
  65. package/dist/useCoinListOffers-DvJxu6qj.d.cts +0 -27
  66. package/dist/useCompleteCoinListOAuth-C359mp_k.d.cts +0 -55
  67. package/dist/useCompleteCoinListOAuth-wZX3o8r2.d.ts +0 -55
@@ -22,6 +22,7 @@ var client_exports = {};
22
22
  __export(client_exports, {
23
23
  AuthorizationCode: () => AuthorizationCode,
24
24
  Blockchain: () => Blockchain,
25
+ ChecklistStatus: () => ChecklistStatus,
25
26
  ClientId: () => ClientId,
26
27
  ClientSecret: () => ClientSecret,
27
28
  CodeChallenge: () => CodeChallenge,
@@ -45,7 +46,13 @@ __export(client_exports, {
45
46
  PaginationParams: () => PaginationParams,
46
47
  Participation: () => Participation,
47
48
  ParticipationId: () => ParticipationId,
49
+ ParticipationsPaginationParams: () => ParticipationsPaginationParams,
48
50
  RedirectUri: () => RedirectUri,
51
+ Requirement: () => Requirement,
52
+ RequirementId: () => RequirementId,
53
+ RequirementStatus: () => RequirementStatus,
54
+ RequirementStatusInfo: () => RequirementStatusInfo,
55
+ RequirementVariant: () => RequirementVariant,
49
56
  TermItem: () => TermItem,
50
57
  User: () => User,
51
58
  UserEmail: () => UserEmail,
@@ -54,13 +61,94 @@ __export(client_exports, {
54
61
  createCoinListClient: () => createCoinListClient,
55
62
  fetchAllPages: () => fetchAllPages,
56
63
  useCoinList: () => useCoinList,
57
- useCompleteCoinListOAuth: () => useCompleteCoinListOAuth
64
+ useCoinListOfferDetails: () => useCoinListOfferDetails,
65
+ useCoinListOffers: () => useCoinListOffers,
66
+ useCoinListRequirements: () => useCoinListRequirements,
67
+ useCompleteCoinListOAuth: () => useCompleteCoinListOAuth,
68
+ useParticipations: () => useParticipations
58
69
  });
59
70
  module.exports = __toCommonJS(client_exports);
60
71
 
61
72
  // src/client/CoinListProvider.tsx
62
73
  var import_react = require("react");
63
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
+
64
152
  // src/shared/api/http-attributes.ts
65
153
  var empty = {};
66
154
  var concat = (left, right) => ({
@@ -106,24 +194,28 @@ var Attributes = {
106
194
  wasRenewAttempted
107
195
  };
108
196
 
109
- // src/client/core/api/middleware/attach-session-middleware.ts
110
- function attachSessionMiddleware(fetchAccessToken) {
111
- return async (request) => {
112
- if (!Attributes.isProtected(request.attributes)) {
113
- return request;
114
- }
115
- const accessToken = await fetchAccessToken(false);
116
- if (accessToken === null) {
117
- 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
118
208
  }
119
- return {
120
- ...request,
121
- headers: {
122
- ...request.headers ?? {},
123
- Authorization: `Bearer ${accessToken.value}`
124
- }
125
- };
126
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})`;
127
219
  }
128
220
 
129
221
  // src/shared/api/http.ts
@@ -224,124 +316,6 @@ var Request = {
224
316
  concatAttributes
225
317
  };
226
318
 
227
- // src/client/core/api/middleware/session-renewal.ts
228
- function renewSessionMiddleware(fetchAccessToken) {
229
- return async ({ request, response, retry }) => {
230
- if (response.status !== 401) {
231
- return response;
232
- }
233
- if (!Attributes.isProtected(request.attributes)) {
234
- return response;
235
- }
236
- if (Attributes.wasRenewAttempted(request.attributes)) {
237
- return response;
238
- }
239
- const newToken = await fetchAccessToken(true);
240
- if (newToken) {
241
- const nextRequest = Request.concatAttributes(
242
- request,
243
- Attributes.renewAttempted(true)
244
- );
245
- return retry(nextRequest);
246
- } else {
247
- return response;
248
- }
249
- };
250
- }
251
-
252
- // src/shared/utils.ts
253
- async function sha256(data) {
254
- const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
255
- const buffer = bytes.buffer.slice(
256
- bytes.byteOffset,
257
- bytes.byteOffset + bytes.byteLength
258
- );
259
- return crypto.subtle.digest("SHA-256", buffer);
260
- }
261
- function arrayBufferToBase64Url(buffer, padding = true) {
262
- const bytes = new Uint8Array(buffer);
263
- let binary = "";
264
- for (let i = 0; i < bytes.length; i++) {
265
- binary += String.fromCharCode(bytes[i]);
266
- }
267
- let base64 = btoa(binary);
268
- base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
269
- if (!padding) {
270
- base64 = base64.replace(/=+$/, "");
271
- }
272
- return base64;
273
- }
274
- function generateSecureRandomBase64Url(byteLength) {
275
- const bytes = new Uint8Array(byteLength);
276
- crypto.getRandomValues(bytes);
277
- const buffer = bytes.buffer;
278
- return arrayBufferToBase64Url(buffer, false);
279
- }
280
- function getUUIDv4() {
281
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
282
- return crypto.randomUUID();
283
- }
284
- if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
285
- const bytes = new Uint8Array(16);
286
- crypto.getRandomValues(bytes);
287
- bytes[6] = bytes[6] & 15 | 64;
288
- bytes[8] = bytes[8] & 63 | 128;
289
- const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
290
- 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("")}`;
291
- }
292
- return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
293
- }
294
- function notBlankStringOrNull(value) {
295
- if (value?.trim()) {
296
- return value;
297
- } else {
298
- return null;
299
- }
300
- }
301
-
302
- // src/client/core/api/middleware/device-id.ts
303
- var DEVICE_ID_KEY = "coinlist.device_id";
304
- function getDeviceId() {
305
- let deviceId = localStorage.getItem(DEVICE_ID_KEY);
306
- if (!deviceId) {
307
- deviceId = getUUIDv4();
308
- localStorage.setItem(DEVICE_ID_KEY, deviceId);
309
- }
310
- return deviceId;
311
- }
312
-
313
- // src/shared/api/frontline.ts
314
- var PUBLIC_API_BASE_URL = "https://api.coinlist.co";
315
- var HEADER_API_VERSION = "X-API-Version";
316
- var HEADER_USER_AGENT = "User-Agent";
317
- var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
318
- var API_VERSION = "2025-10-17";
319
- var COINLIST_OAUTH_PAGE_URL = "https://coinlist.co/oauth/authorize";
320
-
321
- // src/client/core/api/middleware/user-agent.ts
322
- var userAgentMiddleware = async (request) => {
323
- if (!Attributes.needUserAgent(request.attributes)) {
324
- return request;
325
- }
326
- const userAgent2 = generateUserAgent();
327
- return {
328
- ...request,
329
- headers: {
330
- ...request.headers ?? {},
331
- [HEADER_USER_AGENT]: userAgent2
332
- }
333
- };
334
- };
335
- function generateUserAgent() {
336
- const appInfo = `CoinList/1.0`;
337
- const deviceInfo = "Web Browser";
338
- const devicePlatform = "DevicePlatform web";
339
- const deviceAppId = "DeviceAppID co.coinlist.sdk";
340
- const deviceId = getDeviceId();
341
- const finalDeviceId = `DeviceID ${deviceId}`;
342
- return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;
343
- }
344
-
345
319
  // src/shared/api/http-client.ts
346
320
  var HttpClient = class {
347
321
  constructor(config, middleware = {}) {
@@ -411,6 +385,26 @@ var HttpClient = class {
411
385
  }
412
386
  };
413
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
+
414
408
  // src/shared/api/middleware/idempotency-key.ts
415
409
  var idempotencyKeyMiddleware = async (request) => {
416
410
  if (!Attributes.isIdempotent(request.attributes)) {
@@ -464,19 +458,42 @@ function defaultDelay(ms) {
464
458
  }
465
459
  var requestRetryMiddleware = createRequestRetryMiddleware();
466
460
 
467
- // src/client/core/api/api-client.ts
468
- var ApiClient = class {
469
- constructor(config, fetchAccessToken) {
470
- this.config = config;
471
- this.fetchAccessToken = fetchAccessToken;
472
- 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, {
473
490
  beforeRequest: [
474
- attachSessionMiddleware(this.fetchAccessToken),
475
- userAgentMiddleware,
491
+ attachSessionMiddleware(fetchAccessToken),
492
+ ...additionalBeforeRequest,
476
493
  idempotencyKeyMiddleware
477
494
  ],
478
495
  afterRequest: [
479
- renewSessionMiddleware(this.fetchAccessToken),
496
+ renewSessionMiddleware(fetchAccessToken),
480
497
  requestRetryMiddleware
481
498
  ]
482
499
  });
@@ -491,15 +508,29 @@ var ApiClient = class {
491
508
  }
492
509
  };
493
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
+
494
523
  // src/shared/api/pagination.ts
495
524
  var Cursor = (value) => value;
496
- async function fetchAllPages(fetchPage) {
525
+ async function fetchAllPages(fetchPage, baseParams) {
497
526
  const items = [];
498
527
  let cursor = null;
499
528
  do {
500
- const page = await fetchPage({
529
+ const params = {
530
+ ...baseParams ?? {},
501
531
  after: cursor ?? void 0
502
- });
532
+ };
533
+ const page = await fetchPage(params);
503
534
  items.push(...page.data);
504
535
  cursor = page.startingAfter;
505
536
  } while (cursor);
@@ -528,22 +559,6 @@ var PaginationParams = {
528
559
  }
529
560
  };
530
561
 
531
- // src/shared/types/errors.ts
532
- var NotAuthenticatedError = class extends Error {
533
- constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
534
- super(message);
535
- this.name = "NotAuthenticatedError";
536
- }
537
- };
538
-
539
- // src/shared/types/oauth.ts
540
- var AuthorizationCode = (value) => value;
541
- var CodeVerifier = (value) => value;
542
- var CodeChallenge = (value) => value;
543
- var RedirectUri = (value) => value;
544
- var ClientId = (value) => value;
545
- var ClientSecret = (value) => value;
546
-
547
562
  // src/shared/types/offer.ts
548
563
  var OfferId = (value) => value;
549
564
  var OfferSlug = (value) => value;
@@ -653,10 +668,44 @@ var Milestone = {
653
668
  })
654
669
  };
655
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
+
656
694
  // src/shared/types/participation.ts
657
695
  var ParticipationId = (value) => value;
658
696
  var Blockchain = (value) => value;
659
697
  var WalletAddress = (value) => value;
698
+ var ParticipationsPaginationParams = {
699
+ toQueryParams: (params) => {
700
+ const queryParams = PaginationParams.toQueryParams(params);
701
+ if (params.offerId) {
702
+ queryParams["filters[0][field]"] = "offer_id";
703
+ queryParams["filters[0][op]"] = "==";
704
+ queryParams["filters[0][value]"] = params.offerId;
705
+ }
706
+ return queryParams;
707
+ }
708
+ };
660
709
  var Participation = {
661
710
  /** Maps API DTO shape into the SDK participation domain model. */
662
711
  fromDto: (dto) => {
@@ -689,6 +738,95 @@ var CreateParticipationParams = {
689
738
  })
690
739
  };
691
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
+
775
+ // src/shared/types/requirement.ts
776
+ var RequirementId = (value) => value;
777
+ var Requirement = {
778
+ fromDto: (dto) => ({
779
+ id: RequirementId(dto.id),
780
+ type: dto.type,
781
+ details: dto.details
782
+ })
783
+ };
784
+ var RequirementStatusInfo = {
785
+ fromStatusesDto: (dto) => Object.entries(dto.statuses).map(([id, status]) => ({
786
+ id: RequirementId(id),
787
+ status
788
+ }))
789
+ };
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
+
692
830
  // src/client/core/coinlist-client.ts
693
831
  var OAUTH_STATE_KEY = "coinlist.oauth_state";
694
832
  var OAUTH_CODE_VERIFIER_KEY = "coinlist.oauth_code_verifier";
@@ -741,8 +879,8 @@ var CoinListClientImpl = class {
741
879
  code_challenge_method: "S256",
742
880
  state
743
881
  });
744
- const oauthPageUrl = this._config.authorizationPageUrl ?? COINLIST_OAUTH_PAGE_URL;
745
- const url = `${oauthPageUrl}?${params.toString()}`;
882
+ const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;
883
+ const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;
746
884
  window.location.href = url;
747
885
  }
748
886
  completeOAuth() {
@@ -778,61 +916,76 @@ var CoinListClientImpl = class {
778
916
  }
779
917
  async fetchAllOffers() {
780
918
  this.ensureAuthenticated();
781
- return await fetchAllPages(this.fetchOffersPage.bind(this));
919
+ return fetchAllOffers(this.api);
782
920
  }
783
921
  async fetchOffersPage(params) {
784
922
  this.ensureAuthenticated();
785
- const pageDto = await this.api.send({
786
- method: "GET",
787
- url: "/v1/offers",
788
- queryParams: PaginationParams.toQueryParams(params),
789
- attributes: Attributes.protected()
790
- });
791
- return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
923
+ return fetchOffersPage(this.api, params);
792
924
  }
793
925
  async fetchOfferDetails(id) {
794
926
  this.ensureAuthenticated();
795
- const offerDetailDto = await this.api.send({
796
- method: "GET",
797
- url: `/v1/offers/${id}`,
798
- attributes: Attributes.protected()
799
- });
800
- return OfferDetail.fromDto(offerDetailDto);
927
+ return fetchOfferDetails(this.api, id);
801
928
  }
802
- async fetchAllParticipations() {
929
+ async fetchAllParticipations(offerId) {
803
930
  this.ensureAuthenticated();
804
- return await fetchAllPages(this.fetchParticipationsPage.bind(this));
931
+ return fetchAllParticipations(this.api, offerId);
805
932
  }
806
933
  async fetchParticipationsPage(params) {
807
934
  this.ensureAuthenticated();
808
- const pageDto = await this.api.send(
809
- {
810
- method: "GET",
811
- url: "/v1/participations",
812
- queryParams: PaginationParams.toQueryParams(params),
813
- attributes: Attributes.protected()
814
- }
815
- );
816
- return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
935
+ return fetchParticipationsPage(this.api, params);
817
936
  }
818
937
  async fetchParticipation(id) {
819
938
  this.ensureAuthenticated();
820
- const participationDto = await this.api.send({
821
- method: "GET",
822
- url: `/v1/participations/${id}`,
823
- attributes: Attributes.protected()
824
- });
825
- return Participation.fromDto(participationDto);
939
+ return fetchParticipation(this.api, id);
826
940
  }
827
941
  async createParticipation(params) {
828
942
  this.ensureAuthenticated();
829
- const participationDto = await this.api.send({
830
- method: "POST",
831
- url: "/v1/participations",
832
- body: CreateParticipationParams.toDto(params),
833
- attributes: Attributes.protected()
834
- });
835
- return Participation.fromDto(participationDto);
943
+ return createParticipation(this.api, params);
944
+ }
945
+ async fetchOfferRequirements(offerId) {
946
+ this.ensureAuthenticated();
947
+ return fetchOfferRequirements(this.api, offerId);
948
+ }
949
+ async fetchRequirementStatuses(offerId) {
950
+ this.ensureAuthenticated();
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);
836
989
  }
837
990
  ensureAuthenticated() {
838
991
  if (this.getAuthState() !== "logged-in") {
@@ -840,6 +993,9 @@ var CoinListClientImpl = class {
840
993
  }
841
994
  }
842
995
  };
996
+ function openInNewTab(url) {
997
+ window.open(url, "_blank", "noopener,noreferrer");
998
+ }
843
999
  function createCoinListClient(config) {
844
1000
  return new CoinListClientImpl(config);
845
1001
  }
@@ -873,6 +1029,43 @@ function CoinListProvider({ config, children }) {
873
1029
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CoinListContext.Provider, { value, children });
874
1030
  }
875
1031
 
1032
+ // src/client/components/requirements/RequirementItem.tsx
1033
+ var import_lucide_react = require("lucide-react");
1034
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1035
+ var RequirementVariant = {
1036
+ fromType(type) {
1037
+ switch (type) {
1038
+ case "external_wallet":
1039
+ case "whitelisted_wallet":
1040
+ return "wallet";
1041
+ default:
1042
+ return "verification";
1043
+ }
1044
+ }
1045
+ };
1046
+ var RequirementStatus = {
1047
+ fromStatusValue(status) {
1048
+ switch (status) {
1049
+ case "not_started":
1050
+ case "action_needed":
1051
+ return "required";
1052
+ case "in_progress":
1053
+ return "pending";
1054
+ case "completed":
1055
+ return "completed";
1056
+ case "rejected":
1057
+ return "rejected";
1058
+ }
1059
+ }
1060
+ };
1061
+ var ChecklistStatus = {
1062
+ derive(statuses) {
1063
+ if (statuses.some((s) => s.status === "rejected")) return "ineligible";
1064
+ if (statuses.every((s) => s.status === "completed")) return "eligible";
1065
+ return "inProgress";
1066
+ }
1067
+ };
1068
+
876
1069
  // src/client/hooks/useCoinList.ts
877
1070
  var import_react2 = require("react");
878
1071
  function useCoinList() {
@@ -892,18 +1085,153 @@ var CoinListClientInitializationError = class extends Error {
892
1085
  }
893
1086
  };
894
1087
 
895
- // src/client/hooks/useCompleteCoinListOAuth.ts
1088
+ // src/client/hooks/useCoinListOfferDetails.ts
896
1089
  var import_react3 = require("react");
1090
+ var LOADING_STATE = { type: "LOADING" };
1091
+ function useCoinListOfferDetails(offerId, options = {}) {
1092
+ const { coinlist, isReady } = useCoinList();
1093
+ const { serverData } = options;
1094
+ const [offerDetailsState, setOfferDetailsState] = (0, import_react3.useState)(
1095
+ serverData !== void 0 ? { type: "CONTENT", offerDetail: serverData } : LOADING_STATE
1096
+ );
1097
+ (0, import_react3.useEffect)(() => {
1098
+ let isCancelled = false;
1099
+ if (!isReady) {
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) {
1194
+ return () => {
1195
+ isCancelled = true;
1196
+ };
1197
+ }
1198
+ setRequirementsState(LOADING_STATE3);
1199
+ Promise.all([
1200
+ coinlist.fetchOfferRequirements(offerId),
1201
+ coinlist.fetchRequirementStatuses(offerId)
1202
+ ]).then(([requirementsByOptionId, statuses]) => {
1203
+ if (!isCancelled) {
1204
+ setRequirementsState({
1205
+ type: "CONTENT",
1206
+ requirementsByOptionId,
1207
+ statuses
1208
+ });
1209
+ }
1210
+ }).catch((error) => {
1211
+ if (!isCancelled) {
1212
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
1213
+ setRequirementsState({ type: "ERROR", reason });
1214
+ }
1215
+ });
1216
+ return () => {
1217
+ isCancelled = true;
1218
+ };
1219
+ }, [coinlist, isReady, offerId, fetchKey]);
1220
+ return { requirementsState, refetch };
1221
+ }
1222
+
1223
+ // src/client/hooks/useCompleteCoinListOAuth.ts
1224
+ var import_react6 = require("react");
897
1225
  function useCompleteCoinListOAuth(options) {
898
1226
  const { coinlist } = useCoinList();
899
- const postOAuthCompleteRef = (0, import_react3.useRef)(options.postOAuthComplete);
900
- const onFailureRef = (0, import_react3.useRef)(options.onFailure);
901
- const onSuccessRef = (0, import_react3.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);
902
1230
  postOAuthCompleteRef.current = options.postOAuthComplete;
903
1231
  onFailureRef.current = options.onFailure;
904
1232
  onSuccessRef.current = options.onSuccess;
905
- const hasStartedExchangeRef = (0, import_react3.useRef)(false);
906
- (0, import_react3.useEffect)(() => {
1233
+ const hasStartedExchangeRef = (0, import_react6.useRef)(false);
1234
+ (0, import_react6.useEffect)(() => {
907
1235
  if (typeof window === "undefined") return;
908
1236
  const params = new URLSearchParams(window.location.search);
909
1237
  if (!params.has("code") && !params.has("error")) return;
@@ -946,6 +1274,48 @@ function useCompleteCoinListOAuth(options) {
946
1274
  }, [coinlist]);
947
1275
  }
948
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
+
949
1319
  // src/shared/types/oauth-session.ts
950
1320
  var OAuthRefreshToken = (value) => value;
951
1321
  var OAuthSession = {
@@ -974,6 +1344,7 @@ var User = {
974
1344
  0 && (module.exports = {
975
1345
  AuthorizationCode,
976
1346
  Blockchain,
1347
+ ChecklistStatus,
977
1348
  ClientId,
978
1349
  ClientSecret,
979
1350
  CodeChallenge,
@@ -997,7 +1368,13 @@ var User = {
997
1368
  PaginationParams,
998
1369
  Participation,
999
1370
  ParticipationId,
1371
+ ParticipationsPaginationParams,
1000
1372
  RedirectUri,
1373
+ Requirement,
1374
+ RequirementId,
1375
+ RequirementStatus,
1376
+ RequirementStatusInfo,
1377
+ RequirementVariant,
1001
1378
  TermItem,
1002
1379
  User,
1003
1380
  UserEmail,
@@ -1006,6 +1383,10 @@ var User = {
1006
1383
  createCoinListClient,
1007
1384
  fetchAllPages,
1008
1385
  useCoinList,
1009
- useCompleteCoinListOAuth
1386
+ useCoinListOfferDetails,
1387
+ useCoinListOffers,
1388
+ useCoinListRequirements,
1389
+ useCompleteCoinListOAuth,
1390
+ useParticipations
1010
1391
  });
1011
1392
  //# sourceMappingURL=index.cjs.map