@bitpal/checkout 0.1.0 → 0.2.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.
@@ -0,0 +1,135 @@
1
+ # @bitpal/checkout — Migration Guide v0.1.x → v0.2.0
2
+
3
+ > Audit doc 11 §3 C-01 option 2 (PaymentAuthorization 이중방어) 적용으로 인한 SDK 메이저 bump.
4
+
5
+ ## Why this change
6
+
7
+ v0.1.x 까지의 `payWithAuthorization` 흐름은 buyer 의 EIP-3009 USDC sig 만 받았다. 이 sig 는
8
+ `(from, to, value, validAfter, validBefore, nonce)` 만 바인딩하므로, **paymentId / merchant /
9
+ amount / fee / reserve / duration** 은 호출자(BitPal gateway)가 자유롭게 지정 가능했다.
10
+
11
+ → gateway 키 탈취 시 공격자가 (a) buyer 의 EIP-3009 sig 입수 후 (b) 자기 주소를 merchant 로 설정,
12
+ (c) `depositWithAuthorization` 호출 → buyer 자금이 attacker merchant 로 흘러간다.
13
+
14
+ v0.2.0 는 buyer 가 **결제 의도 전체** 에 별도 EIP-712 서명 (`PaymentAuthorization`) 을 한다. gateway
15
+ 키 탈취 시에도 buyer 의도 밖 결제 생성 불가 (이중방어).
16
+
17
+ ## Breaking changes
18
+
19
+ ### `BitPal.checkout.payWithAuthorization(sessionId, params)`
20
+
21
+ `params.payment_auth` 필드가 **필수** 가 됐다.
22
+
23
+ **Before (v0.1.x):**
24
+ ```ts
25
+ await bp.checkout.payWithAuthorization(sessionId, {
26
+ session_token: 'xyz...',
27
+ chain: 'base',
28
+ authorization: {
29
+ from: buyer.address,
30
+ validAfter: '0',
31
+ validBefore: String(Math.floor(Date.now()/1000) + 3600),
32
+ authNonce: '0x...',
33
+ v: 27, r: '0x...', s: '0x...',
34
+ },
35
+ });
36
+ ```
37
+
38
+ **After (v0.2.0):**
39
+ ```ts
40
+ import {
41
+ buildPaymentAuthTypedData,
42
+ sessionIdToPaymentId,
43
+ } from '@bitpal/checkout';
44
+
45
+ // 1. PaymentAuthorization nonce 조회 (CheckoutEscrow.paymentAuthNonce)
46
+ const nonce = await escrow.read.paymentAuthNonce([buyer.address]);
47
+
48
+ // 2. PaymentAuthorization typed-data sig
49
+ const paymentAuthDeadline = Math.floor(Date.now()/1000) + 3600;
50
+ const paymentId = sessionIdToPaymentId(sessionId);
51
+ const paymentAuthTd = buildPaymentAuthTypedData({
52
+ escrowAddress: escrow.address,
53
+ chainId: 8453,
54
+ paymentId,
55
+ payer: buyer.address,
56
+ merchant: session.seller_wallet,
57
+ token: session.token_address,
58
+ amount: session.amount_total,
59
+ feeAmount: '0',
60
+ reserveAmount: '0',
61
+ duration: '0',
62
+ deadline: String(paymentAuthDeadline),
63
+ nonce: String(nonce),
64
+ });
65
+ const paymentAuthSig = await wallet.signTypedData(paymentAuthTd);
66
+ const paymentAuthParsed = parseSignature(paymentAuthSig); // viem helper
67
+
68
+ // 3. USDC EIP-3009 sig (변경 없음 — 기존 흐름 그대로)
69
+ const usdcSig = await wallet.signTypedData({ /* TransferWithAuthorization ... */ });
70
+ const usdcParsed = parseSignature(usdcSig);
71
+
72
+ // 4. payWithAuthorization 호출 — payment_auth 필드 추가
73
+ await bp.checkout.payWithAuthorization(sessionId, {
74
+ session_token: 'xyz...',
75
+ chain: 'base',
76
+ authorization: {
77
+ from: buyer.address,
78
+ validAfter: '0',
79
+ validBefore: String(Math.floor(Date.now()/1000) + 3600),
80
+ authNonce: '0x...',
81
+ v: Number(usdcParsed.v), r: usdcParsed.r, s: usdcParsed.s,
82
+ },
83
+ // ← 신규 필수
84
+ payment_auth: {
85
+ deadline: String(paymentAuthDeadline),
86
+ duration: '0',
87
+ v: Number(paymentAuthParsed.v),
88
+ r: paymentAuthParsed.r,
89
+ s: paymentAuthParsed.s,
90
+ },
91
+ });
92
+ ```
93
+
94
+ ### 백엔드 응답에서 `payment_auth_nonce` 노출
95
+
96
+ 서버는 `GET /v1/checkout/sessions/:id/public` 응답에 `payment_auth_nonce` 필드를 포함한다
97
+ (Q5 적용 후). buyer UI 가 컨트랙트를 직접 호출하지 않고도 nonce 를 얻을 수 있다. 단,
98
+ `merchant_wallet` (seller_wallet) 도 sig 에 들어가므로 public response 에서 확인할 수 있어야 한다.
99
+
100
+ ## Non-breaking changes
101
+
102
+ 다음 SDK 흐름은 변경 없음:
103
+
104
+ - `createSession()`, `getSession()`, `listSessions()`, `previewFee()`
105
+ - `refundSession()`, `recordRefund()`, `listRefunds()`
106
+ - `submitExternalPayment()` (Mode A — buyer 가 본인 지갑으로 직접 deposit)
107
+ - Webhook helpers (`verifyWebhookSignature`, `parseWebhookEvent`)
108
+ - Amount helpers (`toAtomicUSDC`, `fromAtomicUSDC`)
109
+
110
+ ## Why `payment_auth` is required (no opt-out)
111
+
112
+ Q4 PR 적용 후 `CheckoutEscrow.depositWithAuthorization` 가 PaymentAuthorization sig 를 강제한다
113
+ (컨트랙트 require). SDK 가 sig 없이 호출 시 백엔드가 `PAYMENT_AUTH_REQUIRED` (400) 로 거부.
114
+
115
+ ## Compatibility matrix
116
+
117
+ | SDK version | Backend (CheckoutEscrow contract) | Result |
118
+ |---|---|---|
119
+ | v0.1.x | post-Q5 (PaymentAuthorization 필수) | ❌ `PAYMENT_AUTH_REQUIRED` 400 |
120
+ | v0.2.0 | post-Q5 | ✅ OK |
121
+ | v0.2.0 | pre-Q5 (legacy 미배포 contract) | ❌ contract revert (signature 추가 인자 없음) |
122
+
123
+ → SDK v0.2.0 와 컨트랙트 Q4+Q5 적용은 **동시 배포** 가 원칙. testnet 부터 함께 갈아끼움.
124
+
125
+ ## New helpers
126
+
127
+ - `buildPaymentAuthTypedData(args)` — `signTypedData` 호환 객체 생성
128
+ - `buildConfirmReceiptTypedData(args)` — Q4 H-01 `confirmReceiptWithSignature` 용 (off-chain receipt confirmation 직접 구현 시 사용. 기본 흐름에서는 BitPal hosted page 가 처리)
129
+ - `sessionIdToPaymentId(sessionId)` — 32-byte hex 변환 (= 백엔드 `toBytes32()`)
130
+
131
+ ## See also
132
+
133
+ - `docs/_dan/b2b-spec/2026-05-14-11-smart-contract-security-audit.md` §3 C-01
134
+ - `docs/_dan/b2b-spec/2026-05-18-14-post-audit-remaining-hardening-plan.md` §4 (PR-C 실행 가이드)
135
+ - README.md §"Gasless lane (Hosted / Gasless)"
package/dist/index.d.ts CHANGED
@@ -145,6 +145,7 @@ interface SubmitExternalPaymentResult {
145
145
  interface PayWithAuthorizationParams {
146
146
  chain?: string;
147
147
  session_token: string;
148
+ /** EIP-3009 TransferWithAuthorization sig (USDC). */
148
149
  authorization: {
149
150
  from: string;
150
151
  validAfter?: string;
@@ -154,6 +155,39 @@ interface PayWithAuthorizationParams {
154
155
  r: string;
155
156
  s: string;
156
157
  };
158
+ /**
159
+ * Q5 C-01 옵션 2 (SDK v0.2.0): PaymentAuthorization typed-data sig.
160
+ * Buyer 가 결제 의도 전체 (paymentId, merchant, amount, fee, reserve, duration) 에 서명.
161
+ * gateway 키 탈취 시에도 buyer 의도 밖 결제 생성 차단.
162
+ *
163
+ * 서명 생성: `buildPaymentAuthTypedData()` helper 또는 viem `signTypedData` 직접 호출.
164
+ * Required for SDK v0.2.x+ — gasless lane 모든 호출에 필수. v0.1.x 는 미지원.
165
+ */
166
+ payment_auth: {
167
+ deadline: string;
168
+ duration: string;
169
+ v: number;
170
+ r: string;
171
+ s: string;
172
+ };
173
+ }
174
+ /**
175
+ * Q5 C-01 옵션 2: buyer 가 서명할 EIP-712 PaymentAuthorization typed-data 의 입력 인자.
176
+ * `buildPaymentAuthTypedData()` 가 이를 받아 viem 호환 객체를 반환.
177
+ */
178
+ interface PaymentAuthTypedDataArgs {
179
+ escrowAddress: string;
180
+ chainId: number;
181
+ paymentId: string;
182
+ payer: string;
183
+ merchant: string;
184
+ token: string;
185
+ amount: string;
186
+ feeAmount: string;
187
+ reserveAmount: string;
188
+ duration: string;
189
+ deadline: string;
190
+ nonce: string;
157
191
  }
158
192
  interface CheckoutPaymentResult {
159
193
  status: string;
@@ -344,10 +378,24 @@ declare class BitPalCheckoutClient {
344
378
  /**
345
379
  * Gasless checkout payment through the BitPal API relayer.
346
380
  *
347
- * The buyer signs an EIP-3009 authorization and the API calls
348
- * `CheckoutEscrow.depositWithAuthorization()` with the platform relayer.
381
+ * The buyer signs **two** EIP-712 typed-data structures and the API calls
382
+ * `CheckoutEscrow.depositWithAuthorization()` with the platform relayer:
383
+ *
384
+ * 1. **EIP-3009 USDC TransferWithAuthorization** (`params.authorization`) —
385
+ * authorizes USDC transfer from buyer to escrow.
386
+ * 2. **PaymentAuthorization** (`params.payment_auth`, since SDK v0.2.0) —
387
+ * binds the entire payment intent (paymentId, merchant, amount, fee,
388
+ * reserve, duration) to the buyer's signature. Without this, a compromised
389
+ * gateway key could redirect funds to an attacker-controlled merchant.
390
+ *
391
+ * Build the PaymentAuthorization typed-data with `buildPaymentAuthTypedData()`.
392
+ * The PaymentAuthorization nonce comes from `CheckoutEscrow.paymentAuthNonce(payer)`.
393
+ *
349
394
  * Use the returned session/order state only as immediate UX feedback; the
350
395
  * merchant backend should finalize fulfillment from signed webhooks.
396
+ *
397
+ * @breaking-change v0.2.0 — `payment_auth` field is now required. v0.1.x clients
398
+ * must upgrade their signing flow. See MIGRATION_v0.2.md.
351
399
  */
352
400
  payWithAuthorization(sessionId: string, params: PayWithAuthorizationParams, opts?: IdempotencyOptions): Promise<ApiResponse<CheckoutPaymentResult>>;
353
401
  /**
@@ -485,6 +533,154 @@ declare function toAtomicUSDC(decimal: string): string;
485
533
  */
486
534
  declare function fromAtomicUSDC(atomic: string): string;
487
535
 
536
+ /**
537
+ * typed-data.ts — Q5 C-01 옵션 2 (SDK v0.2.0).
538
+ *
539
+ * BitPal Checkout 의 EIP-712 typed-data helper. SDK 가 모든 typed-data 작업을 직접
540
+ * 수행하지 않고 (서명은 머천트의 wallet provider 가) **typed-data 객체만 생성** 한다.
541
+ *
542
+ * 사용 예 (viem):
543
+ *
544
+ * ```ts
545
+ * import { buildPaymentAuthTypedData } from '@bitpal/checkout';
546
+ * import { signTypedData } from 'viem/accounts';
547
+ *
548
+ * const td = buildPaymentAuthTypedData({
549
+ * escrowAddress: '0x...',
550
+ * chainId: 8453,
551
+ * paymentId: '0x...', // = toBytes32(sessionId)
552
+ * payer: buyer.address,
553
+ * merchant: session.seller_wallet,
554
+ * token: session.token_address,
555
+ * amount: session.amount_total,
556
+ * feeAmount: '0',
557
+ * reserveAmount: '0',
558
+ * duration: '0',
559
+ * deadline: String(Math.floor(Date.now()/1000) + 3600),
560
+ * nonce: String(await escrow.read.paymentAuthNonce(buyer.address)),
561
+ * });
562
+ * const sig = await walletClient.signTypedData(td);
563
+ * ```
564
+ *
565
+ * 사용 예 (wagmi `useSignTypedData`):
566
+ *
567
+ * ```tsx
568
+ * const { signTypedDataAsync } = useSignTypedData();
569
+ * const td = buildPaymentAuthTypedData({ ... });
570
+ * const sig = await signTypedDataAsync(td);
571
+ * ```
572
+ */
573
+
574
+ /**
575
+ * Build EIP-712 typed-data object for PaymentAuthorization signing.
576
+ * Returns a viem-compatible structure (also compatible with wagmi/ethers v6 signTypedData).
577
+ */
578
+ declare function buildPaymentAuthTypedData(args: PaymentAuthTypedDataArgs): {
579
+ readonly domain: {
580
+ readonly name: "CheckoutEscrow";
581
+ readonly version: "1";
582
+ readonly chainId: number;
583
+ readonly verifyingContract: `0x${string}`;
584
+ };
585
+ readonly types: {
586
+ readonly PaymentAuthorization: readonly [{
587
+ readonly name: "paymentId";
588
+ readonly type: "bytes32";
589
+ }, {
590
+ readonly name: "payer";
591
+ readonly type: "address";
592
+ }, {
593
+ readonly name: "merchant";
594
+ readonly type: "address";
595
+ }, {
596
+ readonly name: "token";
597
+ readonly type: "address";
598
+ }, {
599
+ readonly name: "amount";
600
+ readonly type: "uint256";
601
+ }, {
602
+ readonly name: "feeAmount";
603
+ readonly type: "uint256";
604
+ }, {
605
+ readonly name: "reserveAmount";
606
+ readonly type: "uint256";
607
+ }, {
608
+ readonly name: "duration";
609
+ readonly type: "uint256";
610
+ }, {
611
+ readonly name: "deadline";
612
+ readonly type: "uint256";
613
+ }, {
614
+ readonly name: "nonce";
615
+ readonly type: "uint256";
616
+ }];
617
+ };
618
+ readonly primaryType: "PaymentAuthorization";
619
+ readonly message: {
620
+ readonly paymentId: `0x${string}`;
621
+ readonly payer: `0x${string}`;
622
+ readonly merchant: `0x${string}`;
623
+ readonly token: `0x${string}`;
624
+ readonly amount: bigint;
625
+ readonly feeAmount: bigint;
626
+ readonly reserveAmount: bigint;
627
+ readonly duration: bigint;
628
+ readonly deadline: bigint;
629
+ readonly nonce: bigint;
630
+ };
631
+ };
632
+ /**
633
+ * Args for the EIP-712 ConfirmReceipt typed-data.
634
+ * Used when buyer signs an off-chain receipt confirmation that BitPal gateway relays
635
+ * on-chain via `confirmReceiptWithSignature` (Q4 H-01).
636
+ */
637
+ interface ConfirmReceiptTypedDataArgs {
638
+ escrowAddress: string;
639
+ chainId: number;
640
+ paymentId: string;
641
+ payer: string;
642
+ deadline: string;
643
+ nonce: string;
644
+ }
645
+ /**
646
+ * Build EIP-712 typed-data object for ConfirmReceipt signing (Q4 H-01).
647
+ */
648
+ declare function buildConfirmReceiptTypedData(args: ConfirmReceiptTypedDataArgs): {
649
+ readonly domain: {
650
+ readonly name: "CheckoutEscrow";
651
+ readonly version: "1";
652
+ readonly chainId: number;
653
+ readonly verifyingContract: `0x${string}`;
654
+ };
655
+ readonly types: {
656
+ readonly ConfirmReceipt: readonly [{
657
+ readonly name: "paymentId";
658
+ readonly type: "bytes32";
659
+ }, {
660
+ readonly name: "payer";
661
+ readonly type: "address";
662
+ }, {
663
+ readonly name: "deadline";
664
+ readonly type: "uint256";
665
+ }, {
666
+ readonly name: "nonce";
667
+ readonly type: "uint256";
668
+ }];
669
+ };
670
+ readonly primaryType: "ConfirmReceipt";
671
+ readonly message: {
672
+ readonly paymentId: `0x${string}`;
673
+ readonly payer: `0x${string}`;
674
+ readonly deadline: bigint;
675
+ readonly nonce: bigint;
676
+ };
677
+ };
678
+ /**
679
+ * Convert a session ID string into a 32-byte hex (`paymentId`) suitable for typed-data signing.
680
+ * Mirrors the backend `toBytes32(sessionId)` helper.
681
+ */
682
+ declare function sessionIdToPaymentId(sessionId: string): `0x${string}`;
683
+
488
684
  /**
489
685
  * @bitpal/checkout — BitPal Checkout SDK
490
686
  *
@@ -512,4 +708,4 @@ declare class BitPal {
512
708
  constructor(config: BitPalConfig | string);
513
709
  }
514
710
 
515
- export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutPaymentResult, type CheckoutSession, type CheckoutWebhookEvent, type CreateSessionParams, type ExternalPaymentConfig, type FeePreview, type IdempotencyOptions, type LineItem, type ListResponse, type PayWithAuthorizationParams, type PaymentObservation, type RecordRefundParams, type RefundEntry, type RefundSessionParams, type RefundSessionResult, type SubmitExternalPaymentParams, type SubmitExternalPaymentResult, WEBHOOK_HEADERS, type WebhookPayload, fromAtomicUSDC, parseWebhookEvent, toAtomicUSDC, verifyWebhookSignature };
711
+ export { type ApiResponse, BitPal, BitPalCheckoutClient, type BitPalConfig, BitPalError, CHECKOUT_WEBHOOK_EVENTS, type CheckoutPaymentResult, type CheckoutSession, type CheckoutWebhookEvent, type ConfirmReceiptTypedDataArgs, type CreateSessionParams, type ExternalPaymentConfig, type FeePreview, type IdempotencyOptions, type LineItem, type ListResponse, type PayWithAuthorizationParams, type PaymentAuthTypedDataArgs, type PaymentObservation, type RecordRefundParams, type RefundEntry, type RefundSessionParams, type RefundSessionResult, type SubmitExternalPaymentParams, type SubmitExternalPaymentResult, WEBHOOK_HEADERS, type WebhookPayload, buildConfirmReceiptTypedData, buildPaymentAuthTypedData, fromAtomicUSDC, parseWebhookEvent, sessionIdToPaymentId, toAtomicUSDC, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -182,10 +182,24 @@ var BitPalCheckoutClient = class {
182
182
  /**
183
183
  * Gasless checkout payment through the BitPal API relayer.
184
184
  *
185
- * The buyer signs an EIP-3009 authorization and the API calls
186
- * `CheckoutEscrow.depositWithAuthorization()` with the platform relayer.
185
+ * The buyer signs **two** EIP-712 typed-data structures and the API calls
186
+ * `CheckoutEscrow.depositWithAuthorization()` with the platform relayer:
187
+ *
188
+ * 1. **EIP-3009 USDC TransferWithAuthorization** (`params.authorization`) —
189
+ * authorizes USDC transfer from buyer to escrow.
190
+ * 2. **PaymentAuthorization** (`params.payment_auth`, since SDK v0.2.0) —
191
+ * binds the entire payment intent (paymentId, merchant, amount, fee,
192
+ * reserve, duration) to the buyer's signature. Without this, a compromised
193
+ * gateway key could redirect funds to an attacker-controlled merchant.
194
+ *
195
+ * Build the PaymentAuthorization typed-data with `buildPaymentAuthTypedData()`.
196
+ * The PaymentAuthorization nonce comes from `CheckoutEscrow.paymentAuthNonce(payer)`.
197
+ *
187
198
  * Use the returned session/order state only as immediate UX feedback; the
188
199
  * merchant backend should finalize fulfillment from signed webhooks.
200
+ *
201
+ * @breaking-change v0.2.0 — `payment_auth` field is now required. v0.1.x clients
202
+ * must upgrade their signing flow. See MIGRATION_v0.2.md.
189
203
  */
190
204
  async payWithAuthorization(sessionId, params, opts) {
191
205
  return this.request(
@@ -304,6 +318,74 @@ function fromAtomicUSDC(atomic) {
304
318
  return fracStr.length > 0 ? `${whole}.${fracStr.padEnd(2, "0")}` : `${whole}.00`;
305
319
  }
306
320
 
321
+ // src/typed-data.ts
322
+ function buildPaymentAuthTypedData(args) {
323
+ return {
324
+ domain: {
325
+ name: "CheckoutEscrow",
326
+ version: "1",
327
+ chainId: args.chainId,
328
+ verifyingContract: args.escrowAddress
329
+ },
330
+ types: {
331
+ PaymentAuthorization: [
332
+ { name: "paymentId", type: "bytes32" },
333
+ { name: "payer", type: "address" },
334
+ { name: "merchant", type: "address" },
335
+ { name: "token", type: "address" },
336
+ { name: "amount", type: "uint256" },
337
+ { name: "feeAmount", type: "uint256" },
338
+ { name: "reserveAmount", type: "uint256" },
339
+ { name: "duration", type: "uint256" },
340
+ { name: "deadline", type: "uint256" },
341
+ { name: "nonce", type: "uint256" }
342
+ ]
343
+ },
344
+ primaryType: "PaymentAuthorization",
345
+ message: {
346
+ paymentId: args.paymentId,
347
+ payer: args.payer,
348
+ merchant: args.merchant,
349
+ token: args.token,
350
+ amount: BigInt(args.amount),
351
+ feeAmount: BigInt(args.feeAmount),
352
+ reserveAmount: BigInt(args.reserveAmount),
353
+ duration: BigInt(args.duration),
354
+ deadline: BigInt(args.deadline),
355
+ nonce: BigInt(args.nonce)
356
+ }
357
+ };
358
+ }
359
+ function buildConfirmReceiptTypedData(args) {
360
+ return {
361
+ domain: {
362
+ name: "CheckoutEscrow",
363
+ version: "1",
364
+ chainId: args.chainId,
365
+ verifyingContract: args.escrowAddress
366
+ },
367
+ types: {
368
+ ConfirmReceipt: [
369
+ { name: "paymentId", type: "bytes32" },
370
+ { name: "payer", type: "address" },
371
+ { name: "deadline", type: "uint256" },
372
+ { name: "nonce", type: "uint256" }
373
+ ]
374
+ },
375
+ primaryType: "ConfirmReceipt",
376
+ message: {
377
+ paymentId: args.paymentId,
378
+ payer: args.payer,
379
+ deadline: BigInt(args.deadline),
380
+ nonce: BigInt(args.nonce)
381
+ }
382
+ };
383
+ }
384
+ function sessionIdToPaymentId(sessionId) {
385
+ const hex = Array.from(new TextEncoder().encode(sessionId)).map((b) => b.toString(16).padStart(2, "0")).join("").padEnd(64, "0");
386
+ return `0x${hex}`;
387
+ }
388
+
307
389
  // src/index.ts
308
390
  var BitPal = class {
309
391
  checkout;
@@ -318,8 +400,11 @@ export {
318
400
  BitPalError,
319
401
  CHECKOUT_WEBHOOK_EVENTS,
320
402
  WEBHOOK_HEADERS,
403
+ buildConfirmReceiptTypedData,
404
+ buildPaymentAuthTypedData,
321
405
  fromAtomicUSDC,
322
406
  parseWebhookEvent,
407
+ sessionIdToPaymentId,
323
408
  toAtomicUSDC,
324
409
  verifyWebhookSignature
325
410
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bitpal/checkout",
3
- "version": "0.1.0",
4
- "description": "BitPal Checkout SDK — crypto payment sessions, external on-chain payment verification, gasless checkout, refunds, fee preview.",
3
+ "version": "0.2.0",
4
+ "description": "BitPal Checkout SDK — crypto payment sessions, external on-chain payment verification, gasless checkout (with PaymentAuthorization double-defense), refunds, fee preview.",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -14,7 +14,8 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
- "README.md"
17
+ "README.md",
18
+ "MIGRATION_v0.2.md"
18
19
  ],
19
20
  "keywords": [
20
21
  "bitpal",
@@ -34,14 +35,15 @@
34
35
  "engines": {
35
36
  "node": ">=18"
36
37
  },
37
- "scripts": {
38
- "build": "tsup src/index.ts --format esm --dts --clean",
39
- "lint": "tsc --noEmit",
40
- "test": "vitest run"
41
- },
42
38
  "devDependencies": {
43
39
  "tsup": "^8.5.1",
44
40
  "typescript": "^5.5.0",
45
41
  "vitest": "^2.1.9"
42
+ },
43
+ "scripts": {
44
+ "build": "tsup src/index.ts --format esm --dts --clean",
45
+ "lint": "tsc --noEmit",
46
+ "test": "vitest run",
47
+ "release": "pnpm publish --access public --no-git-checks"
46
48
  }
47
- }
49
+ }