@bitpal/checkout 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -208,7 +208,7 @@ app.get('/report', x402({
208
208
  apiKey: process.env.BITPAL_API_KEY, // bp_test_… or bp_live_…
209
209
  payTo: '0xYourPayoutWallet',
210
210
  network: 'base', // test key → 'base-sepolia'
211
- amount: '1000000', // atomic (USDC, 6dp) — your gross; the fee comes out of it
211
+ amount: '1.00', // human-readable — no decimals math
212
212
  }), (req, res) => {
213
213
  res.json({ report: '…' }); // req.x402Payment has the txHash
214
214
  });
@@ -267,6 +267,9 @@ if (res.status === 402) {
267
267
  | Base | USDC | `base` |
268
268
  | Base Sepolia | USDC | `base-sepolia` |
269
269
 
270
+ Amounts are human-readable (`'1.00'`), the same model as `line_items[].amount` — the server converts.
271
+ Pass `amountAtomic` instead if you already have raw units.
272
+
270
273
  EOA signers only — smart-contract wallets cannot sign EIP-3009 authorizations. Amounts are exact:
271
274
  over- and underpayment are both rejected, and this lane has no refund path. Authorizations are valid
272
275
  for 90–3600 seconds (the server's floor is 60s; the extra 30s absorbs clock skew and round trips).
package/dist/index.cjs CHANGED
@@ -315,12 +315,23 @@ var BitPalCheckoutClient = class {
315
315
  );
316
316
  }
317
317
  /* ─── Fees ─── */
318
- /** 수수료 미리보기 — `/v1/checkout/fee-preview` (Phase 1 credit system 폐기 후 canonical path) */
318
+ /**
319
+ * 수수료 미리보기 — `/v1/checkout/fee-preview`.
320
+ *
321
+ * `amount` 는 **사람 표기**다("100", "0.5") — line item / Price / x402 와 같은 모델이라
322
+ * decimals 를 계산할 필요가 없다. raw μUSD 를 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
323
+ * 응답은 계속 atomic 이다(계산 결과라 정밀도가 곧 계약이다).
324
+ *
325
+ * @example
326
+ * const { data } = await bp.checkout.previewFee('100'); // $100
327
+ * const { data } = await bp.checkout.previewFee({ amountAtomic: '100000000' });
328
+ */
319
329
  async previewFee(amount) {
320
- return this.request(
321
- "GET",
322
- `/v1/checkout/fee-preview?amount=${encodeURIComponent(amount)}`
323
- );
330
+ const qs = typeof amount === "string" ? `amount=${encodeURIComponent(amount)}` : `amount_atomic=${encodeURIComponent(amount.amountAtomic)}`;
331
+ if (typeof amount === "string" && !/^(0|[1-9]\d*)(\.\d{1,6})?$/.test(amount)) {
332
+ throw new Error('[BitPal] previewFee: amount must be a decimal string like "100" or "0.5" (max 6 decimals). For raw \u03BCUSD use { amountAtomic }.');
333
+ }
334
+ return this.request("GET", `/v1/checkout/fee-preview?${qs}`);
324
335
  }
325
336
  };
326
337
  var BitPalError = class extends Error {
@@ -476,8 +487,16 @@ var X402Gate = class {
476
487
  if (!/^0x[a-fA-F0-9]{40}$/.test(opts.payTo)) {
477
488
  throw new Error("[BitPal] x402: payTo must be a 0x EVM address (your registered payout wallet).");
478
489
  }
479
- if (!/^\d+$/.test(opts.amount)) {
480
- throw new Error('[BitPal] x402: amount must be an atomic integer string (USDC 6dp, $1 = "1000000").');
490
+ const hasHuman = opts.amount != null;
491
+ const hasAtomic = opts.amountAtomic != null;
492
+ if (hasHuman === hasAtomic) {
493
+ throw new Error('[BitPal] x402: provide exactly one of `amount` ("0.1") or `amountAtomic` ("100000").');
494
+ }
495
+ if (hasHuman && !/^(0|[1-9]\d*)(\.\d{1,6})?$/.test(opts.amount)) {
496
+ throw new Error('[BitPal] x402: amount must be a decimal string like "0.1" or "29" (max 6 decimals).');
497
+ }
498
+ if (hasAtomic && !/^\d+$/.test(opts.amountAtomic)) {
499
+ throw new Error('[BitPal] x402: amountAtomic must be an integer string (USDC 6dp, $1 = "1000000").');
481
500
  }
482
501
  const timeoutSeconds = opts.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
483
502
  if (timeoutSeconds < MIN_VALIDITY_SECONDS || timeoutSeconds > MAX_VALIDITY_SECONDS) {
@@ -495,7 +514,8 @@ var X402Gate = class {
495
514
  async requirements(resource) {
496
515
  return this.request("POST", "/v1/x402/requirements", {
497
516
  payTo: this.opts.payTo,
498
- amount: this.opts.amount,
517
+ // 사람 표기 → atomic 변환은 **서버가** 한다. SDK 가 decimals 를 알 필요가 없다.
518
+ ...this.opts.amount != null ? { amount: this.opts.amount } : { amountAtomic: this.opts.amountAtomic },
499
519
  resource,
500
520
  ...this.opts.network ? { network: this.opts.network } : {},
501
521
  ...this.opts.asset ? { asset: this.opts.asset } : {},
package/dist/index.d.cts CHANGED
@@ -556,8 +556,20 @@ declare class BitPalCheckoutClient {
556
556
  * 통지되므로, 서버 사이드 확정은 webhook 을 신뢰(폴링은 buyer UX 용).
557
557
  */
558
558
  getStatus(sessionId: string): Promise<ApiResponse<SessionStatus>>;
559
- /** 수수료 미리보기 — `/v1/checkout/fee-preview` (Phase 1 credit system 폐기 후 canonical path) */
560
- previewFee(amount: string): Promise<ApiResponse<FeePreview>>;
559
+ /**
560
+ * 수수료 미리보기 — `/v1/checkout/fee-preview`.
561
+ *
562
+ * `amount` 는 **사람 표기**다("100", "0.5") — line item / Price / x402 와 같은 모델이라
563
+ * decimals 를 계산할 필요가 없다. raw μUSD 를 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
564
+ * 응답은 계속 atomic 이다(계산 결과라 정밀도가 곧 계약이다).
565
+ *
566
+ * @example
567
+ * const { data } = await bp.checkout.previewFee('100'); // $100
568
+ * const { data } = await bp.checkout.previewFee({ amountAtomic: '100000000' });
569
+ */
570
+ previewFee(amount: string | {
571
+ amountAtomic: string;
572
+ }): Promise<ApiResponse<FeePreview>>;
561
573
  }
562
574
  declare class BitPalError extends Error {
563
575
  readonly statusCode: number;
@@ -785,8 +797,14 @@ interface X402GateOptions {
785
797
  apiKey: string;
786
798
  /** 정산 지갑. 콘솔에 등록한 payout 주소와 같은 값이어야 한다. */
787
799
  payTo: string;
788
- /** 호출 1건당 받을 총액(atomic). USDC 6dp 기준 $1 = `'1000000'`. 수수료는 여기서 차감된다. */
789
- amount: string;
800
+ /**
801
+ * 호출 1건당 받을 총액. **사람 표기 문자열**이다 — `'0.1'`, `'1'`, `'29.00'`.
802
+ * 체인·토큰 decimals 를 계산할 필요가 없다(체크아웃 `line_items[].amount` 와 같은 모델).
803
+ * 수수료는 이 금액에서 차감된다. raw atomic 을 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
804
+ */
805
+ amount?: string;
806
+ /** raw atomic 정수 문자열(고급). USDC 6dp 기준 $1 = `'1000000'`. `amount` 와 상호 배타. */
807
+ amountAtomic?: string;
790
808
  /** 생략 시 API 키 모드의 기본 자산(현재 Base / Base Sepolia). */
791
809
  network?: string;
792
810
  /** 기본 `'USDC'`. */
package/dist/index.d.ts CHANGED
@@ -556,8 +556,20 @@ declare class BitPalCheckoutClient {
556
556
  * 통지되므로, 서버 사이드 확정은 webhook 을 신뢰(폴링은 buyer UX 용).
557
557
  */
558
558
  getStatus(sessionId: string): Promise<ApiResponse<SessionStatus>>;
559
- /** 수수료 미리보기 — `/v1/checkout/fee-preview` (Phase 1 credit system 폐기 후 canonical path) */
560
- previewFee(amount: string): Promise<ApiResponse<FeePreview>>;
559
+ /**
560
+ * 수수료 미리보기 — `/v1/checkout/fee-preview`.
561
+ *
562
+ * `amount` 는 **사람 표기**다("100", "0.5") — line item / Price / x402 와 같은 모델이라
563
+ * decimals 를 계산할 필요가 없다. raw μUSD 를 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
564
+ * 응답은 계속 atomic 이다(계산 결과라 정밀도가 곧 계약이다).
565
+ *
566
+ * @example
567
+ * const { data } = await bp.checkout.previewFee('100'); // $100
568
+ * const { data } = await bp.checkout.previewFee({ amountAtomic: '100000000' });
569
+ */
570
+ previewFee(amount: string | {
571
+ amountAtomic: string;
572
+ }): Promise<ApiResponse<FeePreview>>;
561
573
  }
562
574
  declare class BitPalError extends Error {
563
575
  readonly statusCode: number;
@@ -785,8 +797,14 @@ interface X402GateOptions {
785
797
  apiKey: string;
786
798
  /** 정산 지갑. 콘솔에 등록한 payout 주소와 같은 값이어야 한다. */
787
799
  payTo: string;
788
- /** 호출 1건당 받을 총액(atomic). USDC 6dp 기준 $1 = `'1000000'`. 수수료는 여기서 차감된다. */
789
- amount: string;
800
+ /**
801
+ * 호출 1건당 받을 총액. **사람 표기 문자열**이다 — `'0.1'`, `'1'`, `'29.00'`.
802
+ * 체인·토큰 decimals 를 계산할 필요가 없다(체크아웃 `line_items[].amount` 와 같은 모델).
803
+ * 수수료는 이 금액에서 차감된다. raw atomic 을 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
804
+ */
805
+ amount?: string;
806
+ /** raw atomic 정수 문자열(고급). USDC 6dp 기준 $1 = `'1000000'`. `amount` 와 상호 배타. */
807
+ amountAtomic?: string;
790
808
  /** 생략 시 API 키 모드의 기본 자산(현재 Base / Base Sepolia). */
791
809
  network?: string;
792
810
  /** 기본 `'USDC'`. */
package/dist/index.js CHANGED
@@ -256,12 +256,23 @@ var BitPalCheckoutClient = class {
256
256
  );
257
257
  }
258
258
  /* ─── Fees ─── */
259
- /** 수수료 미리보기 — `/v1/checkout/fee-preview` (Phase 1 credit system 폐기 후 canonical path) */
259
+ /**
260
+ * 수수료 미리보기 — `/v1/checkout/fee-preview`.
261
+ *
262
+ * `amount` 는 **사람 표기**다("100", "0.5") — line item / Price / x402 와 같은 모델이라
263
+ * decimals 를 계산할 필요가 없다. raw μUSD 를 직접 넣으려면 `amountAtomic` 을 쓴다(상호 배타).
264
+ * 응답은 계속 atomic 이다(계산 결과라 정밀도가 곧 계약이다).
265
+ *
266
+ * @example
267
+ * const { data } = await bp.checkout.previewFee('100'); // $100
268
+ * const { data } = await bp.checkout.previewFee({ amountAtomic: '100000000' });
269
+ */
260
270
  async previewFee(amount) {
261
- return this.request(
262
- "GET",
263
- `/v1/checkout/fee-preview?amount=${encodeURIComponent(amount)}`
264
- );
271
+ const qs = typeof amount === "string" ? `amount=${encodeURIComponent(amount)}` : `amount_atomic=${encodeURIComponent(amount.amountAtomic)}`;
272
+ if (typeof amount === "string" && !/^(0|[1-9]\d*)(\.\d{1,6})?$/.test(amount)) {
273
+ throw new Error('[BitPal] previewFee: amount must be a decimal string like "100" or "0.5" (max 6 decimals). For raw \u03BCUSD use { amountAtomic }.');
274
+ }
275
+ return this.request("GET", `/v1/checkout/fee-preview?${qs}`);
265
276
  }
266
277
  };
267
278
  var BitPalError = class extends Error {
@@ -417,8 +428,16 @@ var X402Gate = class {
417
428
  if (!/^0x[a-fA-F0-9]{40}$/.test(opts.payTo)) {
418
429
  throw new Error("[BitPal] x402: payTo must be a 0x EVM address (your registered payout wallet).");
419
430
  }
420
- if (!/^\d+$/.test(opts.amount)) {
421
- throw new Error('[BitPal] x402: amount must be an atomic integer string (USDC 6dp, $1 = "1000000").');
431
+ const hasHuman = opts.amount != null;
432
+ const hasAtomic = opts.amountAtomic != null;
433
+ if (hasHuman === hasAtomic) {
434
+ throw new Error('[BitPal] x402: provide exactly one of `amount` ("0.1") or `amountAtomic` ("100000").');
435
+ }
436
+ if (hasHuman && !/^(0|[1-9]\d*)(\.\d{1,6})?$/.test(opts.amount)) {
437
+ throw new Error('[BitPal] x402: amount must be a decimal string like "0.1" or "29" (max 6 decimals).');
438
+ }
439
+ if (hasAtomic && !/^\d+$/.test(opts.amountAtomic)) {
440
+ throw new Error('[BitPal] x402: amountAtomic must be an integer string (USDC 6dp, $1 = "1000000").');
422
441
  }
423
442
  const timeoutSeconds = opts.maxTimeoutSeconds ?? DEFAULT_MAX_TIMEOUT_SECONDS;
424
443
  if (timeoutSeconds < MIN_VALIDITY_SECONDS || timeoutSeconds > MAX_VALIDITY_SECONDS) {
@@ -436,7 +455,8 @@ var X402Gate = class {
436
455
  async requirements(resource) {
437
456
  return this.request("POST", "/v1/x402/requirements", {
438
457
  payTo: this.opts.payTo,
439
- amount: this.opts.amount,
458
+ // 사람 표기 → atomic 변환은 **서버가** 한다. SDK 가 decimals 를 알 필요가 없다.
459
+ ...this.opts.amount != null ? { amount: this.opts.amount } : { amountAtomic: this.opts.amountAtomic },
440
460
  resource,
441
461
  ...this.opts.network ? { network: this.opts.network } : {},
442
462
  ...this.opts.asset ? { asset: this.opts.asset } : {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpal/checkout",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "BitPal Checkout SDK — non-custodial crypto checkout: create sessions, issue per-order deposit addresses, poll status, verify signed webhooks, and charge per API call with x402.",
5
5
  "license": "MIT",
6
6
  "repository": {