@blocklet/payment-react-headless 1.26.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 (250) hide show
  1. package/.eslintrc.js +18 -0
  2. package/build.config.ts +30 -0
  3. package/es/checkout/context/CheckoutProvider.d.ts +6 -0
  4. package/es/checkout/context/CheckoutProvider.js +209 -0
  5. package/es/checkout/context/CustomerFormContext.d.ts +4 -0
  6. package/es/checkout/context/CustomerFormContext.js +9 -0
  7. package/es/checkout/context/ExchangeRateContext.d.ts +11 -0
  8. package/es/checkout/context/ExchangeRateContext.js +9 -0
  9. package/es/checkout/context/PaymentMethodContext.d.ts +26 -0
  10. package/es/checkout/context/PaymentMethodContext.js +9 -0
  11. package/es/checkout/context/SessionContext.d.ts +45 -0
  12. package/es/checkout/context/SessionContext.js +9 -0
  13. package/es/checkout/context/SubmitContext.d.ts +4 -0
  14. package/es/checkout/context/SubmitContext.js +9 -0
  15. package/es/checkout/context/index.d.ts +6 -0
  16. package/es/checkout/context/index.js +6 -0
  17. package/es/checkout/core/billingInterval.d.ts +15 -0
  18. package/es/checkout/core/billingInterval.js +36 -0
  19. package/es/checkout/core/crossSell.d.ts +4 -0
  20. package/es/checkout/core/crossSell.js +30 -0
  21. package/es/checkout/core/customerForm.d.ts +5 -0
  22. package/es/checkout/core/customerForm.js +105 -0
  23. package/es/checkout/core/exchangeRate.d.ts +11 -0
  24. package/es/checkout/core/exchangeRate.js +25 -0
  25. package/es/checkout/core/index.d.ts +10 -0
  26. package/es/checkout/core/index.js +55 -0
  27. package/es/checkout/core/lineItems.d.ts +7 -0
  28. package/es/checkout/core/lineItems.js +59 -0
  29. package/es/checkout/core/paymentMethod.d.ts +23 -0
  30. package/es/checkout/core/paymentMethod.js +85 -0
  31. package/es/checkout/core/pricing.d.ts +32 -0
  32. package/es/checkout/core/pricing.js +221 -0
  33. package/es/checkout/core/promotion.d.ts +10 -0
  34. package/es/checkout/core/promotion.js +39 -0
  35. package/es/checkout/core/session.d.ts +26 -0
  36. package/es/checkout/core/session.js +50 -0
  37. package/es/checkout/core/submit.d.ts +40 -0
  38. package/es/checkout/core/submit.js +66 -0
  39. package/es/checkout/hooks/index.d.ts +34 -0
  40. package/es/checkout/hooks/index.js +19 -0
  41. package/es/checkout/hooks/useBillingInterval.d.ts +14 -0
  42. package/es/checkout/hooks/useBillingInterval.js +50 -0
  43. package/es/checkout/hooks/useCheckout.d.ts +2 -0
  44. package/es/checkout/hooks/useCheckout.js +212 -0
  45. package/es/checkout/hooks/useCheckoutSession.d.ts +58 -0
  46. package/es/checkout/hooks/useCheckoutSession.js +107 -0
  47. package/es/checkout/hooks/useCheckoutStatus.d.ts +10 -0
  48. package/es/checkout/hooks/useCheckoutStatus.js +16 -0
  49. package/es/checkout/hooks/useCrossSell.d.ts +8 -0
  50. package/es/checkout/hooks/useCrossSell.js +57 -0
  51. package/es/checkout/hooks/useCustomerForm.d.ts +14 -0
  52. package/es/checkout/hooks/useCustomerForm.js +116 -0
  53. package/es/checkout/hooks/useCustomerFormFeature.d.ts +2 -0
  54. package/es/checkout/hooks/useCustomerFormFeature.js +4 -0
  55. package/es/checkout/hooks/useExchangeRate.d.ts +11 -0
  56. package/es/checkout/hooks/useExchangeRate.js +15 -0
  57. package/es/checkout/hooks/useLineItems.d.ts +22 -0
  58. package/es/checkout/hooks/useLineItems.js +139 -0
  59. package/es/checkout/hooks/usePaymentMethod.d.ts +26 -0
  60. package/es/checkout/hooks/usePaymentMethod.js +101 -0
  61. package/es/checkout/hooks/usePaymentMethodFeature.d.ts +2 -0
  62. package/es/checkout/hooks/usePaymentMethodFeature.js +4 -0
  63. package/es/checkout/hooks/usePricing.d.ts +57 -0
  64. package/es/checkout/hooks/usePricing.js +174 -0
  65. package/es/checkout/hooks/usePricingFeature.d.ts +28 -0
  66. package/es/checkout/hooks/usePricingFeature.js +36 -0
  67. package/es/checkout/hooks/useProduct.d.ts +32 -0
  68. package/es/checkout/hooks/useProduct.js +5 -0
  69. package/es/checkout/hooks/usePromotion.d.ts +12 -0
  70. package/es/checkout/hooks/usePromotion.js +48 -0
  71. package/es/checkout/hooks/useSlippage.d.ts +8 -0
  72. package/es/checkout/hooks/useSlippage.js +29 -0
  73. package/es/checkout/hooks/useSubmit.d.ts +38 -0
  74. package/es/checkout/hooks/useSubmit.js +493 -0
  75. package/es/checkout/hooks/useSubmitFeature.d.ts +2 -0
  76. package/es/checkout/hooks/useSubmitFeature.js +4 -0
  77. package/es/checkout/hooks/useUpsell.d.ts +5 -0
  78. package/es/checkout/hooks/useUpsell.js +25 -0
  79. package/es/checkout/index.d.ts +37 -0
  80. package/es/checkout/index.js +28 -0
  81. package/es/checkout/types.d.ts +262 -0
  82. package/es/checkout/types.js +0 -0
  83. package/es/index.d.ts +1 -0
  84. package/es/index.js +28 -0
  85. package/es/shared/api.d.ts +41 -0
  86. package/es/shared/api.js +81 -0
  87. package/es/shared/format.d.ts +38 -0
  88. package/es/shared/format.js +229 -0
  89. package/es/shared/polling.d.ts +15 -0
  90. package/es/shared/polling.js +20 -0
  91. package/es/shared/types.d.ts +10 -0
  92. package/es/shared/types.js +0 -0
  93. package/es/shared/validation.d.ts +38 -0
  94. package/es/shared/validation.js +190 -0
  95. package/es/types/checkout-augmented.d.ts +42 -0
  96. package/es/types/checkout-augmented.js +17 -0
  97. package/es/types/external.d.ts +18 -0
  98. package/examples/01-basic-checkout.tsx +159 -0
  99. package/examples/01-credit-recharge.tsx +19 -0
  100. package/examples/02-subscription.tsx +40 -0
  101. package/examples/03-upsell.tsx +60 -0
  102. package/examples/04-cross-sell.tsx +54 -0
  103. package/examples/05-full-checkout.tsx +126 -0
  104. package/jest.config.js +15 -0
  105. package/lib/checkout/context/CheckoutProvider.d.ts +6 -0
  106. package/lib/checkout/context/CheckoutProvider.js +181 -0
  107. package/lib/checkout/context/CustomerFormContext.d.ts +4 -0
  108. package/lib/checkout/context/CustomerFormContext.js +16 -0
  109. package/lib/checkout/context/ExchangeRateContext.d.ts +11 -0
  110. package/lib/checkout/context/ExchangeRateContext.js +16 -0
  111. package/lib/checkout/context/PaymentMethodContext.d.ts +26 -0
  112. package/lib/checkout/context/PaymentMethodContext.js +16 -0
  113. package/lib/checkout/context/SessionContext.d.ts +45 -0
  114. package/lib/checkout/context/SessionContext.js +16 -0
  115. package/lib/checkout/context/SubmitContext.d.ts +4 -0
  116. package/lib/checkout/context/SubmitContext.js +16 -0
  117. package/lib/checkout/context/index.d.ts +6 -0
  118. package/lib/checkout/context/index.js +77 -0
  119. package/lib/checkout/core/billingInterval.d.ts +15 -0
  120. package/lib/checkout/core/billingInterval.js +42 -0
  121. package/lib/checkout/core/crossSell.d.ts +4 -0
  122. package/lib/checkout/core/crossSell.js +43 -0
  123. package/lib/checkout/core/customerForm.d.ts +5 -0
  124. package/lib/checkout/core/customerForm.js +106 -0
  125. package/lib/checkout/core/exchangeRate.d.ts +11 -0
  126. package/lib/checkout/core/exchangeRate.js +45 -0
  127. package/lib/checkout/core/index.d.ts +10 -0
  128. package/lib/checkout/core/index.js +297 -0
  129. package/lib/checkout/core/lineItems.d.ts +7 -0
  130. package/lib/checkout/core/lineItems.js +76 -0
  131. package/lib/checkout/core/paymentMethod.d.ts +23 -0
  132. package/lib/checkout/core/paymentMethod.js +114 -0
  133. package/lib/checkout/core/pricing.d.ts +32 -0
  134. package/lib/checkout/core/pricing.js +216 -0
  135. package/lib/checkout/core/promotion.d.ts +10 -0
  136. package/lib/checkout/core/promotion.js +62 -0
  137. package/lib/checkout/core/session.d.ts +26 -0
  138. package/lib/checkout/core/session.js +58 -0
  139. package/lib/checkout/core/submit.d.ts +40 -0
  140. package/lib/checkout/core/submit.js +84 -0
  141. package/lib/checkout/hooks/index.d.ts +34 -0
  142. package/lib/checkout/hooks/index.js +138 -0
  143. package/lib/checkout/hooks/useBillingInterval.d.ts +14 -0
  144. package/lib/checkout/hooks/useBillingInterval.js +63 -0
  145. package/lib/checkout/hooks/useCheckout.d.ts +2 -0
  146. package/lib/checkout/hooks/useCheckout.js +190 -0
  147. package/lib/checkout/hooks/useCheckoutSession.d.ts +58 -0
  148. package/lib/checkout/hooks/useCheckoutSession.js +119 -0
  149. package/lib/checkout/hooks/useCheckoutStatus.d.ts +10 -0
  150. package/lib/checkout/hooks/useCheckoutStatus.js +28 -0
  151. package/lib/checkout/hooks/useCrossSell.d.ts +8 -0
  152. package/lib/checkout/hooks/useCrossSell.js +75 -0
  153. package/lib/checkout/hooks/useCustomerForm.d.ts +14 -0
  154. package/lib/checkout/hooks/useCustomerForm.js +135 -0
  155. package/lib/checkout/hooks/useCustomerFormFeature.d.ts +2 -0
  156. package/lib/checkout/hooks/useCustomerFormFeature.js +10 -0
  157. package/lib/checkout/hooks/useExchangeRate.d.ts +11 -0
  158. package/lib/checkout/hooks/useExchangeRate.js +29 -0
  159. package/lib/checkout/hooks/useLineItems.d.ts +22 -0
  160. package/lib/checkout/hooks/useLineItems.js +142 -0
  161. package/lib/checkout/hooks/usePaymentMethod.d.ts +26 -0
  162. package/lib/checkout/hooks/usePaymentMethod.js +101 -0
  163. package/lib/checkout/hooks/usePaymentMethodFeature.d.ts +2 -0
  164. package/lib/checkout/hooks/usePaymentMethodFeature.js +10 -0
  165. package/lib/checkout/hooks/usePricing.d.ts +57 -0
  166. package/lib/checkout/hooks/usePricing.js +168 -0
  167. package/lib/checkout/hooks/usePricingFeature.d.ts +28 -0
  168. package/lib/checkout/hooks/usePricingFeature.js +48 -0
  169. package/lib/checkout/hooks/useProduct.d.ts +32 -0
  170. package/lib/checkout/hooks/useProduct.js +21 -0
  171. package/lib/checkout/hooks/usePromotion.d.ts +12 -0
  172. package/lib/checkout/hooks/usePromotion.js +57 -0
  173. package/lib/checkout/hooks/useSlippage.d.ts +8 -0
  174. package/lib/checkout/hooks/useSlippage.js +39 -0
  175. package/lib/checkout/hooks/useSubmit.d.ts +38 -0
  176. package/lib/checkout/hooks/useSubmit.js +504 -0
  177. package/lib/checkout/hooks/useSubmitFeature.d.ts +2 -0
  178. package/lib/checkout/hooks/useSubmitFeature.js +10 -0
  179. package/lib/checkout/hooks/useUpsell.d.ts +5 -0
  180. package/lib/checkout/hooks/useUpsell.js +40 -0
  181. package/lib/checkout/index.d.ts +37 -0
  182. package/lib/checkout/index.js +182 -0
  183. package/lib/checkout/types.d.ts +262 -0
  184. package/lib/checkout/types.js +1 -0
  185. package/lib/index.d.ts +1 -0
  186. package/lib/index.js +162 -0
  187. package/lib/shared/api.d.ts +41 -0
  188. package/lib/shared/api.js +88 -0
  189. package/lib/shared/format.d.ts +38 -0
  190. package/lib/shared/format.js +262 -0
  191. package/lib/shared/polling.d.ts +15 -0
  192. package/lib/shared/polling.js +32 -0
  193. package/lib/shared/types.d.ts +10 -0
  194. package/lib/shared/types.js +1 -0
  195. package/lib/shared/validation.d.ts +38 -0
  196. package/lib/shared/validation.js +212 -0
  197. package/lib/types/checkout-augmented.d.ts +42 -0
  198. package/lib/types/checkout-augmented.js +24 -0
  199. package/lib/types/external.d.ts +18 -0
  200. package/package.json +64 -0
  201. package/src/checkout/context/CheckoutProvider.tsx +269 -0
  202. package/src/checkout/context/CustomerFormContext.ts +14 -0
  203. package/src/checkout/context/ExchangeRateContext.ts +21 -0
  204. package/src/checkout/context/PaymentMethodContext.ts +36 -0
  205. package/src/checkout/context/SessionContext.ts +49 -0
  206. package/src/checkout/context/SubmitContext.ts +14 -0
  207. package/src/checkout/context/index.ts +6 -0
  208. package/src/checkout/core/billingInterval.ts +62 -0
  209. package/src/checkout/core/crossSell.ts +52 -0
  210. package/src/checkout/core/customerForm.ts +122 -0
  211. package/src/checkout/core/exchangeRate.ts +38 -0
  212. package/src/checkout/core/index.ts +60 -0
  213. package/src/checkout/core/lineItems.ts +106 -0
  214. package/src/checkout/core/paymentMethod.ts +113 -0
  215. package/src/checkout/core/pricing.ts +347 -0
  216. package/src/checkout/core/promotion.ts +59 -0
  217. package/src/checkout/core/session.ts +62 -0
  218. package/src/checkout/core/submit.ts +109 -0
  219. package/src/checkout/hooks/index.ts +41 -0
  220. package/src/checkout/hooks/useBillingInterval.ts +71 -0
  221. package/src/checkout/hooks/useCheckout.ts +267 -0
  222. package/src/checkout/hooks/useCheckoutSession.ts +217 -0
  223. package/src/checkout/hooks/useCheckoutStatus.ts +31 -0
  224. package/src/checkout/hooks/useCrossSell.ts +80 -0
  225. package/src/checkout/hooks/useCustomerForm.ts +156 -0
  226. package/src/checkout/hooks/useCustomerFormFeature.ts +7 -0
  227. package/src/checkout/hooks/useExchangeRate.ts +28 -0
  228. package/src/checkout/hooks/useLineItems.ts +191 -0
  229. package/src/checkout/hooks/usePaymentMethod.ts +165 -0
  230. package/src/checkout/hooks/usePaymentMethodFeature.ts +8 -0
  231. package/src/checkout/hooks/usePricing.ts +274 -0
  232. package/src/checkout/hooks/usePricingFeature.ts +73 -0
  233. package/src/checkout/hooks/useProduct.ts +32 -0
  234. package/src/checkout/hooks/usePromotion.ts +67 -0
  235. package/src/checkout/hooks/useSlippage.ts +39 -0
  236. package/src/checkout/hooks/useSubmit.ts +684 -0
  237. package/src/checkout/hooks/useSubmitFeature.ts +7 -0
  238. package/src/checkout/hooks/useUpsell.ts +35 -0
  239. package/src/checkout/index.ts +65 -0
  240. package/src/checkout/types.ts +292 -0
  241. package/src/index.ts +64 -0
  242. package/src/shared/api.ts +118 -0
  243. package/src/shared/format.ts +318 -0
  244. package/src/shared/polling.ts +49 -0
  245. package/src/shared/types.ts +13 -0
  246. package/src/shared/validation.ts +254 -0
  247. package/src/types/checkout-augmented.ts +77 -0
  248. package/src/types/external.d.ts +18 -0
  249. package/tools/jest.js +1 -0
  250. package/tsconfig.json +18 -0
@@ -0,0 +1,504 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useSubmit = useSubmit;
7
+ var _react = require("react");
8
+ var _ahooks = require("ahooks");
9
+ var _ws = require("@arcblock/ws");
10
+ var _api = _interopRequireWildcard(require("../../shared/api"));
11
+ var _polling = require("../../shared/polling");
12
+ var _checkoutAugmented = require("../../types/checkout-augmented");
13
+ var _submit = require("../core/submit");
14
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
15
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
16
+ function useSubmit(sessionData, sessionId, currencyId, isStripe, isCredit, isDonation, formValues, validateForm, refreshSession, updateSessionData) {
17
+ const session = sessionData?.checkoutSession;
18
+ const [status, setStatus] = (0, _react.useState)("idle");
19
+ const [context, setContext] = (0, _react.useState)(null);
20
+ const [result, setResult] = (0, _react.useState)(null);
21
+ const [locked, setLocked] = (0, _react.useState)(false);
22
+ const lock = (0, _ahooks.useMemoizedFn)(() => setLocked(true));
23
+ const unlock = (0, _ahooks.useMemoizedFn)(() => setLocked(false));
24
+ const mountedRef = (0, _react.useRef)(true);
25
+ const pollingAbortRef = (0, _react.useRef)(false);
26
+ const socketRef = (0, _react.useRef)(null);
27
+ const subscriptionRef = (0, _react.useRef)(null);
28
+ const lastPayloadRef = (0, _react.useRef)(null);
29
+ const [vendorStatus, setVendorStatus] = (0, _react.useState)(null);
30
+ const vendorTimerRef = (0, _react.useRef)(null);
31
+ const quoteRetryCountRef = (0, _react.useRef)(0);
32
+ const MAX_QUOTE_RETRIES = 2;
33
+ const idempotencyKeyRef = (0, _react.useRef)("");
34
+ const sessionFingerprintRef = (0, _react.useRef)("");
35
+ const completedDetectedRef = (0, _react.useRef)(false);
36
+ (0, _react.useEffect)(() => {
37
+ if (completedDetectedRef.current) return;
38
+ if (!session || !sessionData) return;
39
+ const isSessionComplete = session.status === "complete" && ["paid", "no_payment_required"].includes(session.payment_status);
40
+ if (isSessionComplete && status === "idle") {
41
+ completedDetectedRef.current = true;
42
+ setResult(sessionData);
43
+ setStatus("completed");
44
+ }
45
+ }, [session, sessionData]);
46
+ (0, _react.useEffect)(() => {
47
+ mountedRef.current = true;
48
+ if (!sessionId || !(0, _submit.getAppId)()) return void 0;
49
+ const socket = new _ws.WsClient(`${(0, _submit.getRelayProtocol)()}//${(0, _submit.getSocketHost)()}${_submit.RELAY_SOCKET_PREFIX}`, {
50
+ longpollerTimeout: 5e3,
51
+ heartbeatIntervalMs: 30 * 1e3
52
+ });
53
+ socket.connect();
54
+ socketRef.current = socket;
55
+ const sub = socket.subscribe((0, _submit.getRelayChannel)("events"));
56
+ sub.channel = "events";
57
+ subscriptionRef.current = sub;
58
+ return () => {
59
+ mountedRef.current = false;
60
+ pollingAbortRef.current = true;
61
+ if (subscriptionRef.current) {
62
+ socket.unsubscribe((0, _submit.getRelayChannel)(subscriptionRef.current.channel));
63
+ subscriptionRef.current = null;
64
+ }
65
+ socket.disconnect();
66
+ socketRef.current = null;
67
+ };
68
+ }, [sessionId]);
69
+ const handleWsComplete = (0, _ahooks.useMemoizedFn)(async ({
70
+ response
71
+ }) => {
72
+ if (response.id === sessionId && status !== "completed") {
73
+ pollingAbortRef.current = true;
74
+ await handleCompletion();
75
+ }
76
+ });
77
+ (0, _react.useEffect)(() => {
78
+ const sub = subscriptionRef.current;
79
+ if (sub) {
80
+ sub.on("checkout.session.completed", handleWsComplete);
81
+ }
82
+ return () => {
83
+ if (sub) {
84
+ try {
85
+ sub.off?.("checkout.session.completed", handleWsComplete);
86
+ } catch {}
87
+ }
88
+ };
89
+ }, [subscriptionRef.current, status]);
90
+ const handleCompletion = (0, _ahooks.useMemoizedFn)(async () => {
91
+ try {
92
+ const completionResult = await (0, _polling.waitForCheckoutComplete)(sessionId);
93
+ if (!mountedRef.current) return;
94
+ setResult(completionResult);
95
+ updateSessionData?.(completionResult);
96
+ setStatus("completed");
97
+ setContext(null);
98
+ } catch (err) {
99
+ if (!mountedRef.current) return;
100
+ setStatus("failed");
101
+ setContext({
102
+ type: "error",
103
+ message: (0, _checkoutAugmented.getErrorMessage)(err) || "Payment verification failed"
104
+ });
105
+ }
106
+ });
107
+ (0, _react.useEffect)(() => {
108
+ if (status !== "completed" || !sessionId) return void 0;
109
+ const hasVendors = session?.line_items?.some(item => !!item?.price?.product?.vendor_config?.length);
110
+ if (!hasVendors) return void 0;
111
+ const startTime = Date.now();
112
+ const fetchVendorStatus = async () => {
113
+ try {
114
+ const {
115
+ data
116
+ } = await _api.default.get(_api.API.VENDOR_ORDER_STATUS(sessionId));
117
+ if (!mountedRef.current) return;
118
+ const needCheckError = Date.now() - startTime > 6e3;
119
+ const allCompleted = data?.vendors?.every(v => v.progress >= 100);
120
+ const hasFailed = data?.vendors?.some(v => v.status === "failed" || needCheckError && !!v.error && !!v.error_message);
121
+ setVendorStatus({
122
+ ...data,
123
+ isAllCompleted: !hasFailed && allCompleted,
124
+ hasFailed
125
+ });
126
+ if (hasFailed || allCompleted) return;
127
+ vendorTimerRef.current = setTimeout(fetchVendorStatus, 5e3);
128
+ } catch {}
129
+ };
130
+ fetchVendorStatus();
131
+ return () => {
132
+ if (vendorTimerRef.current) clearTimeout(vendorTimerRef.current);
133
+ };
134
+ }, [status, sessionId]);
135
+ const handleQuoteError = (0, _ahooks.useMemoizedFn)(async (errorCode, errorData) => {
136
+ try {
137
+ await refreshSession(true);
138
+ if (!mountedRef.current) return;
139
+ } catch {}
140
+ if (errorCode === "QUOTE_UPDATED" && errorData?.checkoutSession) {
141
+ quoteRetryCountRef.current = 0;
142
+ setStatus("failed");
143
+ setContext({
144
+ type: "error",
145
+ message: "Price updated, please resubmit",
146
+ code: errorCode
147
+ });
148
+ return;
149
+ }
150
+ const canAutoRetry = ["QUOTE_LOCK_EXPIRED", "QUOTE_EXPIRED_OR_USED", "QUOTE_NOT_FOUND", "QUOTE_REQUIRED"].includes(errorCode);
151
+ if (canAutoRetry && quoteRetryCountRef.current < MAX_QUOTE_RETRIES) {
152
+ quoteRetryCountRef.current += 1;
153
+ setStatus("idle");
154
+ setContext(null);
155
+ await execute(true);
156
+ return;
157
+ }
158
+ quoteRetryCountRef.current = 0;
159
+ setStatus("failed");
160
+ setContext({
161
+ type: "error",
162
+ message: "Price updated, please resubmit",
163
+ code: errorCode
164
+ });
165
+ });
166
+ const routeSubmitResponse = (0, _ahooks.useMemoizedFn)(async data => {
167
+ if (isStripe) {
168
+ const stripeCtx = data.stripeContext;
169
+ if (stripeCtx?.status === "succeeded") {
170
+ await handleCompletion();
171
+ return;
172
+ }
173
+ const piCtx = data.paymentIntent;
174
+ const clientSecret = stripeCtx?.client_secret || piCtx?.client_secret;
175
+ if (clientSecret) {
176
+ const intentType = stripeCtx?.intent_type || "payment_intent";
177
+ setStatus("waiting_stripe");
178
+ setContext({
179
+ type: "stripe",
180
+ clientSecret,
181
+ intentType
182
+ });
183
+ return;
184
+ }
185
+ if (data.noPaymentRequired) {
186
+ try {
187
+ const confirmResult = await (0, _submit.confirmFastCheckout)(sessionId);
188
+ const confirmSession = confirmResult.checkoutSession;
189
+ if (confirmResult.fastPaid || confirmSession?.status === "complete") {
190
+ await handleCompletion();
191
+ return;
192
+ }
193
+ } catch {}
194
+ }
195
+ await handleCompletion();
196
+ return;
197
+ }
198
+ if (data.noPaymentRequired) {
199
+ try {
200
+ const confirmResult = await (0, _submit.confirmFastCheckout)(sessionId);
201
+ const confirmSession = confirmResult.checkoutSession;
202
+ if (confirmResult.fastPaid || confirmSession?.status === "complete") {
203
+ await handleCompletion();
204
+ } else {
205
+ setStatus("waiting_did");
206
+ setContext({
207
+ type: "did_connect",
208
+ action: session?.mode || "payment",
209
+ checkpointId: sessionId,
210
+ extraParams: {
211
+ checkoutSessionId: sessionId,
212
+ sessionUserDid: session?.user?.did
213
+ }
214
+ });
215
+ }
216
+ } catch {
217
+ if (!mountedRef.current) return;
218
+ setStatus("waiting_did");
219
+ setContext({
220
+ type: "did_connect",
221
+ action: session?.mode || "payment",
222
+ checkpointId: sessionId,
223
+ extraParams: {
224
+ checkoutSessionId: sessionId,
225
+ sessionUserDid: session?.user?.did
226
+ }
227
+ });
228
+ }
229
+ return;
230
+ }
231
+ const fastPayInfo = data.fastPayInfo;
232
+ const balance = data.balance;
233
+ const delegation = data.delegation;
234
+ if (isCredit) {
235
+ if (data.creditSufficient === true && fastPayInfo) {
236
+ setStatus("confirming_fast_pay");
237
+ setContext({
238
+ type: "fast_pay",
239
+ payType: "credit",
240
+ amount: fastPayInfo.amount || "0",
241
+ payer: fastPayInfo.payer || ""
242
+ });
243
+ return;
244
+ }
245
+ setStatus("credit_insufficient");
246
+ setContext({
247
+ type: "credit_insufficient",
248
+ available: "0",
249
+ required: "0"
250
+ });
251
+ return;
252
+ }
253
+ if ((balance?.sufficient || delegation?.sufficient) && !isDonation && fastPayInfo) {
254
+ setStatus("confirming_fast_pay");
255
+ setContext({
256
+ type: "fast_pay",
257
+ payType: fastPayInfo.type || "balance",
258
+ amount: fastPayInfo.amount || "",
259
+ payer: fastPayInfo.payer || ""
260
+ });
261
+ return;
262
+ }
263
+ setStatus("waiting_did");
264
+ setContext({
265
+ type: "did_connect",
266
+ action: session?.mode || "payment",
267
+ checkpointId: sessionId,
268
+ extraParams: {
269
+ checkoutSessionId: sessionId,
270
+ sessionUserDid: session?.user?.did
271
+ }
272
+ });
273
+ });
274
+ const handleSubmitError = (0, _ahooks.useMemoizedFn)(async err => {
275
+ const {
276
+ code: errorCode,
277
+ data: errorData,
278
+ message: errMessage
279
+ } = (0, _checkoutAugmented.getAxiosErrorDetails)(err);
280
+ if (errorCode && (0, _submit.isQuoteError)(errorCode)) {
281
+ await handleQuoteError(errorCode, errorData);
282
+ return;
283
+ }
284
+ if (errorCode === "RATE_BELOW_SLIPPAGE_LIMIT") {
285
+ try {
286
+ await refreshSession(true);
287
+ } catch {}
288
+ if (!mountedRef.current) return;
289
+ idempotencyKeyRef.current = "";
290
+ sessionFingerprintRef.current = "";
291
+ setStatus("failed");
292
+ setContext({
293
+ type: "error",
294
+ message: errorData?.error || "Exchange rate below acceptable limit, please retry",
295
+ code: errorCode
296
+ });
297
+ return;
298
+ }
299
+ if (errorCode === "RATE_UNAVAILABLE") {
300
+ try {
301
+ await refreshSession(true);
302
+ } catch {}
303
+ if (!mountedRef.current) return;
304
+ setStatus("failed");
305
+ setContext({
306
+ type: "error",
307
+ message: errorData?.rateError || "Exchange rate unavailable",
308
+ code: errorCode
309
+ });
310
+ return;
311
+ }
312
+ if (errorCode === "PRICE_CHANGED") {
313
+ setStatus("confirming_price");
314
+ setContext({
315
+ type: "price_change",
316
+ changePercent: errorData?.change_percent || 0
317
+ });
318
+ return;
319
+ }
320
+ if (errorCode === "PRICE_UNAVAILABLE" || errorCode === "PRICE_UNSTABLE") {
321
+ try {
322
+ await refreshSession(true);
323
+ } catch {}
324
+ if (!mountedRef.current) return;
325
+ setStatus("failed");
326
+ setContext({
327
+ type: "error",
328
+ message: errorData?.error || "Price unavailable, please retry",
329
+ code: errorCode
330
+ });
331
+ return;
332
+ }
333
+ if (errorCode === "UNIFIED_APP_REQUIRED" || errorCode === "CUSTOMER_LIMITED") {
334
+ setStatus("failed");
335
+ setContext({
336
+ type: "error",
337
+ message: errorData?.error || errMessage || "Cannot complete payment",
338
+ code: errorCode
339
+ });
340
+ return;
341
+ }
342
+ const message = errorData?.error || errMessage || "Payment failed";
343
+ setStatus("failed");
344
+ setContext({
345
+ type: "error",
346
+ message,
347
+ code: errorCode
348
+ });
349
+ });
350
+ const execute = (0, _ahooks.useMemoizedFn)(async (force = false) => {
351
+ if (!force && status !== "idle") return;
352
+ if (!force) quoteRetryCountRef.current = 0;
353
+ if (!(await validateForm())) return;
354
+ const user = session?.user;
355
+ if (!user?.sourceAppPid) {
356
+ const hasVendorConfig = session?.line_items?.some(item => !!item?.price?.product?.vendor_config?.length);
357
+ if (hasVendorConfig) {
358
+ setStatus("failed");
359
+ setContext({
360
+ type: "error",
361
+ message: "Vendor account required",
362
+ code: "VENDOR_ACCOUNT_REQUIRED"
363
+ });
364
+ return;
365
+ }
366
+ }
367
+ setStatus("submitting");
368
+ setContext(null);
369
+ setResult(null);
370
+ pollingAbortRef.current = false;
371
+ const fingerprint = (0, _submit.getSessionFingerprint)(session, currencyId);
372
+ if (fingerprint !== sessionFingerprintRef.current || !idempotencyKeyRef.current) {
373
+ sessionFingerprintRef.current = fingerprint;
374
+ idempotencyKeyRef.current = (0, _polling.generateIdempotencyKey)(sessionId, currencyId || "");
375
+ }
376
+ const payload = (0, _submit.buildSubmitPayload)(sessionId, currencyId, formValues, session, false, idempotencyKeyRef.current);
377
+ lastPayloadRef.current = payload;
378
+ try {
379
+ const data = await (0, _submit.submitCheckout)(sessionId, isDonation, payload);
380
+ if (!mountedRef.current) return;
381
+ await routeSubmitResponse(data);
382
+ } catch (err) {
383
+ if (!mountedRef.current) return;
384
+ await handleSubmitError(err);
385
+ }
386
+ });
387
+ const confirm = (0, _ahooks.useMemoizedFn)(async () => {
388
+ if (status === "confirming_fast_pay") {
389
+ setStatus("submitting");
390
+ try {
391
+ const data = await (0, _submit.confirmFastCheckout)(sessionId);
392
+ if (!mountedRef.current) return;
393
+ if (data.fastPaid) {
394
+ await handleCompletion();
395
+ } else {
396
+ setStatus("waiting_did");
397
+ setContext({
398
+ type: "did_connect",
399
+ action: session?.mode || "payment",
400
+ checkpointId: sessionId,
401
+ extraParams: {
402
+ checkoutSessionId: sessionId,
403
+ sessionUserDid: session?.user?.did
404
+ }
405
+ });
406
+ }
407
+ } catch (err) {
408
+ if (!mountedRef.current) return;
409
+ const {
410
+ code: errorCode,
411
+ data: errorData,
412
+ message: errMsg
413
+ } = (0, _checkoutAugmented.getAxiosErrorDetails)(err);
414
+ if (errorCode && (0, _submit.isQuoteError)(errorCode)) {
415
+ await handleQuoteError(errorCode, errorData);
416
+ return;
417
+ }
418
+ if (errorCode === "RATE_UNAVAILABLE") {
419
+ try {
420
+ await refreshSession(true);
421
+ } catch {}
422
+ if (!mountedRef.current) return;
423
+ setStatus("failed");
424
+ setContext({
425
+ type: "error",
426
+ message: errorData?.rateError || "Exchange rate unavailable",
427
+ code: errorCode
428
+ });
429
+ return;
430
+ }
431
+ setStatus("failed");
432
+ setContext({
433
+ type: "error",
434
+ message: errorData?.error || errMsg || "Fast pay confirmation failed",
435
+ code: errorCode
436
+ });
437
+ }
438
+ return;
439
+ }
440
+ if (status === "confirming_price") {
441
+ setStatus("submitting");
442
+ setContext(null);
443
+ pollingAbortRef.current = false;
444
+ const payload = (0, _submit.buildSubmitPayload)(sessionId, currencyId, formValues, session, true, idempotencyKeyRef.current);
445
+ lastPayloadRef.current = payload;
446
+ try {
447
+ const data = await (0, _submit.submitCheckout)(sessionId, isDonation, payload);
448
+ if (!mountedRef.current) return;
449
+ await routeSubmitResponse(data);
450
+ } catch (err) {
451
+ if (!mountedRef.current) return;
452
+ await handleSubmitError(err);
453
+ }
454
+ }
455
+ });
456
+ const cancel = (0, _ahooks.useMemoizedFn)(() => {
457
+ if (status === "confirming_price" || status === "confirming_fast_pay" || status === "credit_insufficient") {
458
+ setStatus("idle");
459
+ setContext(null);
460
+ unlock();
461
+ }
462
+ });
463
+ const retry = (0, _ahooks.useMemoizedFn)(async () => {
464
+ if (status !== "failed") return;
465
+ setStatus("idle");
466
+ setContext(null);
467
+ setResult(null);
468
+ await execute(true);
469
+ });
470
+ const reset = (0, _ahooks.useMemoizedFn)(() => {
471
+ pollingAbortRef.current = true;
472
+ setStatus("idle");
473
+ setContext(null);
474
+ setResult(null);
475
+ unlock();
476
+ });
477
+ const stripeConfirm = (0, _ahooks.useMemoizedFn)(async () => {
478
+ if (status !== "waiting_stripe") return;
479
+ setStatus("submitting");
480
+ setContext(null);
481
+ await handleCompletion();
482
+ });
483
+ const stripeCancel = (0, _ahooks.useMemoizedFn)(async () => {
484
+ if (status !== "waiting_stripe") return;
485
+ await (0, _submit.abortStripePayment)(sessionId);
486
+ setStatus("idle");
487
+ setContext(null);
488
+ });
489
+ return {
490
+ status,
491
+ context,
492
+ execute,
493
+ confirm,
494
+ cancel,
495
+ result,
496
+ retry,
497
+ reset,
498
+ stripeConfirm,
499
+ stripeCancel,
500
+ vendorStatus,
501
+ locked,
502
+ lock
503
+ };
504
+ }
@@ -0,0 +1,2 @@
1
+ import type { UseSubmitReturn } from './useSubmit';
2
+ export declare function useSubmitFeature(): UseSubmitReturn;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useSubmitFeature = useSubmitFeature;
7
+ var _SubmitContext = require("../context/SubmitContext");
8
+ function useSubmitFeature() {
9
+ return (0, _SubmitContext.useSubmitContext)();
10
+ }
@@ -0,0 +1,5 @@
1
+ export interface UseUpsellReturn {
2
+ upsell: (fromId: string, toId: string) => Promise<void>;
3
+ downsell: (priceId: string) => Promise<void>;
4
+ }
5
+ export declare function useUpsell(): UseUpsellReturn;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useUpsell = useUpsell;
7
+ var _ahooks = require("ahooks");
8
+ var _checkoutAugmented = require("../../types/checkout-augmented");
9
+ var _SessionContext = require("../context/SessionContext");
10
+ var _PaymentMethodContext = require("../context/PaymentMethodContext");
11
+ var _lineItems = require("../core/lineItems");
12
+ function useUpsell() {
13
+ const {
14
+ session,
15
+ effectiveSessionId,
16
+ refresh
17
+ } = (0, _SessionContext.useSessionContext)();
18
+ const {
19
+ currency
20
+ } = (0, _PaymentMethodContext.usePaymentMethodContext)();
21
+ const currencyId = currency?.id || null;
22
+ const upsell = (0, _ahooks.useMemoizedFn)(async (fromId, toId) => {
23
+ try {
24
+ await (0, _lineItems.performUpsell)(effectiveSessionId, fromId, toId, session, currencyId, refresh);
25
+ } catch (err) {
26
+ console.error("Failed to upsell:", (0, _checkoutAugmented.getErrorMessage)(err));
27
+ }
28
+ });
29
+ const downsell = (0, _ahooks.useMemoizedFn)(async priceId => {
30
+ try {
31
+ await (0, _lineItems.performDownsell)(effectiveSessionId, priceId, session, currencyId, refresh);
32
+ } catch (err) {
33
+ console.error("Failed to downsell:", (0, _checkoutAugmented.getErrorMessage)(err));
34
+ }
35
+ });
36
+ return {
37
+ upsell,
38
+ downsell
39
+ };
40
+ }
@@ -0,0 +1,37 @@
1
+ export type { UseCheckoutReturn, SubmitStatus, SubmitContext, FieldConfig, CheckoutFormData, CheckoutResult, } from './types';
2
+ export { CheckoutProvider, type CheckoutProviderProps, useSessionContext, usePaymentMethodContext, useExchangeRateContext, useCustomerFormContext, useSubmitContext, } from './context';
3
+ export { useCheckout } from './hooks/useCheckout';
4
+ export { useCheckoutSession } from './hooks/useCheckoutSession';
5
+ export type { UseCheckoutSessionReturn, SessionData } from './hooks/useCheckoutSession';
6
+ export { usePaymentMethod } from './hooks/usePaymentMethod';
7
+ export type { UsePaymentMethodReturn } from './hooks/usePaymentMethod';
8
+ export { usePricing } from './hooks/usePricing';
9
+ export type { UsePricingReturn } from './hooks/usePricing';
10
+ export { useCustomerForm } from './hooks/useCustomerForm';
11
+ export type { UseCustomerFormReturn } from './hooks/useCustomerForm';
12
+ export { useSubmit } from './hooks/useSubmit';
13
+ export type { UseSubmitReturn } from './hooks/useSubmit';
14
+ export { useProduct } from './hooks/useProduct';
15
+ export type { UseProductReturn } from './hooks/useProduct';
16
+ export { useLineItems } from './hooks/useLineItems';
17
+ export type { UseLineItemsReturn } from './hooks/useLineItems';
18
+ export { useBillingInterval } from './hooks/useBillingInterval';
19
+ export type { UseBillingIntervalReturn, BillingIntervalData } from './hooks/useBillingInterval';
20
+ export { useUpsell } from './hooks/useUpsell';
21
+ export type { UseUpsellReturn } from './hooks/useUpsell';
22
+ export { useCrossSell } from './hooks/useCrossSell';
23
+ export type { UseCrossSellReturn } from './hooks/useCrossSell';
24
+ export { usePromotion } from './hooks/usePromotion';
25
+ export type { UsePromotionReturn } from './hooks/usePromotion';
26
+ export { useExchangeRate } from './hooks/useExchangeRate';
27
+ export type { UseExchangeRateReturn } from './hooks/useExchangeRate';
28
+ export { useSlippage } from './hooks/useSlippage';
29
+ export type { UseSlippageReturn } from './hooks/useSlippage';
30
+ export { useCheckoutStatus } from './hooks/useCheckoutStatus';
31
+ export type { UseCheckoutStatusReturn } from './hooks/useCheckoutStatus';
32
+ export { usePricingFeature } from './hooks/usePricingFeature';
33
+ export type { UsePricingFeatureReturn } from './hooks/usePricingFeature';
34
+ export { usePaymentMethodFeature } from './hooks/usePaymentMethodFeature';
35
+ export { useCustomerFormFeature } from './hooks/useCustomerFormFeature';
36
+ export { useSubmitFeature } from './hooks/useSubmitFeature';
37
+ export { getPriceUnitAmountByCurrency } from '../shared/format';