@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
@@ -0,0 +1,777 @@
1
+ // src/shared/api/pagination.ts
2
+ var Cursor = (value) => value;
3
+ async function fetchAllPages(fetchPage, baseParams) {
4
+ const items = [];
5
+ let cursor = null;
6
+ do {
7
+ const params = {
8
+ ...baseParams ?? {},
9
+ after: cursor ?? void 0
10
+ };
11
+ const page = await fetchPage(params);
12
+ items.push(...page.data);
13
+ cursor = page.startingAfter;
14
+ } while (cursor);
15
+ return items;
16
+ }
17
+ var PaginatedResponse = {
18
+ fromDto: (dto, itemMapper) => ({
19
+ data: dto.data.map(itemMapper),
20
+ startingAfter: dto.starting_after ? Cursor(dto.starting_after) : null,
21
+ startingBefore: dto.starting_before ? Cursor(dto.starting_before) : null
22
+ })
23
+ };
24
+ var PaginationParams = {
25
+ toQueryParams: (params) => {
26
+ const queryParams = {};
27
+ if (params.after) {
28
+ queryParams.starting_after = params.after;
29
+ }
30
+ if (params.before) {
31
+ queryParams.starting_before = params.before;
32
+ }
33
+ if (params.limit) {
34
+ queryParams.limit = params.limit;
35
+ }
36
+ return queryParams;
37
+ }
38
+ };
39
+
40
+ // src/shared/utils.ts
41
+ async function sha256(data) {
42
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
43
+ const buffer = bytes.buffer.slice(
44
+ bytes.byteOffset,
45
+ bytes.byteOffset + bytes.byteLength
46
+ );
47
+ return crypto.subtle.digest("SHA-256", buffer);
48
+ }
49
+ function arrayBufferToBase64Url(buffer, padding = true) {
50
+ const bytes = new Uint8Array(buffer);
51
+ let binary = "";
52
+ for (let i = 0; i < bytes.length; i++) {
53
+ binary += String.fromCharCode(bytes[i]);
54
+ }
55
+ let base64 = btoa(binary);
56
+ base64 = base64.replace(/\+/g, "-").replace(/\//g, "_");
57
+ if (!padding) {
58
+ base64 = base64.replace(/=+$/, "");
59
+ }
60
+ return base64;
61
+ }
62
+ function generateSecureRandomBase64Url(byteLength) {
63
+ const bytes = new Uint8Array(byteLength);
64
+ crypto.getRandomValues(bytes);
65
+ const buffer = bytes.buffer;
66
+ return arrayBufferToBase64Url(buffer, false);
67
+ }
68
+ function getUUIDv4() {
69
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
70
+ return crypto.randomUUID();
71
+ }
72
+ if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") {
73
+ const bytes = new Uint8Array(16);
74
+ crypto.getRandomValues(bytes);
75
+ bytes[6] = bytes[6] & 15 | 64;
76
+ bytes[8] = bytes[8] & 63 | 128;
77
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
78
+ 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("")}`;
79
+ }
80
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 12)}`;
81
+ }
82
+ function notBlankStringOrNull(value) {
83
+ if (value?.trim()) {
84
+ return value;
85
+ } else {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ // src/shared/types/offer.ts
91
+ var OfferId = (value) => value;
92
+ var OfferSlug = (value) => value;
93
+ var Offer = {
94
+ fromDto: (dto) => ({
95
+ id: OfferId(dto.id),
96
+ slug: OfferSlug(dto.slug),
97
+ tagline: notBlankStringOrNull(dto.tagline),
98
+ bannerUrl: notBlankStringOrNull(dto.banner_url),
99
+ logoUrl: notBlankStringOrNull(dto.logo_url),
100
+ startsAt: new Date(dto.starts_at),
101
+ endsAt: new Date(dto.ends_at)
102
+ })
103
+ };
104
+
105
+ // src/shared/types/asset.ts
106
+ var AssetId = (value) => value;
107
+ var AssetCode = (value) => value;
108
+ var Asset = {
109
+ fromDto: (dto) => ({
110
+ id: AssetId(dto.id),
111
+ code: AssetCode(dto.code),
112
+ name: dto.name,
113
+ fractionalDigits: dto.fractional_digits
114
+ })
115
+ };
116
+
117
+ // src/shared/types/offer-detail.ts
118
+ var OfferOptionId = (value) => value;
119
+ var OfferOptionSlug = (value) => value;
120
+ var OfferDetail = {
121
+ fromDto: (dto) => {
122
+ if (!Array.isArray(dto.funding_assets)) {
123
+ throw new Error(`funding_assets must be an array`);
124
+ }
125
+ if (!Array.isArray(dto.options)) {
126
+ throw new Error(`options must be an array`);
127
+ }
128
+ if (!Array.isArray(dto.terms)) {
129
+ throw new Error(`terms must be an array`);
130
+ }
131
+ if (!Array.isArray(dto.links)) {
132
+ throw new Error(`links must be an array`);
133
+ }
134
+ if (!Array.isArray(dto.faqs)) {
135
+ throw new Error(`faqs must be an array`);
136
+ }
137
+ if (!Array.isArray(dto.milestones)) {
138
+ throw new Error(`milestones must be an array`);
139
+ }
140
+ return {
141
+ id: OfferId(dto.id),
142
+ slug: OfferSlug(dto.slug),
143
+ name: dto.name,
144
+ asset: Asset.fromDto(dto.asset),
145
+ fundingAssets: dto.funding_assets.map(Asset.fromDto),
146
+ about: notBlankStringOrNull(dto.about),
147
+ tagline: notBlankStringOrNull(dto.tagline),
148
+ bannerUrl: notBlankStringOrNull(dto.banner_url),
149
+ logoUrl: notBlankStringOrNull(dto.logo_url),
150
+ category: notBlankStringOrNull(dto.category),
151
+ startsAt: new Date(dto.starts_at),
152
+ endsAt: new Date(dto.ends_at),
153
+ faqs: dto.faqs.map(FaqItem.fromDto),
154
+ links: dto.links.map(Link.fromDto),
155
+ milestones: dto.milestones.map(Milestone.fromDto),
156
+ options: dto.options.map(OfferOption.fromDto),
157
+ terms: dto.terms.map(TermItem.fromDto)
158
+ };
159
+ }
160
+ };
161
+ var OfferOption = {
162
+ fromDto: (dto) => ({
163
+ id: OfferOptionId(dto.id),
164
+ slug: OfferOptionSlug(dto.slug),
165
+ bidIncrement: dto.bid_increment,
166
+ floorPriceUsd: dto.floor_price_usd,
167
+ minimumPurchaseUsd: dto.minimum_purchase_usd,
168
+ priceUsd: dto.price_usd,
169
+ saleAgreementUrl: notBlankStringOrNull(dto.sale_agreement_url),
170
+ totalTokenSupply: dto.total_token_supply
171
+ })
172
+ };
173
+ var FaqItem = {
174
+ fromDto: (dto) => ({
175
+ question: notBlankStringOrNull(dto.question),
176
+ answer: notBlankStringOrNull(dto.answer)
177
+ })
178
+ };
179
+ var Link = {
180
+ fromDto: (dto) => ({
181
+ label: notBlankStringOrNull(dto.label),
182
+ url: notBlankStringOrNull(dto.url)
183
+ })
184
+ };
185
+ var TermItem = {
186
+ fromDto: (dto) => ({
187
+ key: notBlankStringOrNull(dto.key),
188
+ value: notBlankStringOrNull(dto.value)
189
+ })
190
+ };
191
+ var Milestone = {
192
+ fromDto: (dto) => ({
193
+ name: notBlankStringOrNull(dto.name),
194
+ schedule: notBlankStringOrNull(dto.schedule),
195
+ status: dto.status
196
+ })
197
+ };
198
+
199
+ // src/shared/types/participation.ts
200
+ var ParticipationId = (value) => value;
201
+ var Blockchain = (value) => value;
202
+ var WalletAddress = (value) => value;
203
+ var ParticipationsPaginationParams = {
204
+ toQueryParams: (params) => {
205
+ const queryParams = PaginationParams.toQueryParams(params);
206
+ if (params.offerId) {
207
+ queryParams["filters[0][field]"] = "offer_id";
208
+ queryParams["filters[0][op]"] = "==";
209
+ queryParams["filters[0][value]"] = params.offerId;
210
+ }
211
+ return queryParams;
212
+ }
213
+ };
214
+ var Participation = {
215
+ /** Maps API DTO shape into the SDK participation domain model. */
216
+ fromDto: (dto) => {
217
+ const walletAddress = notBlankStringOrNull(dto.wallet_address);
218
+ return {
219
+ id: ParticipationId(dto.id),
220
+ offerId: OfferId(dto.offer_id),
221
+ offerOptionId: OfferOptionId(dto.offer_option_id),
222
+ status: dto.status,
223
+ amount: dto.amount,
224
+ displayAmount: dto.amount_string,
225
+ asset: Asset.fromDto(dto.asset),
226
+ chain: Blockchain(dto.chain),
227
+ insertedAt: dto.inserted_at ? new Date(dto.inserted_at) : null,
228
+ updatedAt: dto.updated_at ? new Date(dto.updated_at) : null,
229
+ walletAddress: walletAddress ? WalletAddress(walletAddress) : null
230
+ };
231
+ }
232
+ };
233
+ var CreateParticipationParams = {
234
+ /** Maps participation creation params into API DTO payload. */
235
+ toDto: (params) => ({
236
+ offer_id: params.offerId,
237
+ offer_option_id: params.offerOptionId,
238
+ chain: params.chain,
239
+ wallet_address: params.walletAddress,
240
+ amount: params.amount,
241
+ asset_id: params.assetId,
242
+ approval_transaction_hash: params.approvalTransactionHash
243
+ })
244
+ };
245
+
246
+ // src/shared/types/requirement.ts
247
+ var RequirementId = (value) => value;
248
+ var Requirement = {
249
+ fromDto: (dto) => ({
250
+ id: RequirementId(dto.id),
251
+ type: dto.type,
252
+ details: dto.details
253
+ })
254
+ };
255
+ var RequirementStatusInfo = {
256
+ fromStatusesDto: (dto) => Object.entries(dto.statuses).map(([id, status]) => ({
257
+ id: RequirementId(id),
258
+ status
259
+ }))
260
+ };
261
+
262
+ // src/shared/types/errors.ts
263
+ var NotImplementedError = class extends Error {
264
+ constructor(message = "Not implemented yet") {
265
+ super(message);
266
+ this.name = "NotImplementedError";
267
+ }
268
+ };
269
+ var NotAuthenticatedError = class extends Error {
270
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
271
+ super(message);
272
+ this.name = "NotAuthenticatedError";
273
+ }
274
+ };
275
+
276
+ // src/shared/types/oauth.ts
277
+ var AuthorizationCode = (value) => value;
278
+ var CodeVerifier = (value) => value;
279
+ var CodeChallenge = (value) => value;
280
+ var RedirectUri = (value) => value;
281
+ var ClientId = (value) => value;
282
+ var ClientSecret = (value) => value;
283
+
284
+ // src/shared/api/frontline/index.ts
285
+ var PUBLIC_API_BASE_URL = "https://api.coinlist.co";
286
+ var HEADER_API_VERSION = "X-API-Version";
287
+ var HEADER_USER_AGENT = "User-Agent";
288
+ var HEADER_IDEMPOTENCY_KEY = "Idempotency-Key";
289
+ var API_VERSION = "2025-10-17";
290
+ var COINLIST_BASE_URL = "https://coinlist.co";
291
+ var OAUTH_PAGE_PATH = "/oauth/authorize";
292
+ var SUPPORT_NEW_TICKET_URL = "https://support.coinlist.co/support/tickets/new";
293
+ var VERIFY_IDENTITY_PATH = "/verify-identity";
294
+ var VERIFY_IDENTITY_VERIFIED_PATH = "/verify-identity/identity_verified";
295
+ var VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH = "/verify-identity/proof_of_address";
296
+ var VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH = "/verify-identity/source_of_funds";
297
+ var VERIFY_IDENTITY_ACCREDITATION_PATH = "/verify-identity/accreditation_full";
298
+ var WALLET_PATH = "/wallet";
299
+
300
+ // src/shared/api/http-attributes.ts
301
+ var empty = {};
302
+ var concat = (left, right) => ({
303
+ ...left,
304
+ ...right
305
+ });
306
+ var concatAll = (...items) => {
307
+ let result = empty;
308
+ for (const item of items) {
309
+ result = concat(result, item);
310
+ }
311
+ return result;
312
+ };
313
+ var protectedRequest = () => ({ protected: true });
314
+ var userAgent = () => ({ userAgent: true });
315
+ var idempotencyKey = () => ({
316
+ idempotencyKey: true
317
+ });
318
+ var retryAttempt = (attempt) => ({
319
+ retryAttempt: attempt
320
+ });
321
+ var renewAttempted = (value) => ({
322
+ renewAttempted: value
323
+ });
324
+ var isProtected = (attrs) => attrs?.protected === true;
325
+ var needUserAgent = (attrs) => attrs?.userAgent === true;
326
+ var isIdempotent = (attrs) => attrs?.idempotencyKey === true;
327
+ var getRetryAttempt = (attrs) => attrs?.retryAttempt ?? 0;
328
+ var wasRenewAttempted = (attrs) => attrs?.renewAttempted === true;
329
+ var Attributes = {
330
+ empty,
331
+ concat,
332
+ concatAll,
333
+ protected: protectedRequest,
334
+ isProtected,
335
+ userAgent,
336
+ needUserAgent,
337
+ idempotencyKey,
338
+ isIdempotent,
339
+ retryAttempt,
340
+ getRetryAttempt,
341
+ renewAttempted,
342
+ wasRenewAttempted
343
+ };
344
+
345
+ // src/shared/api/http.ts
346
+ var HttpError = class extends Error {
347
+ constructor(response) {
348
+ super(`Request failed with ${response.status} status`);
349
+ this.name = "HttpError";
350
+ this.response = response;
351
+ }
352
+ };
353
+ async function makeRequest(request) {
354
+ const headers = {
355
+ Accept: "application/json",
356
+ ...request.method === "POST" && request.body !== void 0 ? { "Content-Type": "application/json" } : {},
357
+ ...request.headers ?? {}
358
+ };
359
+ const init = {
360
+ method: request.method,
361
+ headers,
362
+ ...request.redirect !== void 0 ? { redirect: request.redirect } : {}
363
+ };
364
+ if (request.method === "POST" && request.body !== void 0) {
365
+ init.body = JSON.stringify(request.body);
366
+ }
367
+ const response = await fetch(
368
+ buildUrlWithQueryParams(request.url, request.queryParams),
369
+ init
370
+ );
371
+ const responseHeaders = headersToRecord(response.headers);
372
+ if (response.status === 204 || response.status === 205) {
373
+ return {
374
+ status: response.status,
375
+ body: null,
376
+ headers: responseHeaders
377
+ };
378
+ }
379
+ if (response.status >= 300 && response.status < 400) {
380
+ await response.text();
381
+ return {
382
+ status: response.status,
383
+ body: null,
384
+ headers: responseHeaders
385
+ };
386
+ }
387
+ const text = await response.text();
388
+ const body = text ? JSON.parse(text) : null;
389
+ return {
390
+ status: response.status,
391
+ body,
392
+ headers: responseHeaders
393
+ };
394
+ }
395
+ function buildUrlWithQueryParams(url, queryParams) {
396
+ if (!queryParams) {
397
+ return url;
398
+ }
399
+ const searchParams = new URLSearchParams();
400
+ for (const [key, value] of Object.entries(queryParams)) {
401
+ if (value === void 0 || value === null) {
402
+ continue;
403
+ }
404
+ if (Array.isArray(value)) {
405
+ for (const item of value) {
406
+ if (item === void 0 || item === null) {
407
+ continue;
408
+ }
409
+ searchParams.append(key, String(item));
410
+ }
411
+ continue;
412
+ }
413
+ searchParams.append(key, String(value));
414
+ }
415
+ const queryString = searchParams.toString();
416
+ if (!queryString) {
417
+ return url;
418
+ }
419
+ return url.includes("?") ? `${url}&${queryString}` : `${url}?${queryString}`;
420
+ }
421
+ function headersToRecord(headers) {
422
+ const record = {};
423
+ headers.forEach((value, key) => {
424
+ record[key.toLowerCase()] = value;
425
+ });
426
+ return record;
427
+ }
428
+ function concatAttributes(request, attrs) {
429
+ const nextAttributes = Attributes.concat(
430
+ request.attributes ?? Attributes.empty,
431
+ attrs
432
+ );
433
+ const nextRequest = {
434
+ ...request,
435
+ attributes: nextAttributes
436
+ };
437
+ return nextRequest;
438
+ }
439
+ var Request = {
440
+ concatAttributes
441
+ };
442
+
443
+ // src/shared/api/frontline/offers.ts
444
+ async function fetchAllOffers(api) {
445
+ return fetchAllPages((params) => fetchOffersPage(api, params));
446
+ }
447
+ async function fetchOffersPage(api, params) {
448
+ const queryParams = PaginationParams.toQueryParams(params);
449
+ const pageDto = await api.send({
450
+ method: "GET",
451
+ url: "/v1/offers",
452
+ queryParams,
453
+ attributes: Attributes.protected()
454
+ });
455
+ return PaginatedResponse.fromDto(pageDto, Offer.fromDto);
456
+ }
457
+ async function fetchOfferDetails(api, id) {
458
+ const dto = await api.send({
459
+ method: "GET",
460
+ url: `/v1/offers/${id}`,
461
+ attributes: Attributes.protected()
462
+ });
463
+ return OfferDetail.fromDto(dto);
464
+ }
465
+
466
+ // src/shared/api/frontline/participations.ts
467
+ async function fetchAllParticipations(api, offerId) {
468
+ return fetchAllPages(
469
+ (params) => fetchParticipationsPage(api, params),
470
+ { offerId }
471
+ );
472
+ }
473
+ async function fetchParticipationsPage(api, params) {
474
+ const pageDto = await api.send({
475
+ method: "GET",
476
+ url: "/v1/participations",
477
+ queryParams: ParticipationsPaginationParams.toQueryParams(params),
478
+ attributes: Attributes.protected()
479
+ });
480
+ return PaginatedResponse.fromDto(pageDto, Participation.fromDto);
481
+ }
482
+ async function fetchParticipation(api, id) {
483
+ const dto = await api.send({
484
+ method: "GET",
485
+ url: `/v1/participations/${id}`,
486
+ attributes: Attributes.protected()
487
+ });
488
+ return Participation.fromDto(dto);
489
+ }
490
+ async function createParticipation(api, params) {
491
+ const dto = await api.send({
492
+ method: "POST",
493
+ url: "/v1/participations",
494
+ body: CreateParticipationParams.toDto(params),
495
+ attributes: Attributes.protected()
496
+ });
497
+ return Participation.fromDto(dto);
498
+ }
499
+
500
+ // src/shared/api/frontline/requirements.ts
501
+ async function fetchOfferRequirements(api, offerId) {
502
+ const response = await api.send({
503
+ method: "GET",
504
+ url: `/v1/offers/${offerId}/requirements`,
505
+ attributes: Attributes.protected()
506
+ });
507
+ return Object.fromEntries(
508
+ Object.entries(response.options).map(([optionId, list]) => [
509
+ optionId,
510
+ list.data.map(Requirement.fromDto)
511
+ ])
512
+ );
513
+ }
514
+ async function fetchRequirementStatuses(api, offerId) {
515
+ const response = await api.send({
516
+ method: "GET",
517
+ url: `/v1/offers/${offerId}/requirements/statuses`,
518
+ attributes: Attributes.protected()
519
+ });
520
+ return RequirementStatusInfo.fromStatusesDto(response);
521
+ }
522
+
523
+ // src/shared/api/http-client.ts
524
+ var HttpClient = class {
525
+ constructor(config, middleware = {}) {
526
+ this.config = config;
527
+ this.middleware = middleware;
528
+ }
529
+ async send(request) {
530
+ return this.runRequestWithAfterMiddleware(request);
531
+ }
532
+ /**
533
+ * Runs beforeRequest, executeRequest, then the full afterRequest middleware
534
+ * chain. Used by send() and by the retry() callback so that when a
535
+ * middleware calls retry(), the retried response also goes through all
536
+ * afterRequest middleware (e.g. session renewal, retry). Middleware
537
+ * must use request.attributes.retryAttempt (or similar) to avoid infinite
538
+ * recursion when they trigger retries.
539
+ */
540
+ async runRequestWithAfterMiddleware(request) {
541
+ const preparedRequest = await this.runBeforeRequestMiddleware(
542
+ this.withClientDefaults(request)
543
+ );
544
+ let response = await this.executeRequest(preparedRequest);
545
+ for (const middleware of this.middleware.afterRequest ?? []) {
546
+ response = await middleware({
547
+ request: preparedRequest,
548
+ response,
549
+ retry: (nextRequest = preparedRequest) => this.runRequestWithAfterMiddleware(nextRequest)
550
+ });
551
+ }
552
+ return response;
553
+ }
554
+ withClientDefaults(request) {
555
+ const url = this.resolveUrl(request.url);
556
+ const headers = {
557
+ ...request.headers ?? {},
558
+ [HEADER_API_VERSION]: this.config.xApiVersion
559
+ };
560
+ return {
561
+ ...request,
562
+ url,
563
+ headers
564
+ };
565
+ }
566
+ /**
567
+ * Resolves a request URL against the client's baseUrl.
568
+ *
569
+ * @internal Public only for testing. Do not use in application code; use
570
+ * {@link HttpClient.send} with a path and the client will resolve the URL.
571
+ */
572
+ resolveUrl(url) {
573
+ if (url.startsWith("http://") || url.startsWith("https://")) {
574
+ return url;
575
+ }
576
+ const base = this.config.baseUrl.replace(/\/$/, "");
577
+ const path = url.startsWith("/") ? url : `/${url}`;
578
+ return base + path;
579
+ }
580
+ async runBeforeRequestMiddleware(initialRequest) {
581
+ let request = initialRequest;
582
+ for (const middleware of this.middleware.beforeRequest ?? []) {
583
+ request = await middleware(request);
584
+ }
585
+ return request;
586
+ }
587
+ executeRequest(request) {
588
+ return makeRequest(request);
589
+ }
590
+ };
591
+
592
+ // src/shared/api/middleware/attach-session-middleware.ts
593
+ function attachSessionMiddleware(fetchAccessToken) {
594
+ return async (request) => {
595
+ if (!Attributes.isProtected(request.attributes)) {
596
+ return request;
597
+ }
598
+ const accessToken = await fetchAccessToken(false);
599
+ if (accessToken === null) {
600
+ return request;
601
+ }
602
+ return {
603
+ ...request,
604
+ headers: {
605
+ ...request.headers ?? {},
606
+ Authorization: `Bearer ${accessToken.value}`
607
+ }
608
+ };
609
+ };
610
+ }
611
+
612
+ // src/shared/api/middleware/idempotency-key.ts
613
+ var idempotencyKeyMiddleware = async (request) => {
614
+ if (!Attributes.isIdempotent(request.attributes)) {
615
+ return request;
616
+ }
617
+ const existingHeaders = request.headers ?? {};
618
+ if (existingHeaders[HEADER_IDEMPOTENCY_KEY]) {
619
+ return request;
620
+ }
621
+ return {
622
+ ...request,
623
+ headers: {
624
+ ...existingHeaders,
625
+ [HEADER_IDEMPOTENCY_KEY]: getUUIDv4()
626
+ }
627
+ };
628
+ };
629
+
630
+ // src/shared/api/middleware/request-retry.ts
631
+ var MAX_ATTEMPTS = 3;
632
+ var INITIAL_DELAY_MS = 300;
633
+ var MAX_DELAY_MS = 2e3;
634
+ var RETRYABLE_4XX = /* @__PURE__ */ new Set([408, 409, 429]);
635
+ function isRetryableStatus(status) {
636
+ return status >= 500 && status < 600 || RETRYABLE_4XX.has(status);
637
+ }
638
+ function getRetryDelayMs(attempt) {
639
+ return Math.min(INITIAL_DELAY_MS * 2 ** (attempt - 1), MAX_DELAY_MS);
640
+ }
641
+ function createRequestRetryMiddleware(options = {}) {
642
+ const delayFn = options.delayFn ?? defaultDelay;
643
+ return async ({ request, response, retry }) => {
644
+ if (!isRetryableStatus(response.status)) {
645
+ return response;
646
+ }
647
+ const currentAttempt = Attributes.getRetryAttempt(request.attributes);
648
+ if (currentAttempt >= MAX_ATTEMPTS - 1) {
649
+ return response;
650
+ }
651
+ const nextAttempt = currentAttempt + 1;
652
+ await delayFn(getRetryDelayMs(nextAttempt));
653
+ const nextRequest = Request.concatAttributes(
654
+ request,
655
+ Attributes.retryAttempt(nextAttempt)
656
+ );
657
+ return retry(nextRequest);
658
+ };
659
+ }
660
+ function defaultDelay(ms) {
661
+ return new Promise((resolve) => setTimeout(resolve, ms));
662
+ }
663
+ var requestRetryMiddleware = createRequestRetryMiddleware();
664
+
665
+ // src/shared/api/middleware/session-renewal.ts
666
+ function renewSessionMiddleware(fetchAccessToken) {
667
+ return async ({ request, response, retry }) => {
668
+ if (response.status !== 401) {
669
+ return response;
670
+ }
671
+ if (!Attributes.isProtected(request.attributes)) {
672
+ return response;
673
+ }
674
+ if (Attributes.wasRenewAttempted(request.attributes)) {
675
+ return response;
676
+ }
677
+ const newToken = await fetchAccessToken(true);
678
+ if (newToken) {
679
+ const nextRequest = Request.concatAttributes(
680
+ request,
681
+ Attributes.renewAttempted(true)
682
+ );
683
+ return retry(nextRequest);
684
+ } else {
685
+ return response;
686
+ }
687
+ };
688
+ }
689
+
690
+ // src/shared/api/authenticated-api-client.ts
691
+ var AuthenticatedApiClient = class {
692
+ constructor(config, fetchAccessToken, additionalBeforeRequest = []) {
693
+ this.httpClient = new HttpClient(config, {
694
+ beforeRequest: [
695
+ attachSessionMiddleware(fetchAccessToken),
696
+ ...additionalBeforeRequest,
697
+ idempotencyKeyMiddleware
698
+ ],
699
+ afterRequest: [
700
+ renewSessionMiddleware(fetchAccessToken),
701
+ requestRetryMiddleware
702
+ ]
703
+ });
704
+ }
705
+ async send(request) {
706
+ const response = await this.httpClient.send(request);
707
+ if (response.status >= 200 && response.status < 300) {
708
+ return response.body;
709
+ } else {
710
+ throw new HttpError(response);
711
+ }
712
+ }
713
+ };
714
+
715
+ export {
716
+ sha256,
717
+ arrayBufferToBase64Url,
718
+ generateSecureRandomBase64Url,
719
+ getUUIDv4,
720
+ PUBLIC_API_BASE_URL,
721
+ HEADER_USER_AGENT,
722
+ API_VERSION,
723
+ COINLIST_BASE_URL,
724
+ OAUTH_PAGE_PATH,
725
+ SUPPORT_NEW_TICKET_URL,
726
+ VERIFY_IDENTITY_PATH,
727
+ VERIFY_IDENTITY_VERIFIED_PATH,
728
+ VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH,
729
+ VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH,
730
+ VERIFY_IDENTITY_ACCREDITATION_PATH,
731
+ WALLET_PATH,
732
+ Attributes,
733
+ HttpError,
734
+ AuthenticatedApiClient,
735
+ Cursor,
736
+ fetchAllPages,
737
+ PaginatedResponse,
738
+ PaginationParams,
739
+ OfferId,
740
+ OfferSlug,
741
+ Offer,
742
+ OfferOptionId,
743
+ OfferOptionSlug,
744
+ OfferDetail,
745
+ OfferOption,
746
+ FaqItem,
747
+ Link,
748
+ TermItem,
749
+ Milestone,
750
+ fetchAllOffers,
751
+ fetchOffersPage,
752
+ fetchOfferDetails,
753
+ ParticipationId,
754
+ Blockchain,
755
+ WalletAddress,
756
+ ParticipationsPaginationParams,
757
+ Participation,
758
+ CreateParticipationParams,
759
+ fetchAllParticipations,
760
+ fetchParticipationsPage,
761
+ fetchParticipation,
762
+ createParticipation,
763
+ RequirementId,
764
+ Requirement,
765
+ RequirementStatusInfo,
766
+ fetchOfferRequirements,
767
+ fetchRequirementStatuses,
768
+ NotImplementedError,
769
+ NotAuthenticatedError,
770
+ AuthorizationCode,
771
+ CodeVerifier,
772
+ CodeChallenge,
773
+ RedirectUri,
774
+ ClientId,
775
+ ClientSecret
776
+ };
777
+ //# sourceMappingURL=chunk-NC45IO63.js.map