kryptoexpress-sdk 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,702 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ALL_CRYPTO_CURRENCIES: () => ALL_CRYPTO_CURRENCIES,
24
+ APIError: () => APIError,
25
+ AuthError: () => AuthError,
26
+ CurrencyConversionError: () => CurrencyConversionError,
27
+ FIAT_CURRENCIES: () => FIAT_CURRENCIES,
28
+ KryptoExpressClient: () => KryptoExpressClient,
29
+ MinimumAmountError: () => MinimumAmountError,
30
+ MinimumAmountPolicy: () => MinimumAmountPolicy,
31
+ NATIVE_CRYPTO_CURRENCIES: () => NATIVE_CRYPTO_CURRENCIES,
32
+ NotFoundError: () => NotFoundError,
33
+ PAYMENT_TYPES: () => PAYMENT_TYPES,
34
+ RateLimitError: () => RateLimitError,
35
+ SDKError: () => SDKError,
36
+ STABLE_CRYPTO_CURRENCIES: () => STABLE_CRYPTO_CURRENCIES,
37
+ StaticRateFiatConverter: () => StaticRateFiatConverter,
38
+ UnsupportedPaymentModeError: () => UnsupportedPaymentModeError,
39
+ ValidationError: () => ValidationError,
40
+ WITHDRAW_TYPES: () => WITHDRAW_TYPES,
41
+ assertPaymentModeSupported: () => assertPaymentModeSupported,
42
+ compactJson: () => compactJson,
43
+ computeCallbackSignature: () => computeCallbackSignature,
44
+ isStableCryptoCurrency: () => isStableCryptoCurrency,
45
+ verifyCallbackSignature: () => verifyCallbackSignature
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/core/config.ts
50
+ var DEFAULT_RETRY_STATUS_CODES = [408, 409, 429, 500, 502, 503, 504];
51
+ function resolveClientOptions(options = {}) {
52
+ const normalizedBaseUrl = (options.baseUrl ?? "https://kryptoexpress.pro/api").replace(/\/+$/, "");
53
+ return {
54
+ apiKey: options.apiKey,
55
+ baseUrl: normalizedBaseUrl,
56
+ timeoutMs: options.timeoutMs ?? 1e4,
57
+ retry: {
58
+ maxRetries: options.retry?.maxRetries ?? 2,
59
+ retryStatusCodes: options.retry?.retryStatusCodes ?? DEFAULT_RETRY_STATUS_CODES
60
+ },
61
+ fetch: options.fetch ?? globalThis.fetch,
62
+ fiatConverter: options.fiatConverter
63
+ };
64
+ }
65
+
66
+ // src/domain/errors.ts
67
+ var SDKError = class extends Error {
68
+ cause;
69
+ constructor(message, options = {}) {
70
+ super(message);
71
+ this.name = new.target.name;
72
+ this.cause = options.cause;
73
+ }
74
+ };
75
+ var ValidationError = class extends SDKError {
76
+ details;
77
+ constructor(message, options = {}) {
78
+ super(message, options);
79
+ this.details = options.details;
80
+ }
81
+ };
82
+ var UnsupportedPaymentModeError = class extends ValidationError {
83
+ };
84
+ var MinimumAmountError = class extends ValidationError {
85
+ minimumUsdAmount;
86
+ constructor(message, minimumUsdAmount = 1, options = {}) {
87
+ super(message, options);
88
+ this.minimumUsdAmount = minimumUsdAmount;
89
+ }
90
+ };
91
+ var CurrencyConversionError = class extends ValidationError {
92
+ };
93
+ var APIError = class extends SDKError {
94
+ statusCode;
95
+ code;
96
+ details;
97
+ constructor(message, statusCode, options = {}) {
98
+ super(message, options);
99
+ this.statusCode = statusCode;
100
+ this.code = options.code;
101
+ this.details = options.details;
102
+ }
103
+ };
104
+ var AuthError = class extends APIError {
105
+ };
106
+ var RateLimitError = class extends APIError {
107
+ };
108
+ var NotFoundError = class extends APIError {
109
+ };
110
+
111
+ // src/core/http.ts
112
+ var HttpClient = class {
113
+ options;
114
+ constructor(options) {
115
+ this.options = options;
116
+ }
117
+ async request(request) {
118
+ const url = buildUrl(this.options.baseUrl, request.path, request.query);
119
+ for (let attempt = 0; ; attempt += 1) {
120
+ const controller = new AbortController();
121
+ const timeout = setTimeout(() => controller.abort(), this.options.timeoutMs);
122
+ try {
123
+ const requestInit = {
124
+ method: request.method ?? "GET",
125
+ headers: this.buildHeaders(request.requiresAuth ?? false, request.body !== void 0),
126
+ signal: controller.signal
127
+ };
128
+ if (request.body !== void 0) {
129
+ requestInit.body = JSON.stringify(request.body);
130
+ }
131
+ const response = await this.options.fetch(url, requestInit);
132
+ clearTimeout(timeout);
133
+ if (!response.ok) {
134
+ if (attempt < this.options.retry.maxRetries && this.options.retry.retryStatusCodes.includes(response.status)) {
135
+ continue;
136
+ }
137
+ throw await toApiError(response);
138
+ }
139
+ if (response.status === 204) {
140
+ return void 0;
141
+ }
142
+ return await response.json();
143
+ } catch (error) {
144
+ clearTimeout(timeout);
145
+ if (!(error instanceof APIError) && attempt < this.options.retry.maxRetries) {
146
+ continue;
147
+ }
148
+ if (error instanceof Error && error.name === "AbortError") {
149
+ throw new SDKError(`Request timed out after ${this.options.timeoutMs}ms.`, { cause: error });
150
+ }
151
+ if (error instanceof SDKError) {
152
+ throw error;
153
+ }
154
+ throw new SDKError("Unexpected HTTP client error.", { cause: error });
155
+ }
156
+ }
157
+ }
158
+ buildHeaders(requiresAuth, hasJsonBody) {
159
+ const headers = new Headers();
160
+ headers.set("Accept", "application/json");
161
+ if (hasJsonBody) {
162
+ headers.set("Content-Type", "application/json");
163
+ }
164
+ if (requiresAuth) {
165
+ if (!this.options.apiKey) {
166
+ throw new AuthError("This endpoint requires an API key.", 401);
167
+ }
168
+ headers.set("X-Api-Key", this.options.apiKey);
169
+ }
170
+ return headers;
171
+ }
172
+ };
173
+ function buildUrl(baseUrl, path, query = {}) {
174
+ const url = new URL(`${baseUrl}${path}`);
175
+ for (const [key, value] of Object.entries(query)) {
176
+ if (value === void 0) {
177
+ continue;
178
+ }
179
+ url.searchParams.set(key, String(value));
180
+ }
181
+ return url.toString();
182
+ }
183
+ async function toApiError(response) {
184
+ const bodyText = await response.text();
185
+ let payload;
186
+ try {
187
+ payload = bodyText ? JSON.parse(bodyText) : void 0;
188
+ } catch {
189
+ payload = void 0;
190
+ }
191
+ const message = typeof payload?.message === "string" && payload.message || typeof payload?.error === "string" && payload.error || `Request failed with status ${response.status}.`;
192
+ const code = typeof payload?.code === "string" ? payload.code : void 0;
193
+ const options = code === void 0 ? { details: payload ?? bodyText } : { code, details: payload ?? bodyText };
194
+ if (response.status === 401 || response.status === 403) {
195
+ return new AuthError(message, response.status, options);
196
+ }
197
+ if (response.status === 404) {
198
+ return new NotFoundError(message, response.status, options);
199
+ }
200
+ if (response.status === 429) {
201
+ return new RateLimitError(message, response.status, options);
202
+ }
203
+ return new APIError(message, response.status, options);
204
+ }
205
+
206
+ // src/domain/enums.ts
207
+ var FIAT_CURRENCIES = [
208
+ "USD",
209
+ "EUR",
210
+ "GBP",
211
+ "JPY",
212
+ "CHF",
213
+ "AUD",
214
+ "CAD",
215
+ "CNY",
216
+ "HKD",
217
+ "SGD",
218
+ "SEK",
219
+ "NOK",
220
+ "DKK",
221
+ "PLN",
222
+ "CZK",
223
+ "HUF",
224
+ "TRY",
225
+ "INR",
226
+ "KRW",
227
+ "THB",
228
+ "IDR",
229
+ "MYR",
230
+ "PHP",
231
+ "VND",
232
+ "AED",
233
+ "SAR",
234
+ "ZAR",
235
+ "NGN",
236
+ "KES",
237
+ "GHS",
238
+ "BRL",
239
+ "MXN",
240
+ "ARS",
241
+ "CLP",
242
+ "COP",
243
+ "PEN",
244
+ "RUB",
245
+ "UAH",
246
+ "ILS",
247
+ "PKR",
248
+ "BDT",
249
+ "LKR",
250
+ "TWD",
251
+ "BHD",
252
+ "KWD",
253
+ "RON",
254
+ "NZD"
255
+ ];
256
+ var NATIVE_CRYPTO_CURRENCIES = ["BTC", "LTC", "ETH", "SOL", "BNB", "DOGE"];
257
+ var STABLE_CRYPTO_CURRENCIES = [
258
+ "USDC_ERC20",
259
+ "USDT_ERC20",
260
+ "USDT_BEP20",
261
+ "USDC_BEP20",
262
+ "USDT_SOL",
263
+ "USDC_SOL"
264
+ ];
265
+ var ALL_CRYPTO_CURRENCIES = [
266
+ ...NATIVE_CRYPTO_CURRENCIES,
267
+ ...STABLE_CRYPTO_CURRENCIES
268
+ ];
269
+ var PAYMENT_TYPES = ["PAYMENT", "DEPOSIT"];
270
+ var WITHDRAW_TYPES = ["ALL", "SINGLE"];
271
+ var stableCurrencySet = new Set(STABLE_CRYPTO_CURRENCIES);
272
+ function isStableCryptoCurrency(value) {
273
+ return stableCurrencySet.has(value);
274
+ }
275
+
276
+ // src/domain/conversion.ts
277
+ var StaticRateFiatConverter = class {
278
+ rates = /* @__PURE__ */ new Map();
279
+ constructor(quotes) {
280
+ for (const quote of quotes) {
281
+ this.rates.set(`${quote.from}:${quote.to}`, quote.rate);
282
+ }
283
+ }
284
+ convert(amount, from, to) {
285
+ if (from === to) {
286
+ return Promise.resolve(amount);
287
+ }
288
+ const direct = this.rates.get(`${from}:${to}`);
289
+ if (direct !== void 0) {
290
+ return Promise.resolve(amount * direct);
291
+ }
292
+ const inverse = this.rates.get(`${to}:${from}`);
293
+ if (inverse !== void 0 && inverse !== 0) {
294
+ return Promise.resolve(amount / inverse);
295
+ }
296
+ throw new CurrencyConversionError(`No fiat conversion rate available for ${from} -> ${to}.`);
297
+ }
298
+ };
299
+ var MinimumAmountPolicy = class {
300
+ converter;
301
+ minimumUsdAmount;
302
+ constructor(options = {}) {
303
+ this.converter = options.converter;
304
+ this.minimumUsdAmount = options.minimumUsdAmount ?? 1;
305
+ }
306
+ async assertFiatAmountEligible(amount, fiatCurrency) {
307
+ if (amount <= 0) {
308
+ throw new MinimumAmountError("Payment amount must be greater than zero.", this.minimumUsdAmount);
309
+ }
310
+ if (fiatCurrency !== "USD") {
311
+ return;
312
+ }
313
+ const amountInUsd = amount;
314
+ if (amountInUsd < this.minimumUsdAmount) {
315
+ throw new MinimumAmountError(
316
+ `Payment amount must be at least the fiat equivalent of ${this.minimumUsdAmount} USD.`,
317
+ this.minimumUsdAmount,
318
+ { details: { amount, fiatCurrency, amountInUsd } }
319
+ );
320
+ }
321
+ }
322
+ };
323
+ function assertPaymentModeSupported(paymentType, cryptoCurrency) {
324
+ if (paymentType === "DEPOSIT" && isStableCryptoCurrency(cryptoCurrency)) {
325
+ throw new UnsupportedPaymentModeError(
326
+ `Stablecoin ${cryptoCurrency} is not supported for DEPOSIT payments.`
327
+ );
328
+ }
329
+ }
330
+
331
+ // src/core/validation.ts
332
+ function assertObject(value, label) {
333
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
334
+ throw new ValidationError(`${label} must be an object.`, { details: value });
335
+ }
336
+ return value;
337
+ }
338
+ function assertString(value, label) {
339
+ if (typeof value !== "string") {
340
+ throw new ValidationError(`${label} must be a string.`, { details: value });
341
+ }
342
+ return value;
343
+ }
344
+ function assertNumberOrNull(value, label) {
345
+ if (value === null) {
346
+ return null;
347
+ }
348
+ if (typeof value !== "number" || Number.isNaN(value)) {
349
+ throw new ValidationError(`${label} must be a number or null.`, { details: value });
350
+ }
351
+ return value;
352
+ }
353
+ function assertNumber(value, label) {
354
+ if (typeof value !== "number" || Number.isNaN(value)) {
355
+ throw new ValidationError(`${label} must be a number.`, { details: value });
356
+ }
357
+ return value;
358
+ }
359
+ function assertBoolean(value, label) {
360
+ if (typeof value !== "boolean") {
361
+ throw new ValidationError(`${label} must be a boolean.`, { details: value });
362
+ }
363
+ return value;
364
+ }
365
+ function parsePaymentRecord(value) {
366
+ const record = assertObject(value, "payment");
367
+ const paymentType = assertString(record.paymentType, "payment.paymentType");
368
+ if (!PAYMENT_TYPES.includes(paymentType)) {
369
+ throw new ValidationError("payment.paymentType is invalid.", { details: paymentType });
370
+ }
371
+ return {
372
+ id: assertNumber(record.id, "payment.id"),
373
+ paymentType,
374
+ fiatCurrency: assertString(record.fiatCurrency, "payment.fiatCurrency"),
375
+ fiatAmount: assertNumberOrNull(record.fiatAmount, "payment.fiatAmount"),
376
+ cryptoAmount: assertNumberOrNull(record.cryptoAmount, "payment.cryptoAmount"),
377
+ cryptoCurrency: assertString(
378
+ record.cryptoCurrency,
379
+ "payment.cryptoCurrency"
380
+ ),
381
+ expireDatetime: assertNumber(record.expireDatetime, "payment.expireDatetime"),
382
+ createDatetime: assertNumber(record.createDatetime, "payment.createDatetime"),
383
+ paidAt: assertNumberOrNull(record.paidAt, "payment.paidAt"),
384
+ address: assertString(record.address, "payment.address"),
385
+ isPaid: assertBoolean(record.isPaid, "payment.isPaid"),
386
+ isWithdrawn: assertBoolean(record.isWithdrawn, "payment.isWithdrawn"),
387
+ hash: assertString(record.hash, "payment.hash"),
388
+ callbackUrl: record.callbackUrl === null ? null : assertString(record.callbackUrl, "payment.callbackUrl")
389
+ };
390
+ }
391
+ function parseWalletBalances(value) {
392
+ const record = assertObject(value, "wallet");
393
+ const result = {};
394
+ for (const [currency, amount] of Object.entries(record)) {
395
+ result[currency] = assertNumber(amount, `wallet.${currency}`);
396
+ }
397
+ return result;
398
+ }
399
+ function parseWithdrawalResponse(value) {
400
+ const record = assertObject(value, "withdrawal");
401
+ const withdrawType = assertString(record.withdrawType, "withdrawal.withdrawType");
402
+ if (!WITHDRAW_TYPES.includes(withdrawType)) {
403
+ throw new ValidationError("withdrawal.withdrawType is invalid.", { details: withdrawType });
404
+ }
405
+ const txIdList = record.txIdList;
406
+ if (!Array.isArray(txIdList) || txIdList.some((item) => typeof item !== "string")) {
407
+ throw new ValidationError("withdrawal.txIdList must be a string array.", { details: txIdList });
408
+ }
409
+ return {
410
+ id: assertNumber(record.id, "withdrawal.id"),
411
+ withdrawType,
412
+ paymentId: record.paymentId === null ? null : assertNumber(record.paymentId, "withdrawal.paymentId"),
413
+ cryptoCurrency: assertString(
414
+ record.cryptoCurrency,
415
+ "withdrawal.cryptoCurrency"
416
+ ),
417
+ toAddress: assertString(record.toAddress, "withdrawal.toAddress"),
418
+ txIdList,
419
+ receivingAmount: assertNumber(record.receivingAmount, "withdrawal.receivingAmount"),
420
+ blockchainFeeAmount: assertNumber(
421
+ record.blockchainFeeAmount,
422
+ "withdrawal.blockchainFeeAmount"
423
+ ),
424
+ serviceFeeAmount: assertNumber(record.serviceFeeAmount, "withdrawal.serviceFeeAmount"),
425
+ onlyCalculate: assertBoolean(record.onlyCalculate, "withdrawal.onlyCalculate"),
426
+ totalWithdrawalAmount: assertNumber(
427
+ record.totalWithdrawalAmount,
428
+ "withdrawal.totalWithdrawalAmount"
429
+ ),
430
+ createDatetime: assertNumber(record.createDatetime, "withdrawal.createDatetime")
431
+ };
432
+ }
433
+ function parseStringArray(value, label) {
434
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
435
+ throw new ValidationError(`${label} must be a string array.`, { details: value });
436
+ }
437
+ return value;
438
+ }
439
+ function parseCryptoPrices(value) {
440
+ if (!Array.isArray(value)) {
441
+ throw new ValidationError("prices must be an array.", { details: value });
442
+ }
443
+ const items = value;
444
+ return items.map((item, index) => {
445
+ const record = assertObject(item, `prices[${index}]`);
446
+ return {
447
+ cryptoCurrency: assertString(record.cryptoCurrency, `prices[${index}].cryptoCurrency`),
448
+ fiatCurrency: assertString(record.fiatCurrency, `prices[${index}].fiatCurrency`),
449
+ price: assertNumber(record.price, `prices[${index}].price`)
450
+ };
451
+ });
452
+ }
453
+
454
+ // src/resources/currencies.ts
455
+ var CurrenciesResource = class {
456
+ httpClient;
457
+ constructor(httpClient) {
458
+ this.httpClient = httpClient;
459
+ }
460
+ async listNative() {
461
+ const response = await this.httpClient.request({
462
+ path: "/cryptocurrency"
463
+ });
464
+ return parseStringArray(response, "cryptocurrency");
465
+ }
466
+ async listAll() {
467
+ const response = await this.httpClient.request({
468
+ path: "/cryptocurrency/all"
469
+ });
470
+ return parseStringArray(response, "cryptocurrency/all");
471
+ }
472
+ async listStable() {
473
+ const response = await this.httpClient.request({
474
+ path: "/cryptocurrency/stable"
475
+ });
476
+ return parseStringArray(response, "cryptocurrency/stable");
477
+ }
478
+ async getPrices(input) {
479
+ if (input.cryptoCurrency.length === 0) {
480
+ throw new ValidationError("At least one cryptoCurrency is required.", { details: input });
481
+ }
482
+ const response = await this.httpClient.request({
483
+ path: "/cryptocurrency/price",
484
+ query: {
485
+ cryptoCurrency: input.cryptoCurrency.join(","),
486
+ fiatCurrency: input.fiatCurrency
487
+ }
488
+ });
489
+ return parseCryptoPrices(response);
490
+ }
491
+ };
492
+
493
+ // src/resources/fiat.ts
494
+ var FiatResource = class {
495
+ httpClient;
496
+ constructor(httpClient) {
497
+ this.httpClient = httpClient;
498
+ }
499
+ async list() {
500
+ const response = await this.httpClient.request({
501
+ path: "/currency"
502
+ });
503
+ return parseStringArray(response, "currency");
504
+ }
505
+ };
506
+
507
+ // src/resources/payments.ts
508
+ var PaymentsResource = class {
509
+ httpClient;
510
+ minimumAmountPolicy;
511
+ constructor(httpClient, minimumAmountPolicy) {
512
+ this.httpClient = httpClient;
513
+ this.minimumAmountPolicy = minimumAmountPolicy;
514
+ }
515
+ async create(input) {
516
+ if (input.paymentType === "PAYMENT") {
517
+ return this.createPayment(input);
518
+ }
519
+ return this.createDeposit(input);
520
+ }
521
+ async createPayment(input) {
522
+ const request = {
523
+ ...input,
524
+ paymentType: "PAYMENT"
525
+ };
526
+ if (request.fiatAmount <= 0) {
527
+ throw new ValidationError("fiatAmount must be greater than zero.", { details: request });
528
+ }
529
+ assertPaymentModeSupported(request.paymentType, request.cryptoCurrency);
530
+ await this.minimumAmountPolicy.assertFiatAmountEligible(request.fiatAmount, request.fiatCurrency);
531
+ const response = await this.httpClient.request({
532
+ path: "/payment",
533
+ method: "POST",
534
+ body: request,
535
+ requiresAuth: true
536
+ });
537
+ return parsePaymentRecord(response);
538
+ }
539
+ async createDeposit(input) {
540
+ const request = {
541
+ ...input,
542
+ paymentType: "DEPOSIT"
543
+ };
544
+ if (isStableCryptoCurrency(request.cryptoCurrency)) {
545
+ throw new UnsupportedPaymentModeError(
546
+ `Stablecoin ${request.cryptoCurrency} supports only PAYMENT, not DEPOSIT.`,
547
+ { details: request }
548
+ );
549
+ }
550
+ const response = await this.httpClient.request({
551
+ path: "/payment",
552
+ method: "POST",
553
+ body: request,
554
+ requiresAuth: true
555
+ });
556
+ return parsePaymentRecord(response);
557
+ }
558
+ async getByHash(hash) {
559
+ if (!hash) {
560
+ throw new ValidationError("hash is required.");
561
+ }
562
+ const response = await this.httpClient.request({
563
+ path: "/payment",
564
+ query: { hash },
565
+ requiresAuth: false
566
+ });
567
+ return parsePaymentRecord(response);
568
+ }
569
+ };
570
+
571
+ // src/resources/wallet.ts
572
+ var WalletResource = class {
573
+ httpClient;
574
+ constructor(httpClient) {
575
+ this.httpClient = httpClient;
576
+ }
577
+ async get() {
578
+ const response = await this.httpClient.request({
579
+ path: "/wallet",
580
+ requiresAuth: true
581
+ });
582
+ return parseWalletBalances(response);
583
+ }
584
+ async withdraw(input) {
585
+ this.assertWithdrawalInput(input);
586
+ const response = await this.httpClient.request({
587
+ path: "/wallet/withdrawal",
588
+ method: "POST",
589
+ body: input,
590
+ requiresAuth: true
591
+ });
592
+ return parseWithdrawalResponse(response);
593
+ }
594
+ async calculate(input) {
595
+ return this.withdraw({
596
+ ...input,
597
+ onlyCalculate: true
598
+ });
599
+ }
600
+ async withdrawAll(input) {
601
+ return this.withdraw({
602
+ ...input,
603
+ withdrawType: "ALL",
604
+ onlyCalculate: false
605
+ });
606
+ }
607
+ async withdrawSingle(input) {
608
+ return this.withdraw({
609
+ ...input,
610
+ withdrawType: "SINGLE",
611
+ onlyCalculate: false
612
+ });
613
+ }
614
+ async calculateAll(input) {
615
+ return this.calculate({
616
+ ...input,
617
+ withdrawType: "ALL"
618
+ });
619
+ }
620
+ async calculateSingle(input) {
621
+ return this.calculate({
622
+ ...input,
623
+ withdrawType: "SINGLE"
624
+ });
625
+ }
626
+ assertWithdrawalInput(input) {
627
+ if (!input.toAddress) {
628
+ throw new ValidationError("toAddress is required.", { details: input });
629
+ }
630
+ if (input.withdrawType === "SINGLE" && typeof input.paymentId !== "number") {
631
+ throw new ValidationError("paymentId is required for SINGLE withdrawals.", {
632
+ details: input
633
+ });
634
+ }
635
+ }
636
+ };
637
+
638
+ // src/client.ts
639
+ var KryptoExpressClient = class {
640
+ payments;
641
+ wallet;
642
+ currencies;
643
+ fiat;
644
+ constructor(options = {}) {
645
+ const resolved = resolveClientOptions(options);
646
+ const httpClient = new HttpClient(resolved);
647
+ const minimumAmountPolicy = resolved.fiatConverter ? new MinimumAmountPolicy({ converter: resolved.fiatConverter }) : new MinimumAmountPolicy();
648
+ this.payments = new PaymentsResource(httpClient, minimumAmountPolicy);
649
+ this.wallet = new WalletResource(httpClient);
650
+ this.currencies = new CurrenciesResource(httpClient);
651
+ this.fiat = new FiatResource(httpClient);
652
+ }
653
+ };
654
+
655
+ // src/webhooks/signature.ts
656
+ var import_node_crypto = require("crypto");
657
+ function compactJson(rawBody) {
658
+ return JSON.stringify(JSON.parse(rawBody));
659
+ }
660
+ function computeCallbackSignature(rawBody, callbackSecret) {
661
+ const compactBody = compactJson(rawBody);
662
+ return (0, import_node_crypto.createHmac)("sha512", callbackSecret).update(compactBody).digest("hex");
663
+ }
664
+ function verifyCallbackSignature(input) {
665
+ if (!input.signature) {
666
+ return false;
667
+ }
668
+ const expectedSignature = computeCallbackSignature(input.rawBody, input.callbackSecret);
669
+ const actual = Buffer.from(input.signature, "hex");
670
+ const expected = Buffer.from(expectedSignature, "hex");
671
+ if (actual.length !== expected.length) {
672
+ return false;
673
+ }
674
+ return (0, import_node_crypto.timingSafeEqual)(actual, expected);
675
+ }
676
+ // Annotate the CommonJS export names for ESM import in node:
677
+ 0 && (module.exports = {
678
+ ALL_CRYPTO_CURRENCIES,
679
+ APIError,
680
+ AuthError,
681
+ CurrencyConversionError,
682
+ FIAT_CURRENCIES,
683
+ KryptoExpressClient,
684
+ MinimumAmountError,
685
+ MinimumAmountPolicy,
686
+ NATIVE_CRYPTO_CURRENCIES,
687
+ NotFoundError,
688
+ PAYMENT_TYPES,
689
+ RateLimitError,
690
+ SDKError,
691
+ STABLE_CRYPTO_CURRENCIES,
692
+ StaticRateFiatConverter,
693
+ UnsupportedPaymentModeError,
694
+ ValidationError,
695
+ WITHDRAW_TYPES,
696
+ assertPaymentModeSupported,
697
+ compactJson,
698
+ computeCallbackSignature,
699
+ isStableCryptoCurrency,
700
+ verifyCallbackSignature
701
+ });
702
+ //# sourceMappingURL=index.cjs.map