@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.
- package/CHANGELOG.md +17 -0
- package/README.md +63 -1
- package/dist/client/billing/checkoutOptions.d.ts +27 -0
- package/dist/client/billing/checkoutOptions.d.ts.map +1 -0
- package/dist/client/billing/checkoutOptions.js +2 -0
- package/dist/client/billing/checkoutOptions.js.map +1 -0
- package/dist/client/billing/intents.d.ts +32 -0
- package/dist/client/billing/intents.d.ts.map +1 -0
- package/dist/client/billing/intents.js +71 -0
- package/dist/client/billing/intents.js.map +1 -0
- package/dist/client/connect/disputes.d.ts +20 -0
- package/dist/client/connect/disputes.d.ts.map +1 -1
- package/dist/client/connect/disputes.js +55 -0
- package/dist/client/connect/disputes.js.map +1 -1
- package/dist/client/core/fees.d.ts +2 -0
- package/dist/client/core/fees.d.ts.map +1 -1
- package/dist/client/core/fees.js +7 -0
- package/dist/client/core/fees.js.map +1 -1
- package/dist/client/costRecovery-invoices.d.ts +10 -4
- package/dist/client/costRecovery-invoices.d.ts.map +1 -1
- package/dist/client/costRecovery-invoices.js +4 -0
- package/dist/client/costRecovery-invoices.js.map +1 -1
- package/dist/client/costRecovery.d.ts +18 -2
- package/dist/client/costRecovery.d.ts.map +1 -1
- package/dist/client/costRecovery.js +4 -0
- package/dist/client/costRecovery.js.map +1 -1
- package/dist/client/errors.d.ts +1 -1
- package/dist/client/errors.d.ts.map +1 -1
- package/dist/client/errors.js.map +1 -1
- package/dist/client/index.d.ts +20 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +18 -20
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +59 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/costRecovery/claims.d.ts +12 -0
- package/dist/component/costRecovery/claims.d.ts.map +1 -1
- package/dist/component/costRecovery/imports.d.ts +53 -0
- package/dist/component/costRecovery/imports.d.ts.map +1 -0
- package/dist/component/costRecovery/imports.js +67 -0
- package/dist/component/costRecovery/imports.js.map +1 -0
- package/dist/component/costRecovery/mutations.d.ts +47 -0
- package/dist/component/costRecovery/mutations.d.ts.map +1 -1
- package/dist/component/costRecovery/mutations.js +7 -1
- package/dist/component/costRecovery/mutations.js.map +1 -1
- package/dist/component/costRecovery/queries.d.ts +12 -0
- package/dist/component/costRecovery/queries.d.ts.map +1 -1
- package/dist/component/costRecovery/schema.d.ts +72 -2
- package/dist/component/costRecovery/schema.d.ts.map +1 -1
- package/dist/component/costRecovery/schema.js +13 -0
- package/dist/component/costRecovery/schema.js.map +1 -1
- package/dist/component/schema.d.ts +19 -1
- package/dist/react/hooks/useConfirmPayment.d.ts +1 -1
- package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
- package/dist/react/hooks/useConfirmPayment.js +13 -2
- package/dist/react/hooks/useConfirmPayment.js.map +1 -1
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/workflows/EvidenceUpload.d.ts +18 -0
- package/dist/react/workflows/EvidenceUpload.d.ts.map +1 -0
- package/dist/react/workflows/EvidenceUpload.js +35 -0
- package/dist/react/workflows/EvidenceUpload.js.map +1 -0
- package/dist/react/workflows/Onboarding.d.ts +3 -3
- package/dist/react/workflows/Onboarding.d.ts.map +1 -1
- package/dist/react/workflows/Onboarding.js +8 -6
- package/dist/react/workflows/Onboarding.js.map +1 -1
- package/dist/react/workflows/SaveCard.d.ts +27 -0
- package/dist/react/workflows/SaveCard.d.ts.map +1 -0
- package/dist/react/workflows/SaveCard.js +56 -0
- package/dist/react/workflows/SaveCard.js.map +1 -0
- package/dist/react/workflows/index.d.ts +2 -0
- package/dist/react/workflows/index.d.ts.map +1 -1
- package/dist/react/workflows/index.js +1 -0
- package/dist/react/workflows/index.js.map +1 -1
- package/dist/react/workflows/useWorkflowAction.d.ts +1 -1
- package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -1
- package/dist/react/workflows/useWorkflowAction.js +6 -2
- package/dist/react/workflows/useWorkflowAction.js.map +1 -1
- package/docs/react-workflows.md +83 -0
- package/package.json +1 -1
- package/src/client/billing/checkoutOptions.ts +27 -0
- package/src/client/billing/intents.test.ts +216 -0
- package/src/client/billing/intents.ts +120 -0
- package/src/client/billing/intentsTransport.test.ts +94 -0
- package/src/client/connect/dispute-upload.test.ts +208 -0
- package/src/client/connect/disputes.ts +103 -0
- package/src/client/core/fees.ts +8 -0
- package/src/client/costRecovery-import.test.ts +174 -0
- package/src/client/costRecovery-invoices.test.ts +69 -0
- package/src/client/costRecovery-invoices.ts +32 -0
- package/src/client/costRecovery.ts +16 -0
- package/src/client/errors.ts +1 -0
- package/src/client/index.ts +50 -52
- package/src/component/_generated/api.ts +2 -0
- package/src/component/_generated/component.ts +65 -0
- package/src/component/costRecovery/imports.ts +74 -0
- package/src/component/costRecovery/mutations.ts +8 -0
- package/src/component/costRecovery/schema.ts +13 -0
- package/src/react/hooks/useConfirmPayment.test.tsx +47 -0
- package/src/react/hooks/useConfirmPayment.ts +16 -2
- package/src/react/index.ts +3 -0
- package/src/react/workflows/EvidenceUpload.test.tsx +56 -0
- package/src/react/workflows/EvidenceUpload.tsx +71 -0
- package/src/react/workflows/Onboarding.test.tsx +73 -0
- package/src/react/workflows/Onboarding.tsx +8 -5
- package/src/react/workflows/SaveCard.test.tsx +127 -0
- package/src/react/workflows/SaveCard.tsx +117 -0
- package/src/react/workflows/index.ts +3 -0
- 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,
|
|
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
|
-
|
|
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":"AAAA,YAAY,CAAC;AACb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AASjE,6GAA6G;AAC7G,MAAM,UAAU,iBAAiB,CAC/B,MAAqC,EACrC,KAAK,GAAW,SAAS;
|
|
1
|
+
{"version":3,"file":"useWorkflowAction.js","sourceRoot":"","sources":["../../../src/react/workflows/useWorkflowAction.ts"],"names":[],"mappings":"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"}
|
package/docs/react-workflows.md
CHANGED
|
@@ -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
|
@@ -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
|
+
);
|