@fantastic.dev/better-stripe 0.13.0 → 0.15.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 (111) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +63 -1
  3. package/dist/client/billing/checkoutOptions.d.ts +27 -0
  4. package/dist/client/billing/checkoutOptions.d.ts.map +1 -0
  5. package/dist/client/billing/checkoutOptions.js +2 -0
  6. package/dist/client/billing/checkoutOptions.js.map +1 -0
  7. package/dist/client/billing/intents.d.ts +32 -0
  8. package/dist/client/billing/intents.d.ts.map +1 -0
  9. package/dist/client/billing/intents.js +71 -0
  10. package/dist/client/billing/intents.js.map +1 -0
  11. package/dist/client/connect/disputes.d.ts +20 -0
  12. package/dist/client/connect/disputes.d.ts.map +1 -1
  13. package/dist/client/connect/disputes.js +55 -0
  14. package/dist/client/connect/disputes.js.map +1 -1
  15. package/dist/client/core/fees.d.ts +2 -0
  16. package/dist/client/core/fees.d.ts.map +1 -1
  17. package/dist/client/core/fees.js +7 -0
  18. package/dist/client/core/fees.js.map +1 -1
  19. package/dist/client/costRecovery-invoices.d.ts +10 -4
  20. package/dist/client/costRecovery-invoices.d.ts.map +1 -1
  21. package/dist/client/costRecovery-invoices.js +4 -0
  22. package/dist/client/costRecovery-invoices.js.map +1 -1
  23. package/dist/client/costRecovery.d.ts +18 -2
  24. package/dist/client/costRecovery.d.ts.map +1 -1
  25. package/dist/client/costRecovery.js +4 -0
  26. package/dist/client/costRecovery.js.map +1 -1
  27. package/dist/client/errors.d.ts +1 -1
  28. package/dist/client/errors.d.ts.map +1 -1
  29. package/dist/client/errors.js.map +1 -1
  30. package/dist/client/index.d.ts +20 -37
  31. package/dist/client/index.d.ts.map +1 -1
  32. package/dist/client/index.js +18 -20
  33. package/dist/client/index.js.map +1 -1
  34. package/dist/component/_generated/component.d.ts +59 -0
  35. package/dist/component/_generated/component.d.ts.map +1 -1
  36. package/dist/component/costRecovery/claims.d.ts +12 -0
  37. package/dist/component/costRecovery/claims.d.ts.map +1 -1
  38. package/dist/component/costRecovery/imports.d.ts +53 -0
  39. package/dist/component/costRecovery/imports.d.ts.map +1 -0
  40. package/dist/component/costRecovery/imports.js +67 -0
  41. package/dist/component/costRecovery/imports.js.map +1 -0
  42. package/dist/component/costRecovery/mutations.d.ts +47 -0
  43. package/dist/component/costRecovery/mutations.d.ts.map +1 -1
  44. package/dist/component/costRecovery/mutations.js +7 -1
  45. package/dist/component/costRecovery/mutations.js.map +1 -1
  46. package/dist/component/costRecovery/queries.d.ts +12 -0
  47. package/dist/component/costRecovery/queries.d.ts.map +1 -1
  48. package/dist/component/costRecovery/schema.d.ts +72 -2
  49. package/dist/component/costRecovery/schema.d.ts.map +1 -1
  50. package/dist/component/costRecovery/schema.js +13 -0
  51. package/dist/component/costRecovery/schema.js.map +1 -1
  52. package/dist/component/schema.d.ts +19 -1
  53. package/dist/react/hooks/useConfirmPayment.d.ts +1 -1
  54. package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
  55. package/dist/react/hooks/useConfirmPayment.js +13 -2
  56. package/dist/react/hooks/useConfirmPayment.js.map +1 -1
  57. package/dist/react/index.d.ts +2 -0
  58. package/dist/react/index.d.ts.map +1 -1
  59. package/dist/react/index.js +1 -0
  60. package/dist/react/index.js.map +1 -1
  61. package/dist/react/workflows/EvidenceUpload.d.ts +18 -0
  62. package/dist/react/workflows/EvidenceUpload.d.ts.map +1 -0
  63. package/dist/react/workflows/EvidenceUpload.js +35 -0
  64. package/dist/react/workflows/EvidenceUpload.js.map +1 -0
  65. package/dist/react/workflows/Onboarding.d.ts +3 -3
  66. package/dist/react/workflows/Onboarding.d.ts.map +1 -1
  67. package/dist/react/workflows/Onboarding.js +8 -6
  68. package/dist/react/workflows/Onboarding.js.map +1 -1
  69. package/dist/react/workflows/SaveCard.d.ts +27 -0
  70. package/dist/react/workflows/SaveCard.d.ts.map +1 -0
  71. package/dist/react/workflows/SaveCard.js +56 -0
  72. package/dist/react/workflows/SaveCard.js.map +1 -0
  73. package/dist/react/workflows/index.d.ts +2 -0
  74. package/dist/react/workflows/index.d.ts.map +1 -1
  75. package/dist/react/workflows/index.js +1 -0
  76. package/dist/react/workflows/index.js.map +1 -1
  77. package/dist/react/workflows/useWorkflowAction.d.ts +1 -1
  78. package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -1
  79. package/dist/react/workflows/useWorkflowAction.js +6 -2
  80. package/dist/react/workflows/useWorkflowAction.js.map +1 -1
  81. package/docs/react-workflows.md +83 -0
  82. package/package.json +1 -1
  83. package/src/client/billing/checkoutOptions.ts +27 -0
  84. package/src/client/billing/intents.test.ts +216 -0
  85. package/src/client/billing/intents.ts +120 -0
  86. package/src/client/billing/intentsTransport.test.ts +94 -0
  87. package/src/client/connect/dispute-upload.test.ts +208 -0
  88. package/src/client/connect/disputes.ts +103 -0
  89. package/src/client/core/fees.ts +8 -0
  90. package/src/client/costRecovery-import.test.ts +174 -0
  91. package/src/client/costRecovery-invoices.test.ts +69 -0
  92. package/src/client/costRecovery-invoices.ts +32 -0
  93. package/src/client/costRecovery.ts +16 -0
  94. package/src/client/errors.ts +1 -0
  95. package/src/client/index.ts +50 -52
  96. package/src/component/_generated/api.ts +2 -0
  97. package/src/component/_generated/component.ts +65 -0
  98. package/src/component/costRecovery/imports.ts +74 -0
  99. package/src/component/costRecovery/mutations.ts +8 -0
  100. package/src/component/costRecovery/schema.ts +13 -0
  101. package/src/react/hooks/useConfirmPayment.test.tsx +47 -0
  102. package/src/react/hooks/useConfirmPayment.ts +16 -2
  103. package/src/react/index.ts +3 -0
  104. package/src/react/workflows/EvidenceUpload.test.tsx +56 -0
  105. package/src/react/workflows/EvidenceUpload.tsx +71 -0
  106. package/src/react/workflows/Onboarding.test.tsx +73 -0
  107. package/src/react/workflows/Onboarding.tsx +8 -5
  108. package/src/react/workflows/SaveCard.test.tsx +127 -0
  109. package/src/react/workflows/SaveCard.tsx +117 -0
  110. package/src/react/workflows/index.ts +3 -0
  111. package/src/react/workflows/useWorkflowAction.ts +6 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EACV,aAAa,EACb,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,cAAc,EACd,SAAS,GACV,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,KAAK,EACL,QAAQ,EACR,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,uBAAuB,EACvB,OAAO,EACP,UAAU,EACV,SAAS,EACT,eAAe,EACf,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EACV,aAAa,EACb,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,aAAa,EACb,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EACV,sBAAsB,EACtB,sBAAsB,EACtB,eAAe,GAChB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,oBAAoB,EACpB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,WAAW,EACX,cAAc,EACd,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACjE,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,iBAAiB,EACjB,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EACV,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,GACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAC9D,YAAY,EACV,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,YAAY,EACV,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAChE,YAAY,EACV,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAClE,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EACV,uBAAuB,EACvB,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -40,4 +40,5 @@ export { Pagination, useCursorPagination } from "./Pagination.js";
40
40
  export { PlanPricingEditor } from "./PlanPricingEditor.js";
41
41
  export { AffiliateRateEditor } from "./AffiliateRateEditor.js";
42
42
  export { AffiliatePayoutEditor } from "./AffiliatePayoutEditor.js";
43
+ export { EvidenceUpload } from "./EvidenceUpload.js";
43
44
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/workflows/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/workflows/index.ts"],"names":[],"mappings":"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"}
@@ -7,5 +7,5 @@ export type WorkflowActionState<T, Args extends unknown[]> = {
7
7
  reset: () => void;
8
8
  };
9
9
  /** Shared async action lifecycle. Scope identifies the authenticated account/resource, not authorization. */
10
- export declare function useWorkflowAction<T, Args extends unknown[]>(action: (...args: Args) => Promise<T>, scope?: string): WorkflowActionState<T, Args>;
10
+ export declare function useWorkflowAction<T, Args extends unknown[]>(action: (...args: Args) => Promise<T>, scope?: string, onSuccess?: (result: T) => void): WorkflowActionState<T, Args>;
11
11
  //# sourceMappingURL=useWorkflowAction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkflowAction.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/useWorkflowAction.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC;IACtB,gFAAgF;IAChF,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AACF,6GAA6G;AAC7G,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,EACzD,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EACrC,KAAK,GAAE,MAAkB,GACxB,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,CA4D9B"}
1
+ {"version":3,"file":"useWorkflowAction.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/useWorkflowAction.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,IAAI;IAC3D,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC;IACtB,gFAAgF;IAChF,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC/C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AACF,6GAA6G;AAC7G,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,SAAS,OAAO,EAAE,EACzD,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,EACrC,KAAK,GAAE,MAAkB,EACzB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GAC9B,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAAC,CAgE9B"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useCallback, useEffect, useRef, useState } from "react";
3
3
  /** Shared async action lifecycle. Scope identifies the authenticated account/resource, not authorization. */
4
- export function useWorkflowAction(action, scope = "default") {
4
+ export function useWorkflowAction(action, scope = "default", onSuccess) {
5
5
  const initial = {
6
6
  scope,
7
7
  isPending: false,
@@ -12,11 +12,13 @@ export function useWorkflowAction(action, scope = "default") {
12
12
  if (state.scope !== scope)
13
13
  setState(initial);
14
14
  const callback = useRef(action);
15
+ const success = useRef(onSuccess);
15
16
  const lifecycle = useRef({ version: 0, mounted: false });
16
17
  const lock = useRef(null);
17
18
  useEffect(() => {
18
19
  callback.current = action;
19
- }, [action]);
20
+ success.current = onSuccess;
21
+ }, [action, onSuccess]);
20
22
  useEffect(() => {
21
23
  const version = ++lifecycle.current.version;
22
24
  lifecycle.current.mounted = true;
@@ -41,10 +43,12 @@ export function useWorkflowAction(action, scope = "default") {
41
43
  lock.current = version;
42
44
  setState({ scope, isPending: true, error: null, result: undefined });
43
45
  const current = () => lifecycle.current.mounted && lifecycle.current.version === version;
46
+ const complete = success.current;
44
47
  try {
45
48
  const result = await callback.current(...args);
46
49
  if (!current())
47
50
  return undefined;
51
+ complete?.(result);
48
52
  setState({ scope, isPending: false, error: null, result });
49
53
  return result;
50
54
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useWorkflowAction.js","sourceRoot":"","sources":["../../../src/react/workflows/useWorkflowAction.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useWorkflowAction.js","sourceRoot":"","sources":["../../../src/react/workflows/useWorkflowAction.ts"],"names":[],"mappings":"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"}
@@ -489,3 +489,86 @@ original method and types; it does not retry an unpaid invoice or automatically
489
489
  fall back to a card. The example demonstrates durable preparation and pending
490
490
  operation records in `storeBalanceFunding.ts` with a separate preview client.
491
491
  See the [README balance-funding workflow](../README.md#optional-balance-funded-subscriptions).
492
+
493
+ ## Dispute evidence uploads and onboarding navigation
494
+
495
+ `EvidenceUpload` is an unstyled control with render props. Its `scopeKey` must
496
+ include the authenticated scope and selected dispute. Bind `onUpload(file)` to
497
+ an authenticated server callback, convert the file to bytes there, and call
498
+ `betterStripe.uploadDisputeEvidence(ctx, { stripeDisputeId, actor, field, file })`.
499
+ The example seller disputes page demonstrates a communication-file attachment.
500
+ The example uses demo personas, so production applications must replace its
501
+ persona authorization with a session-derived actor and dispute ownership check.
502
+ Never accept an actor, connected request account, or attachment file ID from the
503
+ browser as authorization.
504
+
505
+ The server API accepts nonempty PDF, JPEG or PNG bytes up to 5,000,000 bytes. MIME
506
+ type and file signature must match. Stripe performs full document validation and
507
+ may reject corrupt documents or apply additional dispute/network limits. See
508
+ [Stripe's file upload guide](https://docs.stripe.com/file-upload) and
509
+ [evidence troubleshooting](https://support.stripe.com/questions/evidence-submission-troubleshooting-faq).
510
+ Authorization runs before uploading and again before binding. The API uploads
511
+ with `purpose: "dispute_evidence"`, binds only the returned ID to the chosen
512
+ file evidence field, and explicitly sends `submit: false`. Uploading never sends
513
+ evidence to the bank. Continue using `EvidenceForm.stage()` for prose drafts and
514
+ `EvidenceForm.submit()` for explicit final submission.
515
+
516
+ `DISPUTE_UPLOAD_FAILED` carries structured provider error details. An attachment
517
+ failure reports `DISPUTE_UPDATE_FAILED`; the uploaded file can remain at Stripe
518
+ without a draft attachment. Keep the local file and prose draft so the user can
519
+ retry. Do not mark an upload as attached until the entire callback succeeds.
520
+ Convex action payload limits can be lower than Stripe's file limit. For larger
521
+ files, authorize and load a private storage reference on the server, then pass
522
+ its bytes to the package. The example byte-action transport is for small files.
523
+
524
+ `useWorkflowAction(action, scopeKey, onSuccess)` invokes `onSuccess` only after
525
+ checking that the response still belongs to the mounted scope. `useOnboarding`
526
+ uses this lifecycle for both create and continue navigation, including its
527
+ `window.location.assign` fallback. An old response cannot navigate after unmount
528
+ or scope replacement. Current requests preserve shared pending locks and errors.
529
+ These APIs ship in the release containing the dispute-upload and stale-navigation
530
+ implementation PR. Version 0.13.0 does not contain them. Consumers must upgrade
531
+ to that release before removing their navigation guard or using the upload API.
532
+ Production storage, session authorization, styling, translations and extended
533
+ hosted onboarding verification remain application responsibilities.
534
+
535
+ ## Save a card through SetupIntent confirmation
536
+
537
+ `SaveCard` provisions a customer-bound SetupIntent through an authenticated
538
+ `createSetupIntent({ requestId })` callback and mounts Payment Element. It keeps
539
+ creation retries on the same request, blocks duplicate confirmation, exposes
540
+ failures and only calls `onSuccess(setupIntentId)` after Stripe reports
541
+ `succeeded`. Stripe.js handles required authentication and redirects.
542
+
543
+ ```tsx
544
+ <SaveCard
545
+ publishableKey={publishableKey}
546
+ scopeKey={`${authenticatedUserId}:${customerAccount}:off_session`}
547
+ requestId={persistedSaveRequestId}
548
+ returnUrl="https://app.example/billing/cards"
549
+ createSetupIntent={createAuthorizedSetupIntent}
550
+ onSuccess={refreshPaymentMethods}
551
+ />
552
+ ```
553
+
554
+ The host callback calls `stripe.createSetupIntent(ctx, { userId,
555
+ customerAccount, usage: "off_session", consent: true, idempotencyKey })` with
556
+ server-resolved values. Record consent to the selected usage before mounting
557
+ this workflow. The default confirmation checkbox separately grants permission
558
+ to save and redisplay the card, sent as `allow_redisplay: "always"`. Use
559
+ `renderForm` for your own disclosures, consent copy, Payment Element, pending
560
+ state and errors. `useConfirmPayment().confirmSetup(returnUrl, allowRedisplay)`
561
+ supports `always`, `limited` and `unspecified` when a different redisplay policy
562
+ is required. Off-session usage does not guarantee that future payments will
563
+ never require authentication.
564
+
565
+ Persist the logical request and immutable customer/usage scope server-side.
566
+ `requestId` and `scopeKey` isolate UI lifecycles; they do not authorize access.
567
+ Handle redirect returns by retrieving the SetupIntent through an authenticated
568
+ server adapter and checking ownership and status before displaying completion.
569
+ Do not infer success from a URL parameter. Do not attach the confirmed method
570
+ again or treat confirmation as changing a subscription default.
571
+
572
+ Existing `AddCardForm` and `PaymentMethods` tokenization/attach integrations remain
573
+ available. Tokenization plus attachment does not complete SetupIntent or SCA
574
+ verification.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fantastic.dev/better-stripe",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "A Convex component for Stripe V2 Accounts API integration.",
5
5
  "keywords": [
6
6
  "stripe",
@@ -0,0 +1,27 @@
1
+ import type { SplitRecipient } from "../../component/lib/fees.js";
2
+ import type { FeeOverride } from "../types.js";
3
+
4
+ /** Host-authorized Checkout Session request. */
5
+ export type CreateCheckoutSessionOptions = {
6
+ idempotencyKey?: string;
7
+ userId: string;
8
+ orgId?: string;
9
+ stripePriceId: string;
10
+ mode: "payment" | "subscription" | "setup";
11
+ uiMode?: "embedded" | "redirect" | "custom" | "form";
12
+ quantity?: number;
13
+ returnUrl: string;
14
+ trialDays?: number;
15
+ accountId?: string;
16
+ customerEmail?: string;
17
+ /** Seller/recipient connected account to route funds to (destination charge). */
18
+ destinationAccountId?: string;
19
+ /** Multiple recipients (store + affiliate[s]); >1 routes via separate charges & transfers. */
20
+ split?: SplitRecipient[];
21
+ /** Per-call platform fee override; falls back to the configured default. */
22
+ fee?: FeeOverride;
23
+ /** Charge total (minor units) for one-time payment fee computation. */
24
+ amount?: number;
25
+ metadata?: Record<string, string>;
26
+ sessionOverrides?: Record<string, unknown>;
27
+ };
@@ -0,0 +1,216 @@
1
+ import { expect, it, vi } from "vitest";
2
+ import { BetterStripe } from "../index.js";
3
+ import { getStripeClient, type Component, type RunCtx } from "../helpers.js";
4
+
5
+ function fixture() {
6
+ const ref = { [Symbol.for("toReferencePath")]: "account" };
7
+ const component = {
8
+ core: { queries: { getAccountByStripeId: ref } },
9
+ } as unknown as Component;
10
+ const key = `sk_test_intents_${crypto.randomUUID()}`;
11
+ const client = new BetterStripe(component, { STRIPE_SECRET_KEY: key });
12
+ const sdk = getStripeClient(key);
13
+ const ctx = {
14
+ runQuery: vi
15
+ .fn()
16
+ .mockResolvedValue({ userId: "buyer", stripeAccountId: "acct_buyer" }),
17
+ } as unknown as RunCtx;
18
+ const price = vi.spyOn(sdk.prices, "retrieve").mockResolvedValue({
19
+ id: "price_one",
20
+ active: true,
21
+ type: "one_time",
22
+ unit_amount: 1200,
23
+ currency: "usd",
24
+ product: { id: "prod_one", active: true },
25
+ } as never);
26
+ const payment = vi.spyOn(sdk.paymentIntents, "create").mockResolvedValue({
27
+ id: "pi_one",
28
+ client_secret: "secret",
29
+ amount: 1200,
30
+ } as never);
31
+ const setup = vi.spyOn(sdk.setupIntents, "create").mockResolvedValue({
32
+ id: "seti_one",
33
+ client_secret: "setup_secret",
34
+ } as never);
35
+ const opts = {
36
+ userId: "buyer",
37
+ customerAccount: "acct_buyer",
38
+ idempotencyKey: "order:one",
39
+ };
40
+ return { client, ctx, price, payment, setup, opts };
41
+ }
42
+ it("creates a card-only intent with provider price economics and protected ownership metadata", async () => {
43
+ const { client, ctx, payment, opts } = fixture();
44
+ const args = {
45
+ ...opts,
46
+ stripePriceId: "price_one",
47
+ metadata: { userId: "forged", bsSplit: "forged", planId: "plan_one" },
48
+ };
49
+ expect(await client.createPaymentIntent(ctx, args)).toEqual({
50
+ paymentIntentId: "pi_one",
51
+ clientSecret: "secret",
52
+ });
53
+ await client.createPaymentIntent(ctx, args);
54
+ expect(payment).toHaveBeenNthCalledWith(
55
+ 2,
56
+ {
57
+ amount: 1200,
58
+ currency: "usd",
59
+ customer_account: "acct_buyer",
60
+ receipt_email: undefined,
61
+ allowed_payment_method_types: ["card"],
62
+ metadata: {
63
+ userId: "buyer",
64
+ planId: "plan_one",
65
+ stripePriceId: "price_one",
66
+ stripeProductId: "prod_one",
67
+ },
68
+ },
69
+ { idempotencyKey: "order:one" },
70
+ );
71
+ });
72
+ it.each([
73
+ { active: false },
74
+ { type: "recurring" },
75
+ { unit_amount: null },
76
+ { unit_amount: 0 },
77
+ { product: { id: "prod_one", active: false } },
78
+ ])("rejects unsupported price economics %j", async (override) => {
79
+ const { client, ctx, price, payment, opts } = fixture();
80
+ price.mockResolvedValue({
81
+ active: true,
82
+ type: "one_time",
83
+ unit_amount: 1200,
84
+ currency: "usd",
85
+ product: { id: "prod_one", active: true },
86
+ ...override,
87
+ } as never);
88
+ await expect(
89
+ client.createPaymentIntent(ctx, { ...opts, stripePriceId: "price_one" }),
90
+ ).rejects.toThrow();
91
+ expect(payment).not.toHaveBeenCalled();
92
+ });
93
+ it("rejects another customer's account before provider writes", async () => {
94
+ const { client, ctx, payment, setup, opts } = fixture();
95
+ await expect(
96
+ client.createPaymentIntent(ctx, {
97
+ ...opts,
98
+ userId: "attacker",
99
+ stripePriceId: "price_one",
100
+ }),
101
+ ).rejects.toThrow(/belong/);
102
+ await expect(
103
+ client.createSetupIntent(ctx, {
104
+ ...opts,
105
+ userId: "attacker",
106
+ usage: "off_session",
107
+ consent: true,
108
+ }),
109
+ ).rejects.toThrow(/belong/);
110
+ expect(payment).not.toHaveBeenCalled();
111
+ expect(setup).not.toHaveBeenCalled();
112
+ });
113
+ it("provisions consented card setup, preserves retry key after transport failure, and returns minimal secrets", async () => {
114
+ const { client, ctx, setup, opts } = fixture();
115
+ const args = {
116
+ ...opts,
117
+ usage: "off_session" as const,
118
+ consent: true as const,
119
+ };
120
+ setup.mockRejectedValueOnce(new Error("connection lost"));
121
+ await expect(client.createSetupIntent(ctx, args)).rejects.toThrow(
122
+ "connection lost",
123
+ );
124
+ expect(await client.createSetupIntent(ctx, args)).toEqual({
125
+ setupIntentId: "seti_one",
126
+ clientSecret: "setup_secret",
127
+ });
128
+ expect(setup).toHaveBeenNthCalledWith(
129
+ 2,
130
+ {
131
+ customer_account: "acct_buyer",
132
+ usage: "off_session",
133
+ allowed_payment_method_types: ["card"],
134
+ metadata: { userId: "buyer" },
135
+ },
136
+ { idempotencyKey: "order:one" },
137
+ );
138
+ });
139
+ it.each([undefined, "", "\n", "x".repeat(256)])(
140
+ "requires a valid explicit retry key %j",
141
+ async (key) => {
142
+ const { client, ctx, setup, payment, opts } = fixture();
143
+ const args = { ...opts, idempotencyKey: key as string };
144
+ await expect(
145
+ client.createSetupIntent(ctx, {
146
+ ...args,
147
+ usage: "on_session",
148
+ consent: true,
149
+ }),
150
+ ).rejects.toThrow();
151
+ await expect(
152
+ client.createPaymentIntent(ctx, { ...args, stripePriceId: "price_one" }),
153
+ ).rejects.toThrow();
154
+ expect(setup).not.toHaveBeenCalled();
155
+ expect(payment).not.toHaveBeenCalled();
156
+ },
157
+ );
158
+ it("requires setup consent and a supported usage", async () => {
159
+ const { client, ctx, setup, opts } = fixture();
160
+ await expect(
161
+ client.createSetupIntent(ctx, {
162
+ ...opts,
163
+ usage: "off_session",
164
+ consent: false as unknown as true,
165
+ }),
166
+ ).rejects.toThrow(/consent/);
167
+ await expect(
168
+ client.createSetupIntent(ctx, {
169
+ ...opts,
170
+ usage: "invalid" as "on_session",
171
+ consent: true,
172
+ }),
173
+ ).rejects.toThrow(/usage/);
174
+ expect(setup).not.toHaveBeenCalled();
175
+ });
176
+ it("rejects missing client secrets", async () => {
177
+ const { client, ctx, setup, payment, opts } = fixture();
178
+ setup.mockResolvedValue({ id: "seti_one", client_secret: null } as never);
179
+ payment.mockResolvedValue({ id: "pi_one", client_secret: null } as never);
180
+ await expect(
181
+ client.createSetupIntent(ctx, {
182
+ ...opts,
183
+ usage: "on_session",
184
+ consent: true,
185
+ }),
186
+ ).rejects.toThrow(/secret/);
187
+ await expect(
188
+ client.createPaymentIntent(ctx, { ...opts, stripePriceId: "price_one" }),
189
+ ).rejects.toThrow(/secret/);
190
+ });
191
+ it("preserves host-authorized guest purchases without inventing a customer account", async () => {
192
+ const { client, ctx, payment } = fixture();
193
+ await client.createPaymentIntent(ctx, {
194
+ userId: "",
195
+ stripePriceId: "price_one",
196
+ idempotencyKey: "guest:one",
197
+ });
198
+ expect(payment).toHaveBeenCalledWith(
199
+ expect.objectContaining({
200
+ customer_account: undefined,
201
+ metadata: expect.objectContaining({ userId: "" }),
202
+ }),
203
+ { idempotencyKey: "guest:one" },
204
+ );
205
+ });
206
+ it("preserves automatic-method checkout when the host selects it", async () => {
207
+ const { client, ctx, payment, opts } = fixture();
208
+ await client.createPaymentIntent(ctx, {
209
+ ...opts,
210
+ stripePriceId: "price_one",
211
+ paymentMethods: "automatic",
212
+ });
213
+ const request = payment.mock.calls[0][0];
214
+ expect(request.automatic_payment_methods).toEqual({ enabled: true });
215
+ expect(request.allowed_payment_method_types).toBeUndefined();
216
+ });
@@ -0,0 +1,120 @@
1
+ import type Stripe from "stripe";
2
+ import type { Component, RunCtx } from "../helpers.js";
3
+ import { stripReservedMetadata } from "../helpers.js";
4
+ import { idempotencyOptions } from "../core/idempotency.js";
5
+ import { componentRef } from "../webhooks/helpers.js";
6
+
7
+ /** Host must derive userId from authentication and authorize the purchase. */
8
+ export type IntentScope = {
9
+ userId: string;
10
+ customerAccount?: string;
11
+ /** Persist the logical request and its immutable inputs before calling. */
12
+ idempotencyKey: string;
13
+ /** Server-selected attribution only. Never forward arbitrary browser metadata. */
14
+ metadata?: Record<string, string>;
15
+ };
16
+ export type CreatePaymentIntentOptions = IntentScope & {
17
+ stripePriceId: string;
18
+ receiptEmail?: string;
19
+ /** Card-only by default; automatic preserves host-selected local payment methods. */
20
+ paymentMethods?: "card" | "automatic";
21
+ };
22
+ export type CreateSetupIntentOptions = IntentScope & {
23
+ customerAccount: string;
24
+ usage: "on_session" | "off_session";
25
+ /** Host records consent for the selected usage before provisioning. */
26
+ consent: true;
27
+ };
28
+ async function authorize(component: Component, ctx: RunCtx, opts: IntentScope) {
29
+ if (typeof opts.idempotencyKey !== "string")
30
+ throw new Error("An explicit idempotency key is required.");
31
+ const request = idempotencyOptions(opts.idempotencyKey)!;
32
+ if (opts.customerAccount === undefined) return request;
33
+ if (!opts.userId || !/^acct_[a-zA-Z0-9]+$/.test(opts.customerAccount))
34
+ throw new Error(
35
+ "An authenticated user and V2 customer account are required.",
36
+ );
37
+ const account = await ctx.runQuery(
38
+ componentRef(component, "core/queries/getAccountByStripeId"),
39
+ { stripeAccountId: opts.customerAccount },
40
+ );
41
+ if (!account || account.userId !== opts.userId)
42
+ throw new Error(
43
+ "Customer account does not belong to the authenticated user.",
44
+ );
45
+ return request;
46
+ }
47
+ export async function createPaymentIntent(
48
+ stripe: Stripe,
49
+ component: Component,
50
+ ctx: RunCtx,
51
+ opts: CreatePaymentIntentOptions,
52
+ ) {
53
+ const request = await authorize(component, ctx, opts);
54
+ const price = await stripe.prices.retrieve(opts.stripePriceId, {
55
+ expand: ["product"],
56
+ });
57
+ const product = price.product;
58
+ if (
59
+ !price.active ||
60
+ price.type !== "one_time" ||
61
+ !Number.isSafeInteger(price.unit_amount) ||
62
+ price.unit_amount! <= 0 ||
63
+ typeof product === "string" ||
64
+ product.deleted ||
65
+ !product.active
66
+ )
67
+ throw new Error(
68
+ "Payment Intents require an active product and a positive fixed one-time price.",
69
+ );
70
+ const intent = await stripe.paymentIntents.create(
71
+ {
72
+ amount: price.unit_amount!,
73
+ currency: price.currency,
74
+ customer_account: opts.customerAccount,
75
+ receipt_email: opts.receiptEmail,
76
+ ...(opts.paymentMethods === "automatic"
77
+ ? { automatic_payment_methods: { enabled: true } }
78
+ : { allowed_payment_method_types: ["card" as const] }),
79
+ metadata: {
80
+ ...stripReservedMetadata(opts.metadata),
81
+ userId: opts.userId,
82
+ stripePriceId: price.id,
83
+ stripeProductId: product.id,
84
+ },
85
+ },
86
+ request,
87
+ );
88
+ if (!intent.client_secret)
89
+ throw new Error("Stripe did not return a payment secret.");
90
+ return { paymentIntentId: intent.id, clientSecret: intent.client_secret };
91
+ }
92
+ export async function createSetupIntent(
93
+ stripe: Stripe,
94
+ component: Component,
95
+ ctx: RunCtx,
96
+ opts: CreateSetupIntentOptions,
97
+ ) {
98
+ if (!opts.customerAccount)
99
+ throw new Error("A customer account is required for setup.");
100
+ const request = await authorize(component, ctx, opts);
101
+ if (opts.consent !== true)
102
+ throw new Error("Explicit saved-card consent is required.");
103
+ if (opts.usage !== "on_session" && opts.usage !== "off_session")
104
+ throw new Error("Unsupported SetupIntent usage.");
105
+ const intent = await stripe.setupIntents.create(
106
+ {
107
+ customer_account: opts.customerAccount,
108
+ usage: opts.usage,
109
+ allowed_payment_method_types: ["card"],
110
+ metadata: {
111
+ ...stripReservedMetadata(opts.metadata),
112
+ userId: opts.userId,
113
+ },
114
+ },
115
+ request,
116
+ );
117
+ if (!intent.client_secret)
118
+ throw new Error("Stripe did not return a setup secret.");
119
+ return { setupIntentId: intent.id, clientSecret: intent.client_secret };
120
+ }
@@ -0,0 +1,94 @@
1
+ import type Stripe from "stripe";
2
+ import { componentsGeneric } from "convex/server";
3
+ import { expect, it, vi } from "vitest";
4
+ import { BetterStripe } from "../index.js";
5
+ import { getStripeClient, type Component, type RunCtx } from "../helpers.js";
6
+ it.each([undefined, "2026-09-30.preview"] as const)(
7
+ "sends customer-bound intents using configured Stripe version %s",
8
+ async (version) => {
9
+ const key = `sk_test_intent_transport_${crypto.randomUUID()}`;
10
+ const client = new BetterStripe(
11
+ componentsGeneric().betterStripe as unknown as Component,
12
+ { STRIPE_SECRET_KEY: key, stripeApiVersion: version },
13
+ );
14
+ const sdk = getStripeClient(key, version);
15
+ const calls: {
16
+ path: string;
17
+ version: string;
18
+ key?: string;
19
+ body: string;
20
+ }[] = [];
21
+ (
22
+ sdk as unknown as { _setApiField: (name: string, value: unknown) => void }
23
+ )._setApiField("httpClient", {
24
+ getClientName: () => "intent-contract-test",
25
+ makeRequest: async (
26
+ ...[, , path, , headers, body]: Parameters<
27
+ ReturnType<typeof Stripe.createNodeHttpClient>["makeRequest"]
28
+ >
29
+ ) => {
30
+ calls.push({
31
+ path,
32
+ version: String(headers["Stripe-Version"]),
33
+ key: headers["Idempotency-Key"] as string | undefined,
34
+ body,
35
+ });
36
+ const data = path.startsWith("/v1/prices/")
37
+ ? {
38
+ id: "price_one",
39
+ active: true,
40
+ type: "one_time",
41
+ unit_amount: 100,
42
+ currency: "usd",
43
+ product: { id: "prod_one", active: true },
44
+ }
45
+ : {
46
+ id: path.includes("setup_intents") ? "seti_one" : "pi_one",
47
+ client_secret: "secret",
48
+ };
49
+ return {
50
+ getStatusCode: () => 200,
51
+ getHeaders: () => ({}),
52
+ getRawResponse: () => ({}),
53
+ toJSON: async () => data,
54
+ toStream: () => {
55
+ throw new Error("Unexpected stream");
56
+ },
57
+ };
58
+ },
59
+ });
60
+ const ctx = {
61
+ runQuery: vi.fn().mockResolvedValue({ userId: "buyer" }),
62
+ } as unknown as RunCtx;
63
+ const scope = {
64
+ userId: "buyer",
65
+ customerAccount: "acct_buyer",
66
+ idempotencyKey: "save-one",
67
+ };
68
+ await client.createSetupIntent(ctx, {
69
+ ...scope,
70
+ usage: "off_session",
71
+ consent: true,
72
+ });
73
+ await client.createPaymentIntent(ctx, {
74
+ ...scope,
75
+ idempotencyKey: "pay-one",
76
+ stripePriceId: "price_one",
77
+ });
78
+ expect(calls.map((c) => c.version)).toEqual(
79
+ Array(3).fill(version ?? "2026-09-30.endive"),
80
+ );
81
+ const writes = calls.filter((c) => c.key);
82
+ expect(writes.map((c) => c.key)).toEqual(["save-one", "pay-one"]);
83
+ for (const call of writes) {
84
+ const params = new URLSearchParams(call.body);
85
+ expect(params.get("customer_account")).toBe("acct_buyer");
86
+ expect(params.get("allowed_payment_method_types[0]")).toBe("card");
87
+ expect(params.has("customer")).toBe(false);
88
+ }
89
+ expect(new URLSearchParams(writes[0].body).get("usage")).toBe(
90
+ "off_session",
91
+ );
92
+ expect(new URLSearchParams(writes[1].body).get("amount")).toBe("100");
93
+ },
94
+ );