@teleporthq/teleport-plugin-next-workflows 0.43.67 → 0.43.69

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 (787) hide show
  1. package/__tests__/_helpers/bind-workflow-utils.ts +16 -1
  2. package/__tests__/_helpers/fake-fetch.ts +96 -0
  3. package/__tests__/_helpers/fake-stripe.ts +52 -0
  4. package/__tests__/_helpers/load-handler.ts +22 -3
  5. package/__tests__/_helpers/load-invoice-route.ts +75 -0
  6. package/__tests__/_helpers/load-payment-drivers.ts +69 -0
  7. package/__tests__/_helpers/load-server-runtime.ts +33 -0
  8. package/__tests__/_helpers/run-generated-middleware.ts +50 -9
  9. package/__tests__/admin-form-hydration-target.test.ts +39 -0
  10. package/__tests__/admin-form-row-hydration.test.ts +58 -0
  11. package/__tests__/ai-select-database-data-handler.test.ts +14 -3
  12. package/__tests__/api-route-file-name-segments.test.ts +33 -0
  13. package/__tests__/app-secret-env.test.ts +55 -0
  14. package/__tests__/auth-env-secret-preservation.test.ts +22 -3
  15. package/__tests__/auth-nextauth-url.test.ts +134 -50
  16. package/__tests__/cart-add-item-kinds.test.ts +259 -0
  17. package/__tests__/cart-add-item-line-fields.test.ts +328 -0
  18. package/__tests__/cart-availability-add-to-cart.test.ts +108 -0
  19. package/__tests__/cart-get-total-discounts.test.ts +499 -0
  20. package/__tests__/cart-get-total-product-options.test.ts +195 -0
  21. package/__tests__/cart-get-total-subscriptions.test.ts +221 -0
  22. package/__tests__/cart-price-order.test.ts +283 -0
  23. package/__tests__/cart-update-item-quantity-recurring.test.ts +75 -0
  24. package/__tests__/client-loop-current-item.test.ts +164 -0
  25. package/__tests__/cron-route-loop-custom-node.test.ts +123 -0
  26. package/__tests__/cron-route-loop-templateparams.test.ts +7 -0
  27. package/__tests__/cron-route-verification.test.ts +252 -0
  28. package/__tests__/custom-js-runtime-base-url.test.ts +64 -0
  29. package/__tests__/custom-nodes-admin-module.test.ts +310 -0
  30. package/__tests__/data-api-browser-reads.test.ts +341 -0
  31. package/__tests__/data-api-low-stock-autofire.test.ts +67 -17
  32. package/__tests__/data-api-optional-feature-columns.test.ts +240 -0
  33. package/__tests__/data-api-protected-tables.test.ts +948 -0
  34. package/__tests__/data-node-not-awaited.test.ts +7 -3
  35. package/__tests__/data-write-missing-filter.test.ts +119 -0
  36. package/__tests__/ecommerce-rewriter-product-options.test.ts +143 -0
  37. package/__tests__/email-locale-senders.test.ts +1 -1
  38. package/__tests__/file-storage-upload-picked-files.test.ts +20 -0
  39. package/__tests__/input-debounce-per-field.test.ts +141 -0
  40. package/__tests__/internal-request-headers.test.ts +7 -3
  41. package/__tests__/invoice-data-access-replace.test.ts +340 -0
  42. package/__tests__/invoice-delivery-fee.test.ts +3 -2
  43. package/__tests__/invoice-generate-hydration.test.ts +20 -12
  44. package/__tests__/invoice-order-items-settle.test.ts +51 -46
  45. package/__tests__/invoice-product-options.test.ts +177 -0
  46. package/__tests__/invoice-regenerate-route.test.ts +488 -0
  47. package/__tests__/invoice-regional-tax.test.ts +3 -2
  48. package/__tests__/invoice-reservation.test.ts +195 -0
  49. package/__tests__/invoice-route-access.test.ts +275 -0
  50. package/__tests__/invoice-self-call-origin.test.ts +117 -0
  51. package/__tests__/invoice-tender.test.ts +550 -0
  52. package/__tests__/legacy-webhook-self-calls.test.ts +187 -0
  53. package/__tests__/locale-aware-redirects.test.ts +55 -26
  54. package/__tests__/loop-collection-unwrap.test.ts +6 -1
  55. package/__tests__/middleware-subscriber-access.test.ts +269 -0
  56. package/__tests__/payment-charge-user-earlier-attempt.test.ts +267 -0
  57. package/__tests__/payment-charge-user-handler-serialization.test.ts +47 -82
  58. package/__tests__/payment-charge-user-line-descriptions.test.ts +124 -0
  59. package/__tests__/payment-charge-user-report-refusal.test.ts +105 -0
  60. package/__tests__/payment-close-checkout-node.test.ts +127 -0
  61. package/__tests__/payment-driver-close-checkout.test.ts +1163 -0
  62. package/__tests__/payment-driver-coingate.test.ts +470 -0
  63. package/__tests__/payment-driver-inspect-checkout.test.ts +648 -0
  64. package/__tests__/payment-driver-mollie.test.ts +864 -0
  65. package/__tests__/payment-driver-paddle.test.ts +870 -0
  66. package/__tests__/payment-driver-paypal-capture.test.ts +158 -0
  67. package/__tests__/payment-driver-paypal-webhook.test.ts +367 -0
  68. package/__tests__/payment-driver-razorpay.test.ts +895 -0
  69. package/__tests__/payment-driver-square.test.ts +977 -0
  70. package/__tests__/payment-driver-stripe.test.ts +267 -0
  71. package/__tests__/payment-drivers-module.test.ts +429 -0
  72. package/__tests__/payment-legacy-webhook-routes.test.ts +588 -0
  73. package/__tests__/payment-redirect-and-order-notification.test.ts +98 -39
  74. package/__tests__/payment-refund.test.ts +523 -22
  75. package/__tests__/payment-subscription-nodes.test.ts +1360 -0
  76. package/__tests__/payment-webhook-route.test.ts +523 -0
  77. package/__tests__/paypal-webhook-signature-verification.test.ts +205 -0
  78. package/__tests__/prune-context-oversized-leaf.test.ts +1 -0
  79. package/__tests__/prune-context-state-keys.test.ts +89 -0
  80. package/__tests__/push-node-handlers.test.ts +291 -0
  81. package/__tests__/route-changed-trigger.test.ts +40 -0
  82. package/__tests__/runtime-storage-upload-access.test.ts +255 -0
  83. package/__tests__/security-runtime-shadow.test.ts +103 -1
  84. package/__tests__/segment-reply-changed-keys.test.ts +146 -0
  85. package/__tests__/segment-state-keys-emission.test.ts +185 -0
  86. package/__tests__/segment-state-needs.test.ts +102 -0
  87. package/__tests__/server-segment-context-integrity.test.ts +210 -0
  88. package/__tests__/server-step-signing.test.ts +371 -0
  89. package/__tests__/session-cookie-resolver.test.ts +59 -0
  90. package/__tests__/stock-decrement-audit.test.ts +17 -0
  91. package/__tests__/subscriber-access-route.test.ts +406 -0
  92. package/__tests__/webhook-delivery-lease.test.ts +316 -0
  93. package/__tests__/workflow-auth-guard.test.ts +253 -2
  94. package/dist/cjs/admin-form-hydration.d.ts +10 -0
  95. package/dist/cjs/admin-form-hydration.d.ts.map +1 -0
  96. package/dist/cjs/admin-form-hydration.js +25 -0
  97. package/dist/cjs/admin-form-hydration.js.map +1 -0
  98. package/dist/cjs/api-route-generator.d.ts +19 -3
  99. package/dist/cjs/api-route-generator.d.ts.map +1 -1
  100. package/dist/cjs/api-route-generator.js +190 -70
  101. package/dist/cjs/api-route-generator.js.map +1 -1
  102. package/dist/cjs/auth-generator.d.ts +4 -1
  103. package/dist/cjs/auth-generator.d.ts.map +1 -1
  104. package/dist/cjs/auth-generator.js +241 -62
  105. package/dist/cjs/auth-generator.js.map +1 -1
  106. package/dist/cjs/auth-return/signed-in-destination-code.d.ts +17 -0
  107. package/dist/cjs/auth-return/signed-in-destination-code.d.ts.map +1 -0
  108. package/dist/cjs/auth-return/signed-in-destination-code.js +37 -0
  109. package/dist/cjs/auth-return/signed-in-destination-code.js.map +1 -0
  110. package/dist/cjs/cart-pricing-preamble.d.ts +12 -0
  111. package/dist/cjs/cart-pricing-preamble.d.ts.map +1 -0
  112. package/dist/cjs/cart-pricing-preamble.js +23 -0
  113. package/dist/cjs/cart-pricing-preamble.js.map +1 -0
  114. package/dist/cjs/cron-request-verification.d.ts +24 -0
  115. package/dist/cjs/cron-request-verification.d.ts.map +1 -0
  116. package/dist/cjs/cron-request-verification.js +84 -0
  117. package/dist/cjs/cron-request-verification.js.map +1 -0
  118. package/dist/cjs/custom-node-modules.d.ts +30 -0
  119. package/dist/cjs/custom-node-modules.d.ts.map +1 -0
  120. package/dist/cjs/custom-node-modules.js +90 -0
  121. package/dist/cjs/custom-node-modules.js.map +1 -0
  122. package/dist/cjs/data-api-route-generator.d.ts +27 -0
  123. package/dist/cjs/data-api-route-generator.d.ts.map +1 -1
  124. package/dist/cjs/data-api-route-generator.js +366 -29
  125. package/dist/cjs/data-api-route-generator.js.map +1 -1
  126. package/dist/cjs/ecommerce/cart-availability.d.ts.map +1 -1
  127. package/dist/cjs/ecommerce/cart-availability.js +22 -13
  128. package/dist/cjs/ecommerce/cart-availability.js.map +1 -1
  129. package/dist/cjs/ecommerce/stock-decrement.d.ts +2 -1
  130. package/dist/cjs/ecommerce/stock-decrement.d.ts.map +1 -1
  131. package/dist/cjs/ecommerce/stock-decrement.js +6 -0
  132. package/dist/cjs/ecommerce/stock-decrement.js.map +1 -1
  133. package/dist/cjs/executor-generator.d.ts +0 -1
  134. package/dist/cjs/executor-generator.d.ts.map +1 -1
  135. package/dist/cjs/executor-generator.js +213 -20
  136. package/dist/cjs/executor-generator.js.map +1 -1
  137. package/dist/cjs/index.d.ts +12 -4
  138. package/dist/cjs/index.d.ts.map +1 -1
  139. package/dist/cjs/index.js +25 -2
  140. package/dist/cjs/index.js.map +1 -1
  141. package/dist/cjs/invoice/api-routes-code.d.ts +26 -0
  142. package/dist/cjs/invoice/api-routes-code.d.ts.map +1 -1
  143. package/dist/cjs/invoice/api-routes-code.js +423 -391
  144. package/dist/cjs/invoice/api-routes-code.js.map +1 -1
  145. package/dist/cjs/invoice/data-access-code.d.ts.map +1 -1
  146. package/dist/cjs/invoice/data-access-code.js +420 -107
  147. package/dist/cjs/invoice/data-access-code.js.map +1 -1
  148. package/dist/cjs/invoice/index.d.ts.map +1 -1
  149. package/dist/cjs/invoice/index.js +24 -0
  150. package/dist/cjs/invoice/index.js.map +1 -1
  151. package/dist/cjs/invoice/invoice-assembly-code.d.ts +12 -0
  152. package/dist/cjs/invoice/invoice-assembly-code.d.ts.map +1 -0
  153. package/dist/cjs/invoice/invoice-assembly-code.js +517 -0
  154. package/dist/cjs/invoice/invoice-assembly-code.js.map +1 -0
  155. package/dist/cjs/invoice/invoice-html-code.d.ts.map +1 -1
  156. package/dist/cjs/invoice/invoice-html-code.js +111 -9
  157. package/dist/cjs/invoice/invoice-html-code.js.map +1 -1
  158. package/dist/cjs/invoice/pdf-service-client-code.d.ts.map +1 -1
  159. package/dist/cjs/invoice/pdf-service-client-code.js +3 -4
  160. package/dist/cjs/invoice/pdf-service-client-code.js.map +1 -1
  161. package/dist/cjs/nodes/account/account-login.d.ts.map +1 -1
  162. package/dist/cjs/nodes/account/account-login.js +4 -3
  163. package/dist/cjs/nodes/account/account-login.js.map +1 -1
  164. package/dist/cjs/nodes/account/account-signup.d.ts.map +1 -1
  165. package/dist/cjs/nodes/account/account-signup.js +7 -4
  166. package/dist/cjs/nodes/account/account-signup.js.map +1 -1
  167. package/dist/cjs/nodes/ai/ai-select-database-data.d.ts.map +1 -1
  168. package/dist/cjs/nodes/ai/ai-select-database-data.js +6 -1
  169. package/dist/cjs/nodes/ai/ai-select-database-data.js.map +1 -1
  170. package/dist/cjs/nodes/browser/browser-get-push-subscription.d.ts +9 -0
  171. package/dist/cjs/nodes/browser/browser-get-push-subscription.d.ts.map +1 -0
  172. package/dist/cjs/nodes/browser/browser-get-push-subscription.js +25 -0
  173. package/dist/cjs/nodes/browser/browser-get-push-subscription.js.map +1 -0
  174. package/dist/cjs/nodes/browser/browser-show-notification.d.ts +10 -0
  175. package/dist/cjs/nodes/browser/browser-show-notification.d.ts.map +1 -1
  176. package/dist/cjs/nodes/browser/browser-show-notification.js +65 -40
  177. package/dist/cjs/nodes/browser/browser-show-notification.js.map +1 -1
  178. package/dist/cjs/nodes/browser/browser-subscribe-to-push.d.ts +11 -0
  179. package/dist/cjs/nodes/browser/browser-subscribe-to-push.d.ts.map +1 -1
  180. package/dist/cjs/nodes/browser/browser-subscribe-to-push.js +21 -31
  181. package/dist/cjs/nodes/browser/browser-subscribe-to-push.js.map +1 -1
  182. package/dist/cjs/nodes/browser/browser-unsubscribe-from-push.d.ts +8 -0
  183. package/dist/cjs/nodes/browser/browser-unsubscribe-from-push.d.ts.map +1 -0
  184. package/dist/cjs/nodes/browser/browser-unsubscribe-from-push.js +24 -0
  185. package/dist/cjs/nodes/browser/browser-unsubscribe-from-push.js.map +1 -0
  186. package/dist/cjs/nodes/browser/push-api-access.d.ts +12 -0
  187. package/dist/cjs/nodes/browser/push-api-access.d.ts.map +1 -0
  188. package/dist/cjs/nodes/browser/push-api-access.js +19 -0
  189. package/dist/cjs/nodes/browser/push-api-access.js.map +1 -0
  190. package/dist/cjs/nodes/cart/cart-add-item.d.ts.map +1 -1
  191. package/dist/cjs/nodes/cart/cart-add-item.js +174 -10
  192. package/dist/cjs/nodes/cart/cart-add-item.js.map +1 -1
  193. package/dist/cjs/nodes/cart/cart-clear.d.ts.map +1 -1
  194. package/dist/cjs/nodes/cart/cart-clear.js +11 -0
  195. package/dist/cjs/nodes/cart/cart-clear.js.map +1 -1
  196. package/dist/cjs/nodes/cart/cart-get-total.d.ts.map +1 -1
  197. package/dist/cjs/nodes/cart/cart-get-total.js +260 -3
  198. package/dist/cjs/nodes/cart/cart-get-total.js.map +1 -1
  199. package/dist/cjs/nodes/cart/cart-price-order.d.ts +3 -0
  200. package/dist/cjs/nodes/cart/cart-price-order.d.ts.map +1 -0
  201. package/dist/cjs/nodes/cart/cart-price-order.js +281 -0
  202. package/dist/cjs/nodes/cart/cart-price-order.js.map +1 -0
  203. package/dist/cjs/nodes/cart/cart-update-item-quantity.d.ts.map +1 -1
  204. package/dist/cjs/nodes/cart/cart-update-item-quantity.js +7 -0
  205. package/dist/cjs/nodes/cart/cart-update-item-quantity.js.map +1 -1
  206. package/dist/cjs/nodes/data/data-count.d.ts.map +1 -1
  207. package/dist/cjs/nodes/data/data-count.js +6 -1
  208. package/dist/cjs/nodes/data/data-count.js.map +1 -1
  209. package/dist/cjs/nodes/data/data-create-item.d.ts.map +1 -1
  210. package/dist/cjs/nodes/data/data-create-item.js +11 -1
  211. package/dist/cjs/nodes/data/data-create-item.js.map +1 -1
  212. package/dist/cjs/nodes/data/data-delete-item.d.ts.map +1 -1
  213. package/dist/cjs/nodes/data/data-delete-item.js +29 -0
  214. package/dist/cjs/nodes/data/data-delete-item.js.map +1 -1
  215. package/dist/cjs/nodes/data/data-raw-query.d.ts.map +1 -1
  216. package/dist/cjs/nodes/data/data-raw-query.js +6 -1
  217. package/dist/cjs/nodes/data/data-raw-query.js.map +1 -1
  218. package/dist/cjs/nodes/data/data-select.d.ts.map +1 -1
  219. package/dist/cjs/nodes/data/data-select.js +6 -1
  220. package/dist/cjs/nodes/data/data-select.js.map +1 -1
  221. package/dist/cjs/nodes/data/data-update-item.d.ts.map +1 -1
  222. package/dist/cjs/nodes/data/data-update-item.js +29 -0
  223. package/dist/cjs/nodes/data/data-update-item.js.map +1 -1
  224. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
  225. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js +7 -1
  226. package/dist/cjs/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
  227. package/dist/cjs/nodes/file-storage/file-storage-upload.d.ts.map +1 -1
  228. package/dist/cjs/nodes/file-storage/file-storage-upload.js +7 -0
  229. package/dist/cjs/nodes/file-storage/file-storage-upload.js.map +1 -1
  230. package/dist/cjs/nodes/general/general-custom-js.d.ts.map +1 -1
  231. package/dist/cjs/nodes/general/general-custom-js.js +21 -5
  232. package/dist/cjs/nodes/general/general-custom-js.js.map +1 -1
  233. package/dist/cjs/nodes/index.d.ts.map +1 -1
  234. package/dist/cjs/nodes/index.js +9 -4
  235. package/dist/cjs/nodes/index.js.map +1 -1
  236. package/dist/cjs/nodes/payment/payment-billing-portal.d.ts +3 -0
  237. package/dist/cjs/nodes/payment/payment-billing-portal.d.ts.map +1 -0
  238. package/dist/cjs/nodes/payment/payment-billing-portal.js +52 -0
  239. package/dist/cjs/nodes/payment/payment-billing-portal.js.map +1 -0
  240. package/dist/cjs/nodes/payment/payment-charge-user.d.ts.map +1 -1
  241. package/dist/cjs/nodes/payment/payment-charge-user.js +227 -360
  242. package/dist/cjs/nodes/payment/payment-charge-user.js.map +1 -1
  243. package/dist/cjs/nodes/payment/payment-close-checkout.d.ts +3 -0
  244. package/dist/cjs/nodes/payment/payment-close-checkout.d.ts.map +1 -0
  245. package/dist/cjs/nodes/payment/payment-close-checkout.js +141 -0
  246. package/dist/cjs/nodes/payment/payment-close-checkout.js.map +1 -0
  247. package/dist/cjs/nodes/payment/payment-ensure-subscription-plan.d.ts +3 -0
  248. package/dist/cjs/nodes/payment/payment-ensure-subscription-plan.d.ts.map +1 -0
  249. package/dist/cjs/nodes/payment/payment-ensure-subscription-plan.js +67 -0
  250. package/dist/cjs/nodes/payment/payment-ensure-subscription-plan.js.map +1 -0
  251. package/dist/cjs/nodes/payment/payment-manage-subscription.d.ts +3 -0
  252. package/dist/cjs/nodes/payment/payment-manage-subscription.d.ts.map +1 -0
  253. package/dist/cjs/nodes/payment/payment-manage-subscription.js +89 -0
  254. package/dist/cjs/nodes/payment/payment-manage-subscription.js.map +1 -0
  255. package/dist/cjs/nodes/payment/payment-refund.d.ts.map +1 -1
  256. package/dist/cjs/nodes/payment/payment-refund.js +50 -404
  257. package/dist/cjs/nodes/payment/payment-refund.js.map +1 -1
  258. package/dist/cjs/nodes/push/push-send-notification.d.ts +14 -0
  259. package/dist/cjs/nodes/push/push-send-notification.d.ts.map +1 -0
  260. package/dist/cjs/nodes/push/push-send-notification.js +83 -0
  261. package/dist/cjs/nodes/push/push-send-notification.js.map +1 -0
  262. package/dist/cjs/payments/drivers/coingate-driver-code.d.ts +16 -0
  263. package/dist/cjs/payments/drivers/coingate-driver-code.d.ts.map +1 -0
  264. package/dist/cjs/payments/drivers/coingate-driver-code.js +471 -0
  265. package/dist/cjs/payments/drivers/coingate-driver-code.js.map +1 -0
  266. package/dist/cjs/payments/drivers/mollie-driver-code.d.ts +16 -0
  267. package/dist/cjs/payments/drivers/mollie-driver-code.d.ts.map +1 -0
  268. package/dist/cjs/payments/drivers/mollie-driver-code.js +623 -0
  269. package/dist/cjs/payments/drivers/mollie-driver-code.js.map +1 -0
  270. package/dist/cjs/payments/drivers/paddle-driver-code.d.ts +12 -0
  271. package/dist/cjs/payments/drivers/paddle-driver-code.d.ts.map +1 -0
  272. package/dist/cjs/payments/drivers/paddle-driver-code.js +683 -0
  273. package/dist/cjs/payments/drivers/paddle-driver-code.js.map +1 -0
  274. package/dist/cjs/payments/drivers/paypal-driver-code.d.ts +12 -0
  275. package/dist/cjs/payments/drivers/paypal-driver-code.d.ts.map +1 -0
  276. package/dist/cjs/payments/drivers/paypal-driver-code.js +1261 -0
  277. package/dist/cjs/payments/drivers/paypal-driver-code.js.map +1 -0
  278. package/dist/cjs/payments/drivers/razorpay-driver-code.d.ts +12 -0
  279. package/dist/cjs/payments/drivers/razorpay-driver-code.d.ts.map +1 -0
  280. package/dist/cjs/payments/drivers/razorpay-driver-code.js +732 -0
  281. package/dist/cjs/payments/drivers/razorpay-driver-code.js.map +1 -0
  282. package/dist/cjs/payments/drivers/square-driver-code.d.ts +14 -0
  283. package/dist/cjs/payments/drivers/square-driver-code.d.ts.map +1 -0
  284. package/dist/cjs/payments/drivers/square-driver-code.js +931 -0
  285. package/dist/cjs/payments/drivers/square-driver-code.js.map +1 -0
  286. package/dist/cjs/payments/drivers/stripe-driver-code.d.ts +12 -0
  287. package/dist/cjs/payments/drivers/stripe-driver-code.d.ts.map +1 -0
  288. package/dist/cjs/payments/drivers/stripe-driver-code.js +778 -0
  289. package/dist/cjs/payments/drivers/stripe-driver-code.js.map +1 -0
  290. package/dist/cjs/payments/index.d.ts +66 -0
  291. package/dist/cjs/payments/index.d.ts.map +1 -0
  292. package/dist/cjs/payments/index.js +175 -0
  293. package/dist/cjs/payments/index.js.map +1 -0
  294. package/dist/cjs/payments/payment-core-code.d.ts +19 -0
  295. package/dist/cjs/payments/payment-core-code.d.ts.map +1 -0
  296. package/dist/cjs/payments/payment-core-code.js +422 -0
  297. package/dist/cjs/payments/payment-core-code.js.map +1 -0
  298. package/dist/cjs/payments/payment-driver-code-map.d.ts +4 -0
  299. package/dist/cjs/payments/payment-driver-code-map.d.ts.map +1 -0
  300. package/dist/cjs/payments/payment-driver-code-map.js +21 -0
  301. package/dist/cjs/payments/payment-driver-code-map.js.map +1 -0
  302. package/dist/cjs/payments/payment-drivers-scope.d.ts +35 -0
  303. package/dist/cjs/payments/payment-drivers-scope.d.ts.map +1 -0
  304. package/dist/cjs/payments/payment-drivers-scope.js +56 -0
  305. package/dist/cjs/payments/payment-drivers-scope.js.map +1 -0
  306. package/dist/cjs/payments/payment-registry-code.d.ts +8 -0
  307. package/dist/cjs/payments/payment-registry-code.d.ts.map +1 -0
  308. package/dist/cjs/payments/payment-registry-code.js +41 -0
  309. package/dist/cjs/payments/payment-registry-code.js.map +1 -0
  310. package/dist/cjs/pg-client-code.d.ts +10 -0
  311. package/dist/cjs/pg-client-code.d.ts.map +1 -1
  312. package/dist/cjs/pg-client-code.js +27 -1
  313. package/dist/cjs/pg-client-code.js.map +1 -1
  314. package/dist/cjs/runtime-storage-generator.d.ts +28 -0
  315. package/dist/cjs/runtime-storage-generator.d.ts.map +1 -1
  316. package/dist/cjs/runtime-storage-generator.js +240 -5
  317. package/dist/cjs/runtime-storage-generator.js.map +1 -1
  318. package/dist/cjs/secret-collector.d.ts.map +1 -1
  319. package/dist/cjs/secret-collector.js +8 -3
  320. package/dist/cjs/secret-collector.js.map +1 -1
  321. package/dist/cjs/security-scanner.d.ts +10 -1
  322. package/dist/cjs/security-scanner.d.ts.map +1 -1
  323. package/dist/cjs/security-scanner.js +19 -1
  324. package/dist/cjs/security-scanner.js.map +1 -1
  325. package/dist/cjs/segment-context-needs.d.ts +38 -0
  326. package/dist/cjs/segment-context-needs.d.ts.map +1 -0
  327. package/dist/cjs/segment-context-needs.js +129 -0
  328. package/dist/cjs/segment-context-needs.js.map +1 -0
  329. package/dist/cjs/segment-splitter.d.ts.map +1 -1
  330. package/dist/cjs/segment-splitter.js +6 -1
  331. package/dist/cjs/segment-splitter.js.map +1 -1
  332. package/dist/cjs/segment-trust.d.ts +50 -0
  333. package/dist/cjs/segment-trust.d.ts.map +1 -0
  334. package/dist/cjs/segment-trust.js +115 -0
  335. package/dist/cjs/segment-trust.js.map +1 -0
  336. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts +19 -0
  337. package/dist/cjs/sent-email-log/sent-email-log-code.d.ts.map +1 -1
  338. package/dist/cjs/sent-email-log/sent-email-log-code.js +1 -24
  339. package/dist/cjs/sent-email-log/sent-email-log-code.js.map +1 -1
  340. package/dist/cjs/server-runtime-code.d.ts +34 -0
  341. package/dist/cjs/server-runtime-code.d.ts.map +1 -0
  342. package/dist/cjs/server-runtime-code.js +303 -0
  343. package/dist/cjs/server-runtime-code.js.map +1 -0
  344. package/dist/cjs/session-cookie-resolver.d.ts +3 -78
  345. package/dist/cjs/session-cookie-resolver.d.ts.map +1 -1
  346. package/dist/cjs/session-cookie-resolver.js +7 -276
  347. package/dist/cjs/session-cookie-resolver.js.map +1 -1
  348. package/dist/cjs/subscriber-access-route-generator.d.ts +71 -0
  349. package/dist/cjs/subscriber-access-route-generator.d.ts.map +1 -0
  350. package/dist/cjs/subscriber-access-route-generator.js +301 -0
  351. package/dist/cjs/subscriber-access-route-generator.js.map +1 -0
  352. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  353. package/dist/cjs/types.d.ts +6 -0
  354. package/dist/cjs/types.d.ts.map +1 -1
  355. package/dist/cjs/webhook-delivery-lease/index.d.ts +8 -0
  356. package/dist/cjs/webhook-delivery-lease/index.d.ts.map +1 -0
  357. package/dist/cjs/webhook-delivery-lease/index.js +41 -0
  358. package/dist/cjs/webhook-delivery-lease/index.js.map +1 -0
  359. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.d.ts +26 -0
  360. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.d.ts.map +1 -0
  361. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.js +151 -0
  362. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-code.js.map +1 -0
  363. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-scope.d.ts +16 -0
  364. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-scope.d.ts.map +1 -0
  365. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-scope.js +19 -0
  366. package/dist/cjs/webhook-delivery-lease/webhook-delivery-lease-scope.js.map +1 -0
  367. package/dist/cjs/webhook-generator.d.ts +1 -1
  368. package/dist/cjs/webhook-generator.d.ts.map +1 -1
  369. package/dist/cjs/webhook-generator.js +342 -254
  370. package/dist/cjs/webhook-generator.js.map +1 -1
  371. package/dist/cjs/webhook-signature-verification.d.ts +17 -1
  372. package/dist/cjs/webhook-signature-verification.d.ts.map +1 -1
  373. package/dist/cjs/webhook-signature-verification.js +182 -27
  374. package/dist/cjs/webhook-signature-verification.js.map +1 -1
  375. package/dist/cjs/workflow-auth-generator.d.ts +9 -6
  376. package/dist/cjs/workflow-auth-generator.d.ts.map +1 -1
  377. package/dist/cjs/workflow-auth-generator.js +133 -29
  378. package/dist/cjs/workflow-auth-generator.js.map +1 -1
  379. package/dist/cjs/workflow-component-plugin.d.ts.map +1 -1
  380. package/dist/cjs/workflow-component-plugin.js +65 -28
  381. package/dist/cjs/workflow-component-plugin.js.map +1 -1
  382. package/dist/cjs/workflow-project-plugin.d.ts +13 -0
  383. package/dist/cjs/workflow-project-plugin.d.ts.map +1 -1
  384. package/dist/cjs/workflow-project-plugin.js +215 -65
  385. package/dist/cjs/workflow-project-plugin.js.map +1 -1
  386. package/dist/esm/admin-form-hydration.d.ts +10 -0
  387. package/dist/esm/admin-form-hydration.d.ts.map +1 -0
  388. package/dist/esm/admin-form-hydration.js +21 -0
  389. package/dist/esm/admin-form-hydration.js.map +1 -0
  390. package/dist/esm/api-route-generator.d.ts +19 -3
  391. package/dist/esm/api-route-generator.d.ts.map +1 -1
  392. package/dist/esm/api-route-generator.js +189 -70
  393. package/dist/esm/api-route-generator.js.map +1 -1
  394. package/dist/esm/auth-generator.d.ts +4 -1
  395. package/dist/esm/auth-generator.d.ts.map +1 -1
  396. package/dist/esm/auth-generator.js +241 -62
  397. package/dist/esm/auth-generator.js.map +1 -1
  398. package/dist/esm/auth-return/signed-in-destination-code.d.ts +17 -0
  399. package/dist/esm/auth-return/signed-in-destination-code.d.ts.map +1 -0
  400. package/dist/esm/auth-return/signed-in-destination-code.js +33 -0
  401. package/dist/esm/auth-return/signed-in-destination-code.js.map +1 -0
  402. package/dist/esm/cart-pricing-preamble.d.ts +12 -0
  403. package/dist/esm/cart-pricing-preamble.d.ts.map +1 -0
  404. package/dist/esm/cart-pricing-preamble.js +19 -0
  405. package/dist/esm/cart-pricing-preamble.js.map +1 -0
  406. package/dist/esm/cron-request-verification.d.ts +24 -0
  407. package/dist/esm/cron-request-verification.d.ts.map +1 -0
  408. package/dist/esm/cron-request-verification.js +80 -0
  409. package/dist/esm/cron-request-verification.js.map +1 -0
  410. package/dist/esm/custom-node-modules.d.ts +30 -0
  411. package/dist/esm/custom-node-modules.d.ts.map +1 -0
  412. package/dist/esm/custom-node-modules.js +84 -0
  413. package/dist/esm/custom-node-modules.js.map +1 -0
  414. package/dist/esm/data-api-route-generator.d.ts +27 -0
  415. package/dist/esm/data-api-route-generator.d.ts.map +1 -1
  416. package/dist/esm/data-api-route-generator.js +365 -28
  417. package/dist/esm/data-api-route-generator.js.map +1 -1
  418. package/dist/esm/ecommerce/cart-availability.d.ts.map +1 -1
  419. package/dist/esm/ecommerce/cart-availability.js +22 -13
  420. package/dist/esm/ecommerce/cart-availability.js.map +1 -1
  421. package/dist/esm/ecommerce/stock-decrement.d.ts +2 -1
  422. package/dist/esm/ecommerce/stock-decrement.d.ts.map +1 -1
  423. package/dist/esm/ecommerce/stock-decrement.js +6 -0
  424. package/dist/esm/ecommerce/stock-decrement.js.map +1 -1
  425. package/dist/esm/executor-generator.d.ts +0 -1
  426. package/dist/esm/executor-generator.d.ts.map +1 -1
  427. package/dist/esm/executor-generator.js +212 -18
  428. package/dist/esm/executor-generator.js.map +1 -1
  429. package/dist/esm/index.d.ts +12 -4
  430. package/dist/esm/index.d.ts.map +1 -1
  431. package/dist/esm/index.js +10 -4
  432. package/dist/esm/index.js.map +1 -1
  433. package/dist/esm/invoice/api-routes-code.d.ts +26 -0
  434. package/dist/esm/invoice/api-routes-code.d.ts.map +1 -1
  435. package/dist/esm/invoice/api-routes-code.js +421 -390
  436. package/dist/esm/invoice/api-routes-code.js.map +1 -1
  437. package/dist/esm/invoice/data-access-code.d.ts.map +1 -1
  438. package/dist/esm/invoice/data-access-code.js +420 -107
  439. package/dist/esm/invoice/data-access-code.js.map +1 -1
  440. package/dist/esm/invoice/index.d.ts.map +1 -1
  441. package/dist/esm/invoice/index.js +25 -1
  442. package/dist/esm/invoice/index.js.map +1 -1
  443. package/dist/esm/invoice/invoice-assembly-code.d.ts +12 -0
  444. package/dist/esm/invoice/invoice-assembly-code.d.ts.map +1 -0
  445. package/dist/esm/invoice/invoice-assembly-code.js +513 -0
  446. package/dist/esm/invoice/invoice-assembly-code.js.map +1 -0
  447. package/dist/esm/invoice/invoice-html-code.d.ts.map +1 -1
  448. package/dist/esm/invoice/invoice-html-code.js +111 -9
  449. package/dist/esm/invoice/invoice-html-code.js.map +1 -1
  450. package/dist/esm/invoice/pdf-service-client-code.d.ts.map +1 -1
  451. package/dist/esm/invoice/pdf-service-client-code.js +3 -4
  452. package/dist/esm/invoice/pdf-service-client-code.js.map +1 -1
  453. package/dist/esm/nodes/account/account-login.d.ts.map +1 -1
  454. package/dist/esm/nodes/account/account-login.js +4 -3
  455. package/dist/esm/nodes/account/account-login.js.map +1 -1
  456. package/dist/esm/nodes/account/account-signup.d.ts.map +1 -1
  457. package/dist/esm/nodes/account/account-signup.js +7 -4
  458. package/dist/esm/nodes/account/account-signup.js.map +1 -1
  459. package/dist/esm/nodes/ai/ai-select-database-data.d.ts.map +1 -1
  460. package/dist/esm/nodes/ai/ai-select-database-data.js +6 -1
  461. package/dist/esm/nodes/ai/ai-select-database-data.js.map +1 -1
  462. package/dist/esm/nodes/browser/browser-get-push-subscription.d.ts +9 -0
  463. package/dist/esm/nodes/browser/browser-get-push-subscription.d.ts.map +1 -0
  464. package/dist/esm/nodes/browser/browser-get-push-subscription.js +22 -0
  465. package/dist/esm/nodes/browser/browser-get-push-subscription.js.map +1 -0
  466. package/dist/esm/nodes/browser/browser-show-notification.d.ts +10 -0
  467. package/dist/esm/nodes/browser/browser-show-notification.d.ts.map +1 -1
  468. package/dist/esm/nodes/browser/browser-show-notification.js +65 -40
  469. package/dist/esm/nodes/browser/browser-show-notification.js.map +1 -1
  470. package/dist/esm/nodes/browser/browser-subscribe-to-push.d.ts +11 -0
  471. package/dist/esm/nodes/browser/browser-subscribe-to-push.d.ts.map +1 -1
  472. package/dist/esm/nodes/browser/browser-subscribe-to-push.js +21 -31
  473. package/dist/esm/nodes/browser/browser-subscribe-to-push.js.map +1 -1
  474. package/dist/esm/nodes/browser/browser-unsubscribe-from-push.d.ts +8 -0
  475. package/dist/esm/nodes/browser/browser-unsubscribe-from-push.d.ts.map +1 -0
  476. package/dist/esm/nodes/browser/browser-unsubscribe-from-push.js +21 -0
  477. package/dist/esm/nodes/browser/browser-unsubscribe-from-push.js.map +1 -0
  478. package/dist/esm/nodes/browser/push-api-access.d.ts +12 -0
  479. package/dist/esm/nodes/browser/push-api-access.d.ts.map +1 -0
  480. package/dist/esm/nodes/browser/push-api-access.js +13 -0
  481. package/dist/esm/nodes/browser/push-api-access.js.map +1 -0
  482. package/dist/esm/nodes/cart/cart-add-item.d.ts.map +1 -1
  483. package/dist/esm/nodes/cart/cart-add-item.js +174 -10
  484. package/dist/esm/nodes/cart/cart-add-item.js.map +1 -1
  485. package/dist/esm/nodes/cart/cart-clear.d.ts.map +1 -1
  486. package/dist/esm/nodes/cart/cart-clear.js +11 -0
  487. package/dist/esm/nodes/cart/cart-clear.js.map +1 -1
  488. package/dist/esm/nodes/cart/cart-get-total.d.ts.map +1 -1
  489. package/dist/esm/nodes/cart/cart-get-total.js +261 -4
  490. package/dist/esm/nodes/cart/cart-get-total.js.map +1 -1
  491. package/dist/esm/nodes/cart/cart-price-order.d.ts +3 -0
  492. package/dist/esm/nodes/cart/cart-price-order.d.ts.map +1 -0
  493. package/dist/esm/nodes/cart/cart-price-order.js +278 -0
  494. package/dist/esm/nodes/cart/cart-price-order.js.map +1 -0
  495. package/dist/esm/nodes/cart/cart-update-item-quantity.d.ts.map +1 -1
  496. package/dist/esm/nodes/cart/cart-update-item-quantity.js +7 -0
  497. package/dist/esm/nodes/cart/cart-update-item-quantity.js.map +1 -1
  498. package/dist/esm/nodes/data/data-count.d.ts.map +1 -1
  499. package/dist/esm/nodes/data/data-count.js +6 -1
  500. package/dist/esm/nodes/data/data-count.js.map +1 -1
  501. package/dist/esm/nodes/data/data-create-item.d.ts.map +1 -1
  502. package/dist/esm/nodes/data/data-create-item.js +11 -1
  503. package/dist/esm/nodes/data/data-create-item.js.map +1 -1
  504. package/dist/esm/nodes/data/data-delete-item.d.ts.map +1 -1
  505. package/dist/esm/nodes/data/data-delete-item.js +29 -0
  506. package/dist/esm/nodes/data/data-delete-item.js.map +1 -1
  507. package/dist/esm/nodes/data/data-raw-query.d.ts.map +1 -1
  508. package/dist/esm/nodes/data/data-raw-query.js +6 -1
  509. package/dist/esm/nodes/data/data-raw-query.js.map +1 -1
  510. package/dist/esm/nodes/data/data-select.d.ts.map +1 -1
  511. package/dist/esm/nodes/data/data-select.js +6 -1
  512. package/dist/esm/nodes/data/data-select.js.map +1 -1
  513. package/dist/esm/nodes/data/data-update-item.d.ts.map +1 -1
  514. package/dist/esm/nodes/data/data-update-item.js +29 -0
  515. package/dist/esm/nodes/data/data-update-item.js.map +1 -1
  516. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.d.ts.map +1 -1
  517. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js +7 -1
  518. package/dist/esm/nodes/ecommerce/ecommerce-generate-invoice.js.map +1 -1
  519. package/dist/esm/nodes/file-storage/file-storage-upload.d.ts.map +1 -1
  520. package/dist/esm/nodes/file-storage/file-storage-upload.js +7 -0
  521. package/dist/esm/nodes/file-storage/file-storage-upload.js.map +1 -1
  522. package/dist/esm/nodes/general/general-custom-js.d.ts.map +1 -1
  523. package/dist/esm/nodes/general/general-custom-js.js +21 -5
  524. package/dist/esm/nodes/general/general-custom-js.js.map +1 -1
  525. package/dist/esm/nodes/index.d.ts.map +1 -1
  526. package/dist/esm/nodes/index.js +9 -4
  527. package/dist/esm/nodes/index.js.map +1 -1
  528. package/dist/esm/nodes/payment/payment-billing-portal.d.ts +3 -0
  529. package/dist/esm/nodes/payment/payment-billing-portal.d.ts.map +1 -0
  530. package/dist/esm/nodes/payment/payment-billing-portal.js +49 -0
  531. package/dist/esm/nodes/payment/payment-billing-portal.js.map +1 -0
  532. package/dist/esm/nodes/payment/payment-charge-user.d.ts.map +1 -1
  533. package/dist/esm/nodes/payment/payment-charge-user.js +227 -360
  534. package/dist/esm/nodes/payment/payment-charge-user.js.map +1 -1
  535. package/dist/esm/nodes/payment/payment-close-checkout.d.ts +3 -0
  536. package/dist/esm/nodes/payment/payment-close-checkout.d.ts.map +1 -0
  537. package/dist/esm/nodes/payment/payment-close-checkout.js +138 -0
  538. package/dist/esm/nodes/payment/payment-close-checkout.js.map +1 -0
  539. package/dist/esm/nodes/payment/payment-ensure-subscription-plan.d.ts +3 -0
  540. package/dist/esm/nodes/payment/payment-ensure-subscription-plan.d.ts.map +1 -0
  541. package/dist/esm/nodes/payment/payment-ensure-subscription-plan.js +64 -0
  542. package/dist/esm/nodes/payment/payment-ensure-subscription-plan.js.map +1 -0
  543. package/dist/esm/nodes/payment/payment-manage-subscription.d.ts +3 -0
  544. package/dist/esm/nodes/payment/payment-manage-subscription.d.ts.map +1 -0
  545. package/dist/esm/nodes/payment/payment-manage-subscription.js +86 -0
  546. package/dist/esm/nodes/payment/payment-manage-subscription.js.map +1 -0
  547. package/dist/esm/nodes/payment/payment-refund.d.ts.map +1 -1
  548. package/dist/esm/nodes/payment/payment-refund.js +50 -404
  549. package/dist/esm/nodes/payment/payment-refund.js.map +1 -1
  550. package/dist/esm/nodes/push/push-send-notification.d.ts +14 -0
  551. package/dist/esm/nodes/push/push-send-notification.d.ts.map +1 -0
  552. package/dist/esm/nodes/push/push-send-notification.js +80 -0
  553. package/dist/esm/nodes/push/push-send-notification.js.map +1 -0
  554. package/dist/esm/payments/drivers/coingate-driver-code.d.ts +16 -0
  555. package/dist/esm/payments/drivers/coingate-driver-code.d.ts.map +1 -0
  556. package/dist/esm/payments/drivers/coingate-driver-code.js +467 -0
  557. package/dist/esm/payments/drivers/coingate-driver-code.js.map +1 -0
  558. package/dist/esm/payments/drivers/mollie-driver-code.d.ts +16 -0
  559. package/dist/esm/payments/drivers/mollie-driver-code.d.ts.map +1 -0
  560. package/dist/esm/payments/drivers/mollie-driver-code.js +619 -0
  561. package/dist/esm/payments/drivers/mollie-driver-code.js.map +1 -0
  562. package/dist/esm/payments/drivers/paddle-driver-code.d.ts +12 -0
  563. package/dist/esm/payments/drivers/paddle-driver-code.d.ts.map +1 -0
  564. package/dist/esm/payments/drivers/paddle-driver-code.js +679 -0
  565. package/dist/esm/payments/drivers/paddle-driver-code.js.map +1 -0
  566. package/dist/esm/payments/drivers/paypal-driver-code.d.ts +12 -0
  567. package/dist/esm/payments/drivers/paypal-driver-code.d.ts.map +1 -0
  568. package/dist/esm/payments/drivers/paypal-driver-code.js +1257 -0
  569. package/dist/esm/payments/drivers/paypal-driver-code.js.map +1 -0
  570. package/dist/esm/payments/drivers/razorpay-driver-code.d.ts +12 -0
  571. package/dist/esm/payments/drivers/razorpay-driver-code.d.ts.map +1 -0
  572. package/dist/esm/payments/drivers/razorpay-driver-code.js +728 -0
  573. package/dist/esm/payments/drivers/razorpay-driver-code.js.map +1 -0
  574. package/dist/esm/payments/drivers/square-driver-code.d.ts +14 -0
  575. package/dist/esm/payments/drivers/square-driver-code.d.ts.map +1 -0
  576. package/dist/esm/payments/drivers/square-driver-code.js +927 -0
  577. package/dist/esm/payments/drivers/square-driver-code.js.map +1 -0
  578. package/dist/esm/payments/drivers/stripe-driver-code.d.ts +12 -0
  579. package/dist/esm/payments/drivers/stripe-driver-code.d.ts.map +1 -0
  580. package/dist/esm/payments/drivers/stripe-driver-code.js +774 -0
  581. package/dist/esm/payments/drivers/stripe-driver-code.js.map +1 -0
  582. package/dist/esm/payments/index.d.ts +66 -0
  583. package/dist/esm/payments/index.d.ts.map +1 -0
  584. package/dist/esm/payments/index.js +164 -0
  585. package/dist/esm/payments/index.js.map +1 -0
  586. package/dist/esm/payments/payment-core-code.d.ts +19 -0
  587. package/dist/esm/payments/payment-core-code.d.ts.map +1 -0
  588. package/dist/esm/payments/payment-core-code.js +418 -0
  589. package/dist/esm/payments/payment-core-code.js.map +1 -0
  590. package/dist/esm/payments/payment-driver-code-map.d.ts +4 -0
  591. package/dist/esm/payments/payment-driver-code-map.d.ts.map +1 -0
  592. package/dist/esm/payments/payment-driver-code-map.js +18 -0
  593. package/dist/esm/payments/payment-driver-code-map.js.map +1 -0
  594. package/dist/esm/payments/payment-drivers-scope.d.ts +35 -0
  595. package/dist/esm/payments/payment-drivers-scope.d.ts.map +1 -0
  596. package/dist/esm/payments/payment-drivers-scope.js +51 -0
  597. package/dist/esm/payments/payment-drivers-scope.js.map +1 -0
  598. package/dist/esm/payments/payment-registry-code.d.ts +8 -0
  599. package/dist/esm/payments/payment-registry-code.d.ts.map +1 -0
  600. package/dist/esm/payments/payment-registry-code.js +37 -0
  601. package/dist/esm/payments/payment-registry-code.js.map +1 -0
  602. package/dist/esm/pg-client-code.d.ts +10 -0
  603. package/dist/esm/pg-client-code.d.ts.map +1 -1
  604. package/dist/esm/pg-client-code.js +25 -0
  605. package/dist/esm/pg-client-code.js.map +1 -1
  606. package/dist/esm/runtime-storage-generator.d.ts +28 -0
  607. package/dist/esm/runtime-storage-generator.d.ts.map +1 -1
  608. package/dist/esm/runtime-storage-generator.js +239 -4
  609. package/dist/esm/runtime-storage-generator.js.map +1 -1
  610. package/dist/esm/secret-collector.d.ts.map +1 -1
  611. package/dist/esm/secret-collector.js +8 -3
  612. package/dist/esm/secret-collector.js.map +1 -1
  613. package/dist/esm/security-scanner.d.ts +10 -1
  614. package/dist/esm/security-scanner.d.ts.map +1 -1
  615. package/dist/esm/security-scanner.js +18 -0
  616. package/dist/esm/security-scanner.js.map +1 -1
  617. package/dist/esm/segment-context-needs.d.ts +38 -0
  618. package/dist/esm/segment-context-needs.d.ts.map +1 -0
  619. package/dist/esm/segment-context-needs.js +125 -0
  620. package/dist/esm/segment-context-needs.js.map +1 -0
  621. package/dist/esm/segment-splitter.d.ts.map +1 -1
  622. package/dist/esm/segment-splitter.js +6 -1
  623. package/dist/esm/segment-splitter.js.map +1 -1
  624. package/dist/esm/segment-trust.d.ts +50 -0
  625. package/dist/esm/segment-trust.d.ts.map +1 -0
  626. package/dist/esm/segment-trust.js +111 -0
  627. package/dist/esm/segment-trust.js.map +1 -0
  628. package/dist/esm/sent-email-log/sent-email-log-code.d.ts +19 -0
  629. package/dist/esm/sent-email-log/sent-email-log-code.d.ts.map +1 -1
  630. package/dist/esm/sent-email-log/sent-email-log-code.js +2 -25
  631. package/dist/esm/sent-email-log/sent-email-log-code.js.map +1 -1
  632. package/dist/esm/server-runtime-code.d.ts +34 -0
  633. package/dist/esm/server-runtime-code.d.ts.map +1 -0
  634. package/dist/esm/server-runtime-code.js +299 -0
  635. package/dist/esm/server-runtime-code.js.map +1 -0
  636. package/dist/esm/session-cookie-resolver.d.ts +3 -78
  637. package/dist/esm/session-cookie-resolver.d.ts.map +1 -1
  638. package/dist/esm/session-cookie-resolver.js +7 -274
  639. package/dist/esm/session-cookie-resolver.js.map +1 -1
  640. package/dist/esm/subscriber-access-route-generator.d.ts +71 -0
  641. package/dist/esm/subscriber-access-route-generator.d.ts.map +1 -0
  642. package/dist/esm/subscriber-access-route-generator.js +292 -0
  643. package/dist/esm/subscriber-access-route-generator.js.map +1 -0
  644. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  645. package/dist/esm/types.d.ts +6 -0
  646. package/dist/esm/types.d.ts.map +1 -1
  647. package/dist/esm/webhook-delivery-lease/index.d.ts +8 -0
  648. package/dist/esm/webhook-delivery-lease/index.d.ts.map +1 -0
  649. package/dist/esm/webhook-delivery-lease/index.js +37 -0
  650. package/dist/esm/webhook-delivery-lease/index.js.map +1 -0
  651. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.d.ts +26 -0
  652. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.d.ts.map +1 -0
  653. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.js +147 -0
  654. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-code.js.map +1 -0
  655. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-scope.d.ts +16 -0
  656. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-scope.d.ts.map +1 -0
  657. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-scope.js +16 -0
  658. package/dist/esm/webhook-delivery-lease/webhook-delivery-lease-scope.js.map +1 -0
  659. package/dist/esm/webhook-generator.d.ts +1 -1
  660. package/dist/esm/webhook-generator.d.ts.map +1 -1
  661. package/dist/esm/webhook-generator.js +342 -254
  662. package/dist/esm/webhook-generator.js.map +1 -1
  663. package/dist/esm/webhook-signature-verification.d.ts +17 -1
  664. package/dist/esm/webhook-signature-verification.d.ts.map +1 -1
  665. package/dist/esm/webhook-signature-verification.js +179 -25
  666. package/dist/esm/webhook-signature-verification.js.map +1 -1
  667. package/dist/esm/workflow-auth-generator.d.ts +9 -6
  668. package/dist/esm/workflow-auth-generator.d.ts.map +1 -1
  669. package/dist/esm/workflow-auth-generator.js +132 -28
  670. package/dist/esm/workflow-auth-generator.js.map +1 -1
  671. package/dist/esm/workflow-component-plugin.d.ts.map +1 -1
  672. package/dist/esm/workflow-component-plugin.js +65 -28
  673. package/dist/esm/workflow-component-plugin.js.map +1 -1
  674. package/dist/esm/workflow-project-plugin.d.ts +13 -0
  675. package/dist/esm/workflow-project-plugin.d.ts.map +1 -1
  676. package/dist/esm/workflow-project-plugin.js +212 -63
  677. package/dist/esm/workflow-project-plugin.js.map +1 -1
  678. package/package.json +4 -4
  679. package/src/admin-form-hydration.ts +28 -0
  680. package/src/api-route-generator.ts +251 -64
  681. package/src/auth-generator.ts +273 -53
  682. package/src/auth-return/signed-in-destination-code.ts +32 -0
  683. package/src/cart-pricing-preamble.ts +22 -0
  684. package/src/cron-request-verification.ts +79 -0
  685. package/src/custom-node-modules.ts +102 -0
  686. package/src/data-api-route-generator.ts +370 -28
  687. package/src/ecommerce/cart-availability.ts +22 -13
  688. package/src/ecommerce/stock-decrement.ts +13 -1
  689. package/src/executor-generator.ts +212 -19
  690. package/src/index.ts +28 -7
  691. package/src/invoice/api-routes-code.ts +424 -391
  692. package/src/invoice/data-access-code.ts +431 -110
  693. package/src/invoice/index.ts +31 -1
  694. package/src/invoice/invoice-assembly-code.ts +514 -0
  695. package/src/invoice/invoice-html-code.ts +111 -9
  696. package/src/invoice/pdf-service-client-code.ts +3 -4
  697. package/src/nodes/account/account-login.ts +4 -3
  698. package/src/nodes/account/account-signup.ts +7 -4
  699. package/src/nodes/ai/ai-select-database-data.ts +10 -1
  700. package/src/nodes/browser/browser-get-push-subscription.ts +23 -0
  701. package/src/nodes/browser/browser-show-notification.ts +61 -38
  702. package/src/nodes/browser/browser-subscribe-to-push.ts +26 -36
  703. package/src/nodes/browser/browser-unsubscribe-from-push.ts +22 -0
  704. package/src/nodes/browser/push-api-access.ts +20 -0
  705. package/src/nodes/cart/cart-add-item.ts +200 -9
  706. package/src/nodes/cart/cart-clear.ts +11 -0
  707. package/src/nodes/cart/cart-get-total.ts +279 -7
  708. package/src/nodes/cart/cart-price-order.ts +351 -0
  709. package/src/nodes/cart/cart-update-item-quantity.ts +7 -0
  710. package/src/nodes/data/data-count.ts +9 -1
  711. package/src/nodes/data/data-create-item.ts +15 -1
  712. package/src/nodes/data/data-delete-item.ts +32 -0
  713. package/src/nodes/data/data-raw-query.ts +9 -1
  714. package/src/nodes/data/data-select.ts +9 -1
  715. package/src/nodes/data/data-update-item.ts +32 -0
  716. package/src/nodes/ecommerce/ecommerce-generate-invoice.ts +11 -1
  717. package/src/nodes/file-storage/file-storage-upload.ts +8 -0
  718. package/src/nodes/general/general-custom-js.ts +21 -5
  719. package/src/nodes/index.ts +16 -6
  720. package/src/nodes/payment/payment-billing-portal.ts +51 -0
  721. package/src/nodes/payment/payment-charge-user.ts +236 -442
  722. package/src/nodes/payment/payment-close-checkout.ts +137 -0
  723. package/src/nodes/payment/payment-ensure-subscription-plan.ts +66 -0
  724. package/src/nodes/payment/payment-manage-subscription.ts +89 -0
  725. package/src/nodes/payment/payment-refund.ts +52 -467
  726. package/src/nodes/payment-drivers-global.d.ts +13 -0
  727. package/src/nodes/push/push-send-notification.ts +83 -0
  728. package/src/nodes/workflow-utils-global.d.ts +5 -0
  729. package/src/payments/drivers/coingate-driver-code.ts +466 -0
  730. package/src/payments/drivers/mollie-driver-code.ts +618 -0
  731. package/src/payments/drivers/paddle-driver-code.ts +678 -0
  732. package/src/payments/drivers/paypal-driver-code.ts +1256 -0
  733. package/src/payments/drivers/razorpay-driver-code.ts +727 -0
  734. package/src/payments/drivers/square-driver-code.ts +926 -0
  735. package/src/payments/drivers/stripe-driver-code.ts +773 -0
  736. package/src/payments/index.ts +204 -0
  737. package/src/payments/payment-core-code.ts +421 -0
  738. package/src/payments/payment-driver-code-map.ts +19 -0
  739. package/src/payments/payment-drivers-scope.ts +66 -0
  740. package/src/payments/payment-registry-code.ts +38 -0
  741. package/src/pg-client-code.ts +30 -0
  742. package/src/runtime-storage-generator.ts +241 -4
  743. package/src/secret-collector.ts +8 -3
  744. package/src/security-scanner.ts +22 -0
  745. package/src/segment-context-needs.ts +148 -0
  746. package/src/segment-splitter.ts +6 -1
  747. package/src/segment-trust.ts +170 -0
  748. package/src/sent-email-log/sent-email-log-code.ts +2 -32
  749. package/src/server-runtime-code.ts +298 -0
  750. package/src/session-cookie-resolver.ts +9 -277
  751. package/src/subscriber-access-route-generator.ts +351 -0
  752. package/src/types.ts +6 -0
  753. package/src/webhook-delivery-lease/index.ts +44 -0
  754. package/src/webhook-delivery-lease/webhook-delivery-lease-code.ts +151 -0
  755. package/src/webhook-delivery-lease/webhook-delivery-lease-scope.ts +18 -0
  756. package/src/webhook-generator.ts +359 -260
  757. package/src/webhook-signature-verification.ts +180 -25
  758. package/src/workflow-auth-generator.ts +137 -28
  759. package/src/workflow-component-plugin.ts +77 -20
  760. package/src/workflow-project-plugin.ts +247 -44
  761. package/dist/cjs/nodes/payment/payment-cancel-plan.d.ts +0 -3
  762. package/dist/cjs/nodes/payment/payment-cancel-plan.d.ts.map +0 -1
  763. package/dist/cjs/nodes/payment/payment-cancel-plan.js +0 -33
  764. package/dist/cjs/nodes/payment/payment-cancel-plan.js.map +0 -1
  765. package/dist/cjs/nodes/payment/payment-create-subscription.d.ts +0 -3
  766. package/dist/cjs/nodes/payment/payment-create-subscription.d.ts.map +0 -1
  767. package/dist/cjs/nodes/payment/payment-create-subscription.js +0 -41
  768. package/dist/cjs/nodes/payment/payment-create-subscription.js.map +0 -1
  769. package/dist/cjs/nodes/payment/payment-subscribe-to-plan.d.ts +0 -3
  770. package/dist/cjs/nodes/payment/payment-subscribe-to-plan.d.ts.map +0 -1
  771. package/dist/cjs/nodes/payment/payment-subscribe-to-plan.js +0 -45
  772. package/dist/cjs/nodes/payment/payment-subscribe-to-plan.js.map +0 -1
  773. package/dist/esm/nodes/payment/payment-cancel-plan.d.ts +0 -3
  774. package/dist/esm/nodes/payment/payment-cancel-plan.d.ts.map +0 -1
  775. package/dist/esm/nodes/payment/payment-cancel-plan.js +0 -30
  776. package/dist/esm/nodes/payment/payment-cancel-plan.js.map +0 -1
  777. package/dist/esm/nodes/payment/payment-create-subscription.d.ts +0 -3
  778. package/dist/esm/nodes/payment/payment-create-subscription.d.ts.map +0 -1
  779. package/dist/esm/nodes/payment/payment-create-subscription.js +0 -38
  780. package/dist/esm/nodes/payment/payment-create-subscription.js.map +0 -1
  781. package/dist/esm/nodes/payment/payment-subscribe-to-plan.d.ts +0 -3
  782. package/dist/esm/nodes/payment/payment-subscribe-to-plan.d.ts.map +0 -1
  783. package/dist/esm/nodes/payment/payment-subscribe-to-plan.js +0 -42
  784. package/dist/esm/nodes/payment/payment-subscribe-to-plan.js.map +0 -1
  785. package/src/nodes/payment/payment-cancel-plan.ts +0 -33
  786. package/src/nodes/payment/payment-create-subscription.ts +0 -42
  787. package/src/nodes/payment/payment-subscribe-to-plan.ts +0 -46
@@ -0,0 +1,1360 @@
1
+ import { loadHandler, HandlerFn } from './_helpers/load-handler'
2
+ import { loadPaymentDrivers } from './_helpers/load-payment-drivers'
3
+ import { createFakeStripe } from './_helpers/fake-stripe'
4
+ import { paymentChargeUser } from '../src/nodes/payment/payment-charge-user'
5
+ import { paymentManageSubscription } from '../src/nodes/payment/payment-manage-subscription'
6
+ import { paymentEnsureSubscriptionPlan } from '../src/nodes/payment/payment-ensure-subscription-plan'
7
+ import { paymentBillingPortal } from '../src/nodes/payment/payment-billing-portal'
8
+ import { resolveHandlerEntryName } from '../src/nodes/types'
9
+ import { collectSecrets } from '../src/secret-collector'
10
+
11
+ /**
12
+ * The three provider handlers behind a subscription — the recurring checkout,
13
+ * the plan a provider needs before one, and the merchant's cancel / pause /
14
+ * resume — EXECUTED against a fake provider: every PayPal call goes through
15
+ * `fetch`, so the requests the store sends and the answers it accepts are
16
+ * asserted here; Stripe's SDK is not loadable in the test process, so its
17
+ * paths are held to their validation and to the emitted source.
18
+ */
19
+
20
+ interface FetchCall {
21
+ url: string
22
+ init: { method?: string; headers?: Record<string, string>; body?: string }
23
+ }
24
+
25
+ type Responder = (
26
+ url: string,
27
+ init: FetchCall['init']
28
+ ) => { ok: boolean; status?: number; body: unknown }
29
+
30
+ const PAYPAL_ENV = {
31
+ PAYPAL_CLIENT_ID: 'Aclient',
32
+ PAYPAL_CLIENT_SECRET: 'Esecret',
33
+ }
34
+
35
+ const withEnv = async <T>(
36
+ env: Record<string, string | undefined>,
37
+ run: () => Promise<T>
38
+ ): Promise<T> => {
39
+ const saved: Record<string, string | undefined> = {}
40
+ for (const key of Object.keys(env)) {
41
+ saved[key] = process.env[key]
42
+ if (env[key] === undefined) {
43
+ delete process.env[key]
44
+ } else {
45
+ process.env[key] = env[key]
46
+ }
47
+ }
48
+ try {
49
+ return await run()
50
+ } finally {
51
+ for (const key of Object.keys(env)) {
52
+ if (saved[key] === undefined) {
53
+ delete process.env[key]
54
+ } else {
55
+ process.env[key] = saved[key]
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ const withFetch = async <T>(
62
+ respond: Responder,
63
+ run: (calls: FetchCall[]) => Promise<T>
64
+ ): Promise<T> => {
65
+ const calls: FetchCall[] = []
66
+ const previous = (globalThis as { fetch?: unknown }).fetch
67
+ ;(globalThis as { fetch?: unknown }).fetch = async (
68
+ url: string,
69
+ init: FetchCall['init'] = {}
70
+ ) => {
71
+ calls.push({ url, init })
72
+ const answer = respond(url, init)
73
+ return {
74
+ ok: answer.ok,
75
+ status: answer.status ?? (answer.ok ? 200 : 400),
76
+ json: async () => answer.body,
77
+ }
78
+ }
79
+ try {
80
+ return await run(calls)
81
+ } finally {
82
+ ;(globalThis as { fetch?: unknown }).fetch = previous
83
+ ;(globalThis as { __paypalBaseUrlCache?: string }).__paypalBaseUrlCache = undefined
84
+ }
85
+ }
86
+
87
+ const paypalAuth = (url: string) => url.endsWith('/v1/oauth2/token')
88
+
89
+ // A refused charge is not a thrown error: the handler answers an early 400
90
+ // whose body carries the provider's message, which the checkout page renders.
91
+ const refusal = (result: unknown): { status: number; error: string; provider: string } => {
92
+ const early = (
93
+ result as { __earlyResponse?: { status: number; body: { error: string; provider: string } } }
94
+ ).__earlyResponse
95
+ if (!early) {
96
+ throw new Error('expected an early response, got ' + JSON.stringify(result))
97
+ }
98
+ return { status: early.status, error: early.body.error, provider: early.body.provider }
99
+ }
100
+
101
+ // The generated executor publishes `__workflowUtils` for every handler; the
102
+ // charge handler localizes its redirect URLs through it.
103
+ beforeAll(() => {
104
+ ;(globalThis as { __workflowUtils?: unknown }).__workflowUtils = {
105
+ localizeHref: (href: string) => href,
106
+ }
107
+ })
108
+ afterAll(() => {
109
+ delete (globalThis as { __workflowUtils?: unknown }).__workflowUtils
110
+ })
111
+
112
+ describe('payment-charge-user in subscription mode', () => {
113
+ const handler: HandlerFn = loadHandler('payment-charge-user')
114
+ const source = paymentChargeUser.generateHandler()
115
+
116
+ it('refuses a provider the store does not dispatch to, instead of charging Stripe by default', async () => {
117
+ const result = refusal(
118
+ await handler({ providerId: 'adyen', mode: 'subscription', amount: 10, currency: 'usd' }, {})
119
+ )
120
+ expect(result).toEqual({
121
+ status: 400,
122
+ error: 'Payment provider "adyen" is not supported by this store.',
123
+ provider: 'adyen',
124
+ })
125
+ })
126
+
127
+ it('opens Stripe Checkout in subscription mode with an inline recurring price and the trial', async () => {
128
+ const { FakeStripe, calls } = createFakeStripe({
129
+ 'checkout.sessions.create': () => ({
130
+ id: 'cs_sub',
131
+ url: 'https://checkout.stripe.com/c/cs_sub',
132
+ }),
133
+ })
134
+ const stripeHandler = loadHandler('payment-charge-user', {
135
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
136
+ })
137
+ const metadata = { orderId: 'order-1', subscriptionId: 'sub-row-1' }
138
+ await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, async () => {
139
+ const result = await stripeHandler(
140
+ {
141
+ providerId: 'stripe',
142
+ mode: 'subscription',
143
+ amount: 12.5,
144
+ currency: 'usd',
145
+ recurringInterval: 'month',
146
+ recurringIntervalCount: 2,
147
+ trialDays: 7,
148
+ description: 'Coffee club',
149
+ metadata,
150
+ successUrl: 'https://store.test/ok',
151
+ cancelUrl: 'https://store.test/checkout',
152
+ },
153
+ {}
154
+ )
155
+ expect(result).toEqual({
156
+ checkoutUrl: 'https://checkout.stripe.com/c/cs_sub',
157
+ sessionId: 'cs_sub',
158
+ attemptRef: 'cs_sub',
159
+ attemptOutcome: 'created',
160
+ redirectUrl: 'https://checkout.stripe.com/c/cs_sub',
161
+ providerSubscriptionId: '',
162
+ __terminal: true,
163
+ __redirectUrl: 'https://checkout.stripe.com/c/cs_sub',
164
+ })
165
+ })
166
+ expect(calls).toEqual([
167
+ {
168
+ method: 'checkout.sessions.create',
169
+ params: {
170
+ mode: 'subscription',
171
+ success_url: 'https://store.test/ok',
172
+ cancel_url: 'https://store.test/checkout',
173
+ line_items: [
174
+ {
175
+ price_data: {
176
+ currency: 'usd',
177
+ product_data: { name: 'Coffee club' },
178
+ unit_amount: 1250,
179
+ recurring: { interval: 'month', interval_count: 2 },
180
+ },
181
+ quantity: 1,
182
+ },
183
+ ],
184
+ subscription_data: { trial_period_days: 7, metadata },
185
+ metadata,
186
+ },
187
+ },
188
+ ])
189
+ expect(resolveHandlerEntryName(source, 'payment-charge-user')).toBe('payment_charge_user')
190
+ })
191
+
192
+ it('validates the Stripe subscription before touching the provider', async () => {
193
+ await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, async () => {
194
+ const interval = refusal(
195
+ await handler(
196
+ {
197
+ providerId: 'stripe',
198
+ mode: 'subscription',
199
+ amount: 10,
200
+ currency: 'usd',
201
+ recurringInterval: 'fortnight',
202
+ },
203
+ {}
204
+ )
205
+ )
206
+ expect(interval.error).toBe('Unknown billing interval "fortnight"')
207
+ const amount = refusal(
208
+ await handler(
209
+ {
210
+ providerId: 'stripe',
211
+ mode: 'subscription',
212
+ amount: 0,
213
+ currency: 'usd',
214
+ recurringInterval: 'month',
215
+ },
216
+ {}
217
+ )
218
+ )
219
+ expect(amount.error).toBe('A subscription needs a positive amount to bill')
220
+ })
221
+ await withEnv(
222
+ {
223
+ STRIPE_SECRET_KEY: undefined,
224
+ CONFIGURATION_STRIPE_SECRET_KEY: undefined,
225
+ STRIPE_TEST_KEY: undefined,
226
+ },
227
+ async () => {
228
+ const missing = refusal(
229
+ await handler(
230
+ { providerId: 'stripe', mode: 'subscription', amount: 10, currency: 'usd' },
231
+ {}
232
+ )
233
+ )
234
+ expect(missing.error).toBe('STRIPE_SECRET_KEY is not configured')
235
+ }
236
+ )
237
+ })
238
+
239
+ it("takes a gift card's tender off the FIRST Stripe invoice as a one-shot coupon, and never the whole of it", async () => {
240
+ const { FakeStripe, calls } = createFakeStripe({
241
+ 'coupons.create': () => ({ id: 'co_gift' }),
242
+ 'checkout.sessions.create': () => ({
243
+ id: 'cs_sub',
244
+ url: 'https://checkout.stripe.com/c/cs_sub',
245
+ }),
246
+ })
247
+ const stripeHandler = loadHandler('payment-charge-user', {
248
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
249
+ })
250
+ await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () =>
251
+ stripeHandler(
252
+ {
253
+ providerId: 'stripe',
254
+ mode: 'subscription',
255
+ amount: 30,
256
+ amountDue: 20,
257
+ currency: 'usd',
258
+ recurringInterval: 'month',
259
+ description: 'Box',
260
+ },
261
+ {}
262
+ )
263
+ )
264
+ expect(calls.map((call) => call.method)).toEqual(['coupons.create', 'checkout.sessions.create'])
265
+ expect(calls[0].params).toEqual({
266
+ amount_off: 1000,
267
+ currency: 'usd',
268
+ duration: 'once',
269
+ max_redemptions: 1,
270
+ name: 'Gift card',
271
+ metadata: {},
272
+ })
273
+ expect((calls[1].params as { discounts: unknown }).discounts).toEqual([{ coupon: 'co_gift' }])
274
+ await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, async () => {
275
+ const covered = refusal(
276
+ await handler(
277
+ {
278
+ providerId: 'stripe',
279
+ mode: 'subscription',
280
+ amount: 30,
281
+ amountDue: 0,
282
+ currency: 'usd',
283
+ recurringInterval: 'month',
284
+ },
285
+ {}
286
+ )
287
+ )
288
+ expect(covered.error).toBe(
289
+ 'A gift card cannot cover the whole first payment of a subscription'
290
+ )
291
+ })
292
+ })
293
+
294
+ it('creates the PayPal subscription against the plan and sends the buyer to approve it', async () => {
295
+ await withEnv(PAYPAL_ENV, () =>
296
+ withFetch(
297
+ (url) => {
298
+ if (paypalAuth(url)) {
299
+ return { ok: true, body: { access_token: 'tok' } }
300
+ }
301
+ return {
302
+ ok: true,
303
+ body: {
304
+ id: 'I-ABC',
305
+ links: [
306
+ { rel: 'self', href: 'x' },
307
+ { rel: 'approve', href: 'https://paypal.test/approve' },
308
+ ],
309
+ },
310
+ }
311
+ },
312
+ async (calls) => {
313
+ const result = (await handler(
314
+ {
315
+ providerId: 'paypal',
316
+ mode: 'subscription',
317
+ amount: 24,
318
+ currency: 'usd',
319
+ planId: 'P-1',
320
+ customerEmail: 'jane@example.com',
321
+ successUrl: 'https://shop.test/order/1',
322
+ cancelUrl: 'https://shop.test/checkout',
323
+ metadata: JSON.stringify({ orderId: 'order-1', subscriptionId: 'sub-row-1' }),
324
+ },
325
+ {}
326
+ )) as Record<string, unknown>
327
+ expect(result).toMatchObject({
328
+ checkoutUrl: 'https://paypal.test/approve',
329
+ sessionId: 'I-ABC',
330
+ providerSubscriptionId: 'I-ABC',
331
+ __terminal: true,
332
+ __redirectUrl: 'https://paypal.test/approve',
333
+ })
334
+ const create = calls.find((call) => call.url.endsWith('/v1/billing/subscriptions'))!
335
+ expect(create.init.method).toBe('POST')
336
+ expect(create.init.headers?.Authorization).toBe('Bearer tok')
337
+ const payload = JSON.parse(create.init.body!)
338
+ expect(payload.plan_id).toBe('P-1')
339
+ expect(payload.application_context).toMatchObject({
340
+ user_action: 'SUBSCRIBE_NOW',
341
+ return_url: 'https://shop.test/order/1',
342
+ cancel_url: 'https://shop.test/checkout',
343
+ })
344
+ expect(JSON.parse(payload.custom_id)).toEqual({
345
+ orderId: 'order-1',
346
+ subscriptionId: 'sub-row-1',
347
+ })
348
+ // PayPal caps custom_id at 127 characters: two UUIDs fit.
349
+ expect(payload.custom_id.length).toBeLessThanOrEqual(127)
350
+ expect(payload.subscriber).toEqual({ email_address: 'jane@example.com' })
351
+ }
352
+ )
353
+ )
354
+ })
355
+
356
+ it('refuses a PayPal subscription without a plan or when PayPal refuses', async () => {
357
+ await withEnv(PAYPAL_ENV, async () => {
358
+ const noPlan = refusal(
359
+ await handler(
360
+ { providerId: 'paypal', mode: 'subscription', amount: 24, currency: 'usd' },
361
+ {}
362
+ )
363
+ )
364
+ expect(noPlan.error).toBe('No PayPal billing plan was supplied for the subscription')
365
+ await withFetch(
366
+ (url) =>
367
+ paypalAuth(url)
368
+ ? { ok: true, body: { access_token: 'tok' } }
369
+ : { ok: false, body: { message: 'PLAN_NOT_ACTIVE' } },
370
+ async () => {
371
+ const refused = refusal(
372
+ await handler(
373
+ {
374
+ providerId: 'paypal',
375
+ mode: 'subscription',
376
+ amount: 24,
377
+ currency: 'usd',
378
+ planId: 'P-1',
379
+ },
380
+ {}
381
+ )
382
+ )
383
+ expect(refused).toEqual({ status: 400, error: 'PLAN_NOT_ACTIVE', provider: 'paypal' })
384
+ }
385
+ )
386
+ })
387
+ })
388
+ })
389
+
390
+ describe('payment-charge-user one-time checkout email', () => {
391
+ const handler: HandlerFn = loadHandler('payment-charge-user')
392
+ const source = paymentChargeUser.generateHandler()
393
+
394
+ it('prefills the buyer email on the Stripe payment session, as the subscription session does', async () => {
395
+ const { FakeStripe, calls } = createFakeStripe({
396
+ 'checkout.sessions.create': () => ({ id: 'cs_1', url: 'https://checkout.stripe.com/c/cs_1' }),
397
+ })
398
+ const stripeHandler = loadHandler('payment-charge-user', {
399
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
400
+ })
401
+ await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () =>
402
+ stripeHandler(
403
+ { providerId: 'stripe', amount: 9, currency: 'usd', customerEmail: 'jo@store.test' },
404
+ {}
405
+ )
406
+ )
407
+ expect(calls).toHaveLength(1)
408
+ expect(calls[0].params).toMatchObject({ mode: 'payment', customer_email: 'jo@store.test' })
409
+ })
410
+
411
+ it('opens the order with a Pay Now experience, names the buyer, and leaves the email out when the checkout carried none', async () => {
412
+ const ordersCall = (calls: FetchCall[]) =>
413
+ calls.find((call) => call.url.endsWith('/v2/checkout/orders'))!
414
+ const respond: Responder = (url) =>
415
+ paypalAuth(url)
416
+ ? { ok: true, body: { access_token: 'tok' } }
417
+ : {
418
+ ok: true,
419
+ body: {
420
+ id: 'ORDER-1',
421
+ // A payment source answers the page as `payer-action`.
422
+ links: [{ rel: 'payer-action', href: 'https://paypal.test/approve' }],
423
+ },
424
+ }
425
+ await withEnv(PAYPAL_ENV, () =>
426
+ withFetch(respond, async (calls) => {
427
+ const result = (await handler(
428
+ {
429
+ providerId: 'paypal',
430
+ amount: 24,
431
+ currency: 'usd',
432
+ customerEmail: 'jane@example.com',
433
+ successUrl: 'https://shop.test/order/1',
434
+ cancelUrl: 'https://shop.test/checkout',
435
+ metadata: JSON.stringify({ orderId: 'order-1' }),
436
+ },
437
+ {}
438
+ )) as Record<string, unknown>
439
+ expect(result).toMatchObject({
440
+ checkoutUrl: 'https://paypal.test/approve',
441
+ sessionId: 'ORDER-1',
442
+ })
443
+ const payload = JSON.parse(ordersCall(calls).init.body!)
444
+ expect(payload.payment_source.paypal).toEqual({
445
+ email_address: 'jane@example.com',
446
+ experience_context: {
447
+ return_url: 'https://shop.test/order/1',
448
+ cancel_url: 'https://shop.test/checkout',
449
+ user_action: 'PAY_NOW',
450
+ },
451
+ })
452
+ // The deprecated top-level fields are never sent.
453
+ expect(payload).not.toHaveProperty('payer')
454
+ expect(payload).not.toHaveProperty('application_context')
455
+ expect(payload.purchase_units[0].amount).toEqual({ currency_code: 'USD', value: '24.00' })
456
+ })
457
+ )
458
+ await withEnv(PAYPAL_ENV, () =>
459
+ withFetch(respond, async (calls) => {
460
+ await handler({ providerId: 'paypal', amount: 24, currency: 'usd' }, {})
461
+ expect(JSON.parse(ordersCall(calls).init.body!).payment_source.paypal).not.toHaveProperty(
462
+ 'email_address'
463
+ )
464
+ })
465
+ )
466
+ })
467
+ })
468
+
469
+ describe('payment-ensure-subscription-plan', () => {
470
+ const handler: HandlerFn = loadHandler('payment-ensure-subscription-plan')
471
+
472
+ it('is a non-terminal server node whose credentials are collected', () => {
473
+ expect(paymentEnsureSubscriptionPlan.executionEnv).toBe('server')
474
+ expect(paymentEnsureSubscriptionPlan.isTerminal).toBeFalsy()
475
+ const secrets = collectSecrets({
476
+ workflows: {
477
+ wf1: {
478
+ nodes: [
479
+ {
480
+ id: 'n1',
481
+ type: 'payment-ensure-subscription-plan',
482
+ config: { clientId: 'id_1', clientSecret: 'cs_1' },
483
+ },
484
+ ],
485
+ },
486
+ },
487
+ } as never)
488
+ expect(secrets.map((secret) => secret.fieldName).sort()).toEqual(['clientId', 'clientSecret'])
489
+ })
490
+
491
+ it('needs no plan for Stripe and returns a cached PayPal plan without a call', async () => {
492
+ const stripe = await handler({ providerId: 'stripe' }, {})
493
+ expect(stripe).toEqual({ ok: 'true', planId: '', providerProductId: '', created: 'false' })
494
+ await withFetch(
495
+ () => {
496
+ throw new Error('no call expected')
497
+ },
498
+ async (calls) => {
499
+ const cached = await handler(
500
+ { providerId: 'paypal', planId: 'P-cached', providerProductId: 'PROD-1' },
501
+ {}
502
+ )
503
+ expect(cached).toEqual({
504
+ ok: 'true',
505
+ planId: 'P-cached',
506
+ providerProductId: 'PROD-1',
507
+ created: 'false',
508
+ })
509
+ expect(calls).toHaveLength(0)
510
+ }
511
+ )
512
+ const other = (await handler({ providerId: 'adyen' }, {})) as { ok: string; error: string }
513
+ expect(other.ok).toBe('false')
514
+ expect(other.error).toBe('Payment provider "adyen" cannot bill a subscription.')
515
+ })
516
+
517
+ it('checks a cached PayPal plan against the environment of the current credentials, and creates it there when unknown', async () => {
518
+ const known = await withEnv(PAYPAL_ENV, () =>
519
+ withFetch(
520
+ (url) =>
521
+ paypalAuth(url)
522
+ ? { ok: true, body: { access_token: 'tok' } }
523
+ : { ok: true, body: { id: 'P-cached' } },
524
+ async (calls) => ({
525
+ result: await handler(
526
+ { providerId: 'paypal', planId: 'P-cached', providerProductId: 'PROD-1' },
527
+ {}
528
+ ),
529
+ calls,
530
+ })
531
+ )
532
+ )
533
+ expect(known.result).toEqual({
534
+ ok: 'true',
535
+ planId: 'P-cached',
536
+ providerProductId: 'PROD-1',
537
+ created: 'false',
538
+ })
539
+ expect(
540
+ known.calls
541
+ .filter((call) => !paypalAuth(call.url))
542
+ .map((call) => [call.init.method, call.url.replace(/^https:\/\/[^/]+/, '')])
543
+ ).toEqual([['GET', '/v1/billing/plans/P-cached']])
544
+ // A plan the sandbox created is unknown to live credentials (and the other way round).
545
+ const unknown = await withEnv(PAYPAL_ENV, () =>
546
+ withFetch(
547
+ (url, init) => {
548
+ if (paypalAuth(url)) {
549
+ return { ok: true, body: { access_token: 'tok' } }
550
+ }
551
+ if (init.method === 'GET') {
552
+ return { ok: false, status: 404, body: { name: 'RESOURCE_NOT_FOUND' } }
553
+ }
554
+ return {
555
+ ok: true,
556
+ body: { id: url.endsWith('/v1/catalogs/products') ? 'PROD-2' : 'P-2' },
557
+ }
558
+ },
559
+ async () =>
560
+ handler(
561
+ {
562
+ providerId: 'paypal',
563
+ planId: 'P-other-environment',
564
+ providerProductId: 'PROD-1',
565
+ productName: 'Coffee Club',
566
+ amount: 24.5,
567
+ currency: 'usd',
568
+ interval: 'month',
569
+ },
570
+ {}
571
+ )
572
+ )
573
+ )
574
+ expect(unknown).toEqual({
575
+ ok: 'true',
576
+ planId: 'P-2',
577
+ providerProductId: 'PROD-2',
578
+ created: 'true',
579
+ })
580
+ // A check PayPal cannot answer right now keeps the cached plan.
581
+ const outage = await withEnv(PAYPAL_ENV, () =>
582
+ withFetch(
583
+ (url) =>
584
+ paypalAuth(url)
585
+ ? { ok: true, body: { access_token: 'tok' } }
586
+ : { ok: false, status: 503, body: {} },
587
+ async () => handler({ providerId: 'paypal', planId: 'P-cached' }, {})
588
+ )
589
+ )
590
+ expect(outage).toMatchObject({ ok: 'true', planId: 'P-cached', created: 'false' })
591
+ })
592
+
593
+ it('creates the PayPal product and an active plan: a trial cycle, then the regular cycle until cancelled', async () => {
594
+ await withEnv(PAYPAL_ENV, () =>
595
+ withFetch(
596
+ (url) => {
597
+ if (paypalAuth(url)) {
598
+ return { ok: true, body: { access_token: 'tok' } }
599
+ }
600
+ if (url.endsWith('/v1/catalogs/products')) {
601
+ return { ok: true, body: { id: 'PROD-9' } }
602
+ }
603
+ return { ok: true, body: { id: 'P-9' } }
604
+ },
605
+ async (calls) => {
606
+ const result = await handler(
607
+ {
608
+ providerId: 'paypal',
609
+ productId: 'product-1',
610
+ productName: 'Coffee Club',
611
+ amount: 24.5,
612
+ currency: 'usd',
613
+ interval: 'month',
614
+ intervalCount: 3,
615
+ trialDays: 14,
616
+ },
617
+ {}
618
+ )
619
+ expect(result).toEqual({
620
+ ok: 'true',
621
+ planId: 'P-9',
622
+ providerProductId: 'PROD-9',
623
+ created: 'true',
624
+ })
625
+ const product = JSON.parse(
626
+ calls.find((call) => call.url.endsWith('/v1/catalogs/products'))!.init.body!
627
+ )
628
+ expect(product).toEqual({
629
+ name: 'Coffee Club',
630
+ description: 'Store product product-1',
631
+ type: 'SERVICE',
632
+ })
633
+ const plan = JSON.parse(
634
+ calls.find((call) => call.url.endsWith('/v1/billing/plans'))!.init.body!
635
+ )
636
+ expect(plan.product_id).toBe('PROD-9')
637
+ expect(plan.status).toBe('ACTIVE')
638
+ expect(plan.billing_cycles).toEqual([
639
+ {
640
+ frequency: { interval_unit: 'DAY', interval_count: 14 },
641
+ tenure_type: 'TRIAL',
642
+ sequence: 1,
643
+ total_cycles: 1,
644
+ pricing_scheme: { fixed_price: { value: '0', currency_code: 'USD' } },
645
+ },
646
+ {
647
+ frequency: { interval_unit: 'MONTH', interval_count: 3 },
648
+ tenure_type: 'REGULAR',
649
+ sequence: 2,
650
+ total_cycles: 0,
651
+ pricing_scheme: { fixed_price: { value: '24.50', currency_code: 'USD' } },
652
+ },
653
+ ])
654
+ expect(plan.payment_preferences).toEqual({
655
+ auto_bill_outstanding: true,
656
+ setup_fee_failure_action: 'CONTINUE',
657
+ payment_failure_threshold: 3,
658
+ })
659
+ }
660
+ )
661
+ )
662
+ })
663
+
664
+ it('opens the plan with a paid first cycle when a gift card paid part of it, and refuses that beside a free trial', async () => {
665
+ await withEnv(PAYPAL_ENV, () =>
666
+ withFetch(
667
+ (url) => {
668
+ if (paypalAuth(url)) {
669
+ return { ok: true, body: { access_token: 'tok' } }
670
+ }
671
+ if (url.endsWith('/v1/catalogs/products')) {
672
+ return { ok: true, body: { id: 'PROD-9' } }
673
+ }
674
+ return { ok: true, body: { id: 'P-10' } }
675
+ },
676
+ async (calls) => {
677
+ const config = {
678
+ providerId: 'paypal',
679
+ productId: 'product-1',
680
+ productName: 'Coffee Club',
681
+ amount: 24.5,
682
+ currency: 'usd',
683
+ interval: 'month',
684
+ intervalCount: 1,
685
+ trialDays: 0,
686
+ }
687
+ const result = await handler({ ...config, firstCycleAmount: 4.5 }, {})
688
+ expect(result).toEqual({
689
+ ok: 'true',
690
+ planId: 'P-10',
691
+ providerProductId: 'PROD-9',
692
+ created: 'true',
693
+ })
694
+ const plan = JSON.parse(
695
+ calls.find((call) => call.url.endsWith('/v1/billing/plans'))!.init.body!
696
+ )
697
+ expect(plan.billing_cycles).toEqual([
698
+ {
699
+ frequency: { interval_unit: 'MONTH', interval_count: 1 },
700
+ tenure_type: 'TRIAL',
701
+ sequence: 1,
702
+ total_cycles: 1,
703
+ pricing_scheme: { fixed_price: { value: '4.50', currency_code: 'USD' } },
704
+ },
705
+ {
706
+ frequency: { interval_unit: 'MONTH', interval_count: 1 },
707
+ tenure_type: 'REGULAR',
708
+ sequence: 2,
709
+ total_cycles: 0,
710
+ pricing_scheme: { fixed_price: { value: '24.50', currency_code: 'USD' } },
711
+ },
712
+ ])
713
+ // The whole first cycle: the plan opens on the regular cycle alone.
714
+ calls.length = 0
715
+ await handler({ ...config, firstCycleAmount: 24.5 }, {})
716
+ const whole = JSON.parse(
717
+ calls.find((call) => call.url.endsWith('/v1/billing/plans'))!.init.body!
718
+ )
719
+ expect(
720
+ whole.billing_cycles.map((cycle: { tenure_type: string }) => cycle.tenure_type)
721
+ ).toEqual(['REGULAR'])
722
+
723
+ const refused = await handler({ ...config, trialDays: 14, firstCycleAmount: 4.5 }, {})
724
+ expect(refused).toMatchObject({
725
+ ok: 'false',
726
+ error: 'A subscription with a free trial cannot open with a reduced first payment.',
727
+ })
728
+ }
729
+ )
730
+ )
731
+ })
732
+
733
+ it('formats a zero-decimal currency whole and reports a refusal as a failure, never a throw', async () => {
734
+ await withEnv(PAYPAL_ENV, () =>
735
+ withFetch(
736
+ (url) => {
737
+ if (paypalAuth(url)) {
738
+ return { ok: true, body: { access_token: 'tok' } }
739
+ }
740
+ if (url.endsWith('/v1/catalogs/products')) {
741
+ return { ok: true, body: { id: 'PROD-9' } }
742
+ }
743
+ return { ok: false, body: { details: [{ description: 'Currency not supported' }] } }
744
+ },
745
+ async (calls) => {
746
+ const result = (await handler(
747
+ {
748
+ providerId: 'paypal',
749
+ productName: 'Box',
750
+ amount: 1200.4,
751
+ currency: 'jpy',
752
+ interval: 'week',
753
+ },
754
+ {}
755
+ )) as { ok: string; error: string }
756
+ expect(result.ok).toBe('false')
757
+ expect(result.error).toBe('PayPal refused to create the plan: Currency not supported')
758
+ const plan = JSON.parse(
759
+ calls.find((call) => call.url.endsWith('/v1/billing/plans'))!.init.body!
760
+ )
761
+ expect(plan.billing_cycles[0].pricing_scheme.fixed_price).toEqual({
762
+ value: '1200',
763
+ currency_code: 'JPY',
764
+ })
765
+ }
766
+ )
767
+ )
768
+ const bad = (await withEnv(PAYPAL_ENV, () =>
769
+ handler({ providerId: 'paypal', amount: -1, currency: 'usd' }, {})
770
+ )) as {
771
+ error: string
772
+ }
773
+ expect(bad.error).toBe('A subscription needs a positive amount to bill.')
774
+ })
775
+
776
+ // PayPal's frequency limits: DAY 365, WEEK 52, MONTH 12, YEAR 1.
777
+ it('refuses a billing cycle or a trial longer than PayPal allows, before calling it', async () => {
778
+ const plan = (config: Record<string, unknown>) =>
779
+ withEnv(PAYPAL_ENV, () =>
780
+ withFetch(
781
+ (url) => {
782
+ if (paypalAuth(url)) {
783
+ return { ok: true, body: { access_token: 'tok' } }
784
+ }
785
+ return {
786
+ ok: true,
787
+ body: { id: url.endsWith('/v1/catalogs/products') ? 'PROD-1' : 'P-1' },
788
+ }
789
+ },
790
+ async (calls) => ({
791
+ result: (await handler(
792
+ { providerId: 'paypal', productName: 'Box', amount: 10, currency: 'usd', ...config },
793
+ {}
794
+ )) as { ok: string; error?: string },
795
+ calls,
796
+ })
797
+ )
798
+ )
799
+ const refusals: Array<[Record<string, unknown>, string]> = [
800
+ [
801
+ { interval: 'month', intervalCount: 13 },
802
+ 'PayPal cannot bill every 13 months: its longest billing cycle is 12 months.',
803
+ ],
804
+ [
805
+ { interval: 'week', intervalCount: 53 },
806
+ 'PayPal cannot bill every 53 weeks: its longest billing cycle is 52 weeks.',
807
+ ],
808
+ [
809
+ { interval: 'day', intervalCount: 366 },
810
+ 'PayPal cannot bill every 366 days: its longest billing cycle is 365 days.',
811
+ ],
812
+ [
813
+ { interval: 'year', intervalCount: 2 },
814
+ 'PayPal cannot bill every 2 years: its longest billing cycle is one year.',
815
+ ],
816
+ [
817
+ { interval: 'month', trialDays: 366 },
818
+ 'PayPal cannot run a free trial of 366 days: its longest is 365 days.',
819
+ ],
820
+ ]
821
+ for (const [config, error] of refusals) {
822
+ const { result, calls } = await plan(config)
823
+ expect(result).toMatchObject({ ok: 'false', error })
824
+ expect(calls).toEqual([])
825
+ }
826
+ for (const config of [
827
+ { interval: 'month', intervalCount: 12 },
828
+ { interval: 'week', intervalCount: 52, trialDays: 365 },
829
+ { interval: 'year', intervalCount: 1 },
830
+ ]) {
831
+ expect((await plan(config)).result).toMatchObject({ ok: 'true', planId: 'P-1' })
832
+ }
833
+ })
834
+ })
835
+
836
+ describe('payment-manage-subscription', () => {
837
+ const handler: HandlerFn = loadHandler('payment-manage-subscription')
838
+ const source = paymentManageSubscription.generateHandler()
839
+
840
+ it('is a non-terminal server node whose credentials are collected', () => {
841
+ expect(paymentManageSubscription.executionEnv).toBe('server')
842
+ expect(paymentManageSubscription.isTerminal).toBeFalsy()
843
+ expect(resolveHandlerEntryName(source, 'payment-manage-subscription')).toBe(
844
+ 'payment_manage_subscription'
845
+ )
846
+ const secrets = collectSecrets({
847
+ workflows: {
848
+ wf1: {
849
+ nodes: [
850
+ {
851
+ id: 'n1',
852
+ type: 'payment-manage-subscription',
853
+ config: { secretKey: 'sk_1', clientId: 'id_1', clientSecret: 'cs_1' },
854
+ },
855
+ ],
856
+ },
857
+ },
858
+ } as never)
859
+ expect(secrets.map((secret) => secret.fieldName).sort()).toEqual([
860
+ 'clientId',
861
+ 'clientSecret',
862
+ 'secretKey',
863
+ ])
864
+ })
865
+
866
+ it('refuses without an id, an unknown action or a provider that cannot manage one — in one result shape', async () => {
867
+ const noId = (await handler({ providerId: 'stripe', action: 'cancel' }, {})) as Record<
868
+ string,
869
+ unknown
870
+ >
871
+ expect(noId).toEqual({
872
+ ok: 'false',
873
+ status: '',
874
+ cancelAtPeriodEnd: 'false',
875
+ currentPeriodStart: '',
876
+ currentPeriodEnd: '',
877
+ error: 'No provider subscription id was supplied, so there is nothing to manage.',
878
+ })
879
+ const badAction = (await handler(
880
+ { providerId: 'stripe', providerSubscriptionId: 'sub_1', action: 'freeze' },
881
+ {}
882
+ )) as { error: string }
883
+ expect(badAction.error).toBe('Unknown subscription action "freeze".')
884
+ const badProvider = (await handler(
885
+ { providerId: 'adyen', providerSubscriptionId: 's', action: 'cancel' },
886
+ {}
887
+ )) as { error: string }
888
+ expect(badProvider.error).toBe('Payment provider "adyen" cannot manage subscriptions.')
889
+ await withEnv(
890
+ {
891
+ STRIPE_SECRET_KEY: undefined,
892
+ CONFIGURATION_STRIPE_SECRET_KEY: undefined,
893
+ STRIPE_TEST_KEY: undefined,
894
+ },
895
+ async () => {
896
+ const missing = (await handler(
897
+ { providerId: 'stripe', providerSubscriptionId: 'sub_1', action: 'cancel' },
898
+ {}
899
+ )) as { error: string }
900
+ expect(missing.error).toBe('STRIPE_SECRET_KEY is not configured')
901
+ }
902
+ )
903
+ })
904
+
905
+ it('maps every Stripe action onto the API and the answer onto the store vocabulary', async () => {
906
+ const statuses: Record<string, string> = {
907
+ cancel: 'canceled',
908
+ cancel_at_period_end: 'active',
909
+ pause: 'active',
910
+ resume: 'active',
911
+ }
912
+ const answer = (status: string) => () => ({ status, current_period_end: 1700000000 })
913
+ const { FakeStripe, calls } = createFakeStripe({
914
+ 'subscriptions.cancel': answer(statuses.cancel),
915
+ // `update(id, changes)`: the fake records the changes as the call's options.
916
+ 'subscriptions.update': (_id, changes) => ({
917
+ status: 'active',
918
+ pause_collection: (changes as { pause_collection?: unknown }).pause_collection || null,
919
+ cancel_at_period_end:
920
+ (changes as { cancel_at_period_end?: boolean }).cancel_at_period_end === true,
921
+ }),
922
+ })
923
+ const stripeHandler = loadHandler('payment-manage-subscription', {
924
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
925
+ })
926
+ const run = (action: string) =>
927
+ withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () =>
928
+ stripeHandler({ providerId: 'stripe', providerSubscriptionId: 'sub_1', action }, {})
929
+ ) as Promise<{ status: string; cancelAtPeriodEnd: string }>
930
+ expect((await run('cancel')).status).toBe('cancelled')
931
+ expect(await run('cancel_at_period_end')).toMatchObject({
932
+ status: 'active',
933
+ cancelAtPeriodEnd: 'true',
934
+ })
935
+ expect((await run('pause')).status).toBe('paused')
936
+ expect(await run('resume')).toMatchObject({ status: 'active', cancelAtPeriodEnd: 'false' })
937
+ expect(calls).toEqual([
938
+ { method: 'subscriptions.cancel', params: 'sub_1' },
939
+ { method: 'subscriptions.update', params: 'sub_1', options: { cancel_at_period_end: true } },
940
+ {
941
+ method: 'subscriptions.update',
942
+ params: 'sub_1',
943
+ options: { pause_collection: { behavior: 'void' } },
944
+ },
945
+ {
946
+ method: 'subscriptions.update',
947
+ params: 'sub_1',
948
+ options: { pause_collection: '', cancel_at_period_end: false },
949
+ },
950
+ ])
951
+ })
952
+
953
+ // The same decisions as the editor's (the worker's `mapStripeSubscription`).
954
+ it('keeps an ended Stripe subscription ended and leaves a status it does not know unmapped', async () => {
955
+ const read = async (subscription: Record<string, unknown>) => {
956
+ const { FakeStripe } = createFakeStripe({ 'subscriptions.retrieve': () => subscription })
957
+ const stripeHandler = loadHandler('payment-manage-subscription', {
958
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
959
+ })
960
+ return (await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () =>
961
+ stripeHandler(
962
+ { providerId: 'stripe', providerSubscriptionId: 'sub_1', action: 'refresh' },
963
+ {}
964
+ )
965
+ )) as { status: string; cancelAtPeriodEnd: string }
966
+ }
967
+ const paused = { pause_collection: { behavior: 'void' } }
968
+ const ended = await read({ status: 'canceled', cancel_at_period_end: true, ...paused })
969
+ expect(ended).toMatchObject({ status: 'cancelled', cancelAtPeriodEnd: 'false' })
970
+ expect((await read({ status: 'incomplete_expired', ...paused })).status).toBe('expired')
971
+ expect((await read({ status: 'trialing', ...paused })).status).toBe('paused')
972
+ expect((await read({ status: 'past_due', ...paused })).status).toBe('paused')
973
+ expect((await read({ status: 'something_new' })).status).toBe('')
974
+ // A dashboard date after the period's end still renews first.
975
+ expect(
976
+ (await read({ status: 'active', cancel_at: 1700000900, current_period_end: 1700000500 }))
977
+ .cancelAtPeriodEnd
978
+ ).toBe('false')
979
+ })
980
+
981
+ it('reads a Stripe subscription back without changing it, a dashboard `cancel_at` counting as scheduled', async () => {
982
+ const { FakeStripe, calls } = createFakeStripe({
983
+ 'subscriptions.retrieve': () => ({
984
+ status: 'past_due',
985
+ cancel_at: 1700000000,
986
+ // 2025 API versions carry the period on the item.
987
+ items: { data: [{ current_period_start: 1690000000, current_period_end: 1700000500 }] },
988
+ }),
989
+ })
990
+ const stripeHandler = loadHandler('payment-manage-subscription', {
991
+ paymentDrivers: loadPaymentDrivers({ stripe: FakeStripe }),
992
+ })
993
+ const result = await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () =>
994
+ stripeHandler(
995
+ { providerId: 'stripe', providerSubscriptionId: 'sub_1', action: 'refresh' },
996
+ {}
997
+ )
998
+ )
999
+ expect(result).toEqual({
1000
+ ok: 'true',
1001
+ status: 'past_due',
1002
+ cancelAtPeriodEnd: 'true',
1003
+ currentPeriodStart: new Date(1690000000 * 1000).toISOString(),
1004
+ currentPeriodEnd: new Date(1700000500 * 1000).toISOString(),
1005
+ })
1006
+ expect(calls).toEqual([{ method: 'subscriptions.retrieve', params: 'sub_1' }])
1007
+ })
1008
+
1009
+ it('reads a PayPal subscription back without posting anything', async () => {
1010
+ await withEnv(PAYPAL_ENV, () =>
1011
+ withFetch(
1012
+ (url) => {
1013
+ if (paypalAuth(url)) {
1014
+ return { ok: true, body: { access_token: 'tok' } }
1015
+ }
1016
+ return {
1017
+ ok: true,
1018
+ body: {
1019
+ id: 'I-ABC',
1020
+ status: 'SUSPENDED',
1021
+ start_time: '2026-09-01T10:00:00Z',
1022
+ billing_info: {
1023
+ last_payment: { time: '2026-09-22T10:00:00Z' },
1024
+ next_billing_time: '2026-10-22T10:00:00Z',
1025
+ },
1026
+ },
1027
+ }
1028
+ },
1029
+ async (calls) => {
1030
+ const result = await handler(
1031
+ { providerId: 'paypal', providerSubscriptionId: 'I-ABC', action: 'refresh' },
1032
+ {}
1033
+ )
1034
+ expect(result).toEqual({
1035
+ ok: 'true',
1036
+ status: 'paused',
1037
+ cancelAtPeriodEnd: 'false',
1038
+ currentPeriodStart: '2026-09-22T10:00:00Z',
1039
+ currentPeriodEnd: '2026-10-22T10:00:00Z',
1040
+ })
1041
+ expect(
1042
+ calls.filter((call) => call.init.method === 'POST' && !paypalAuth(call.url))
1043
+ ).toEqual([])
1044
+ expect(
1045
+ calls.some(
1046
+ (call) => !call.init.method && call.url.endsWith('/v1/billing/subscriptions/I-ABC')
1047
+ )
1048
+ ).toBe(true)
1049
+ }
1050
+ )
1051
+ )
1052
+ })
1053
+
1054
+ it('cancels, suspends and reactivates a PayPal subscription and reads the state back', async () => {
1055
+ const cases: Array<[string, string, string, string]> = [
1056
+ ['cancel', '/cancel', 'CANCELLED', 'cancelled'],
1057
+ ['cancel_at_period_end', '/cancel', 'CANCELLED', 'cancelled'],
1058
+ ['pause', '/suspend', 'SUSPENDED', 'paused'],
1059
+ ['resume', '/activate', 'ACTIVE', 'active'],
1060
+ ]
1061
+ for (const [action, endpoint, providerStatus, storeStatus] of cases) {
1062
+ await withEnv(PAYPAL_ENV, () =>
1063
+ withFetch(
1064
+ (url, init) => {
1065
+ if (paypalAuth(url)) {
1066
+ return { ok: true, body: { access_token: 'tok' } }
1067
+ }
1068
+ if (init.method === 'POST') {
1069
+ return { ok: true, status: 204, body: {} }
1070
+ }
1071
+ return {
1072
+ ok: true,
1073
+ body: {
1074
+ id: 'I-ABC',
1075
+ status: providerStatus,
1076
+ billing_info: { next_billing_time: '2026-10-22T10:00:00Z' },
1077
+ },
1078
+ }
1079
+ },
1080
+ async (calls) => {
1081
+ const result = (await handler(
1082
+ { providerId: 'paypal', providerSubscriptionId: 'I-ABC', action },
1083
+ {}
1084
+ )) as Record<string, unknown>
1085
+ expect([action, result.ok]).toEqual([action, 'true'])
1086
+ expect([action, result.status]).toEqual([action, storeStatus])
1087
+ const post = calls.find((call) => call.init.method === 'POST' && !paypalAuth(call.url))!
1088
+ expect(post.url.endsWith('/v1/billing/subscriptions/I-ABC' + endpoint)).toBe(true)
1089
+ expect(post.init.headers?.Authorization).toBe('Bearer tok')
1090
+ const read = calls.find((call) => !call.init.method && !paypalAuth(call.url))!
1091
+ expect(read.url.endsWith('/v1/billing/subscriptions/I-ABC')).toBe(true)
1092
+ }
1093
+ )
1094
+ )
1095
+ }
1096
+ })
1097
+
1098
+ it('reports a PayPal refusal as a failure the workflow can read', async () => {
1099
+ await withEnv(PAYPAL_ENV, () =>
1100
+ withFetch(
1101
+ (url) =>
1102
+ paypalAuth(url)
1103
+ ? { ok: true, body: { access_token: 'tok' } }
1104
+ : { ok: false, status: 422, body: { message: 'SUBSCRIPTION_STATUS_INVALID' } },
1105
+ async () => {
1106
+ const result = (await handler(
1107
+ { providerId: 'paypal', providerSubscriptionId: 'I-ABC', action: 'pause' },
1108
+ {}
1109
+ )) as {
1110
+ ok: string
1111
+ error: string
1112
+ }
1113
+ expect(result.ok).toBe('false')
1114
+ expect(result.error).toContain('SUBSCRIPTION_STATUS_INVALID')
1115
+ }
1116
+ )
1117
+ )
1118
+ })
1119
+ })
1120
+
1121
+ /** A stand-in Stripe SDK: records every portal call and answers from the scripted replies. */
1122
+ interface FakeStripeScript {
1123
+ sessionErrors?: string[]
1124
+ configurations?: Array<{ id: string; metadata?: Record<string, string> }>
1125
+ }
1126
+
1127
+ const withFakeStripe = async <T>(
1128
+ script: FakeStripeScript,
1129
+ run: (calls: Array<{ method: string; params: Record<string, unknown> }>) => Promise<T>
1130
+ ): Promise<T> => {
1131
+ const calls: Array<{ method: string; params: Record<string, unknown> }> = []
1132
+ const errors = [...(script.sessionErrors || [])]
1133
+ class FakeStripe {
1134
+ billingPortal = {
1135
+ sessions: {
1136
+ create: async (params: Record<string, unknown>) => {
1137
+ calls.push({ method: 'sessions.create', params })
1138
+ const error = errors.shift()
1139
+ if (error) {
1140
+ throw new Error(error)
1141
+ }
1142
+ return { url: 'https://billing.stripe.com/p/session/test_1' }
1143
+ },
1144
+ },
1145
+ configurations: {
1146
+ list: async (params: Record<string, unknown>) => {
1147
+ calls.push({ method: 'configurations.list', params })
1148
+ return { data: script.configurations || [] }
1149
+ },
1150
+ create: async (params: Record<string, unknown>) => {
1151
+ calls.push({ method: 'configurations.create', params })
1152
+ return { id: 'bpc_created' }
1153
+ },
1154
+ },
1155
+ }
1156
+ }
1157
+ const scope = globalThis as {
1158
+ __non_webpack_require__?: unknown
1159
+ __stripeBillingPortalConfigurationId?: string
1160
+ }
1161
+ scope.__non_webpack_require__ = (name: string) => {
1162
+ if (name !== 'stripe') {
1163
+ throw new Error('unexpected require ' + name)
1164
+ }
1165
+ return FakeStripe
1166
+ }
1167
+ try {
1168
+ return await withEnv({ STRIPE_SECRET_KEY: 'sk_test_1' }, () => run(calls))
1169
+ } finally {
1170
+ delete scope.__non_webpack_require__
1171
+ delete scope.__stripeBillingPortalConfigurationId
1172
+ }
1173
+ }
1174
+
1175
+ describe('payment-billing-portal', () => {
1176
+ const handler: HandlerFn = loadHandler('payment-billing-portal')
1177
+ const source = paymentBillingPortal.generateHandler()
1178
+ const RETURN_URL = 'https://store.test/my-profile?tab=subscriptions'
1179
+ const NO_DEFAULT_CONFIGURATION =
1180
+ 'No configuration provided and your test mode default configuration has not been created.'
1181
+
1182
+ it('is a non-terminal server node whose credentials are collected', () => {
1183
+ expect(paymentBillingPortal.executionEnv).toBe('server')
1184
+ expect(paymentBillingPortal.isTerminal).toBeFalsy()
1185
+ expect(resolveHandlerEntryName(source, 'payment-billing-portal')).toBe('payment_billing_portal')
1186
+ const secrets = collectSecrets({
1187
+ workflows: {
1188
+ wf1: {
1189
+ nodes: [
1190
+ {
1191
+ id: 'n1',
1192
+ type: 'payment-billing-portal',
1193
+ config: { secretKey: 'sk_1', clientId: 'id_1', clientSecret: 'cs_1' },
1194
+ },
1195
+ ],
1196
+ },
1197
+ },
1198
+ } as never)
1199
+ expect(secrets.map((secret) => secret.fieldName).sort()).toEqual([
1200
+ 'clientId',
1201
+ 'clientSecret',
1202
+ 'secretKey',
1203
+ ])
1204
+ })
1205
+
1206
+ it('refuses, in one result shape, what it cannot open', async () => {
1207
+ expect(
1208
+ await handler({ providerId: 'adyen', providerCustomerId: 'c', returnUrl: RETURN_URL }, {})
1209
+ ).toEqual({
1210
+ ok: 'false',
1211
+ url: '',
1212
+ error: 'Payment provider "adyen" has no billing portal.',
1213
+ })
1214
+ const noCustomer = (await handler({ providerId: 'stripe', returnUrl: RETURN_URL }, {})) as {
1215
+ error: string
1216
+ }
1217
+ expect(noCustomer.error).toBe('No Stripe customer is attached to this subscription yet.')
1218
+ for (const returnUrl of ['', '/my-profile', 'javascript:alert(1)']) {
1219
+ const badUrl = (await handler(
1220
+ { providerId: 'stripe', providerCustomerId: 'cus_1', returnUrl },
1221
+ {}
1222
+ )) as {
1223
+ error: string
1224
+ }
1225
+ expect(badUrl.error).toBe(
1226
+ 'A return URL (http or https) is required to open the billing portal.'
1227
+ )
1228
+ }
1229
+ await withEnv(
1230
+ {
1231
+ STRIPE_SECRET_KEY: undefined,
1232
+ CONFIGURATION_STRIPE_SECRET_KEY: undefined,
1233
+ STRIPE_TEST_KEY: undefined,
1234
+ },
1235
+ async () => {
1236
+ const missing = (await handler(
1237
+ { providerId: 'stripe', providerCustomerId: 'cus_1', returnUrl: RETURN_URL },
1238
+ {}
1239
+ )) as { error: string }
1240
+ expect(missing.error).toBe('STRIPE_SECRET_KEY is not configured')
1241
+ }
1242
+ )
1243
+ })
1244
+
1245
+ it("opens a Stripe portal session for the subscription's customer", async () => {
1246
+ await withFakeStripe({}, async (calls) => {
1247
+ const result = await handler(
1248
+ { providerId: 'stripe', providerCustomerId: 'cus_1', returnUrl: RETURN_URL },
1249
+ {}
1250
+ )
1251
+ expect(result).toEqual({ ok: 'true', url: 'https://billing.stripe.com/p/session/test_1' })
1252
+ expect(calls).toEqual([
1253
+ { method: 'sessions.create', params: { customer: 'cus_1', return_url: RETURN_URL } },
1254
+ ])
1255
+ })
1256
+ })
1257
+
1258
+ it('creates the store portal configuration once when the account has none, then reuses it', async () => {
1259
+ await withFakeStripe({ sessionErrors: [NO_DEFAULT_CONFIGURATION] }, async (calls) => {
1260
+ const first = await handler(
1261
+ { providerId: 'stripe', providerCustomerId: 'cus_1', returnUrl: RETURN_URL },
1262
+ {}
1263
+ )
1264
+ expect(first).toEqual({ ok: 'true', url: 'https://billing.stripe.com/p/session/test_1' })
1265
+ expect(calls.map((call) => call.method)).toEqual([
1266
+ 'sessions.create',
1267
+ 'configurations.list',
1268
+ 'configurations.create',
1269
+ 'sessions.create',
1270
+ ])
1271
+ expect(calls[2].params).toEqual({
1272
+ business_profile: { headline: 'Manage your payment method and invoices' },
1273
+ features: { payment_method_update: { enabled: true }, invoice_history: { enabled: true } },
1274
+ metadata: { teleport: 'teleport-store-billing-portal' },
1275
+ })
1276
+ expect(calls[3].params).toEqual({
1277
+ customer: 'cus_1',
1278
+ return_url: RETURN_URL,
1279
+ configuration: 'bpc_created',
1280
+ })
1281
+
1282
+ // The next subscriber goes straight to a session with it.
1283
+ calls.length = 0
1284
+ await handler(
1285
+ { providerId: 'stripe', providerCustomerId: 'cus_2', returnUrl: RETURN_URL },
1286
+ {}
1287
+ )
1288
+ expect(calls).toEqual([
1289
+ {
1290
+ method: 'sessions.create',
1291
+ params: { customer: 'cus_2', return_url: RETURN_URL, configuration: 'bpc_created' },
1292
+ },
1293
+ ])
1294
+ })
1295
+ })
1296
+
1297
+ it('finds the configuration a previous cold start created instead of creating another', async () => {
1298
+ await withFakeStripe(
1299
+ {
1300
+ sessionErrors: [NO_DEFAULT_CONFIGURATION],
1301
+ configurations: [
1302
+ { id: 'bpc_merchant', metadata: {} },
1303
+ { id: 'bpc_store', metadata: { teleport: 'teleport-store-billing-portal' } },
1304
+ ],
1305
+ },
1306
+ async (calls) => {
1307
+ await handler(
1308
+ { providerId: 'stripe', providerCustomerId: 'cus_1', returnUrl: RETURN_URL },
1309
+ {}
1310
+ )
1311
+ expect(calls.map((call) => call.method)).toEqual([
1312
+ 'sessions.create',
1313
+ 'configurations.list',
1314
+ 'sessions.create',
1315
+ ])
1316
+ expect(calls[2].params.configuration).toBe('bpc_store')
1317
+ }
1318
+ )
1319
+ })
1320
+
1321
+ it('reports any other Stripe refusal without touching the configuration', async () => {
1322
+ await withFakeStripe({ sessionErrors: ['No such customer: cus_gone'] }, async (calls) => {
1323
+ const result = await handler(
1324
+ { providerId: 'stripe', providerCustomerId: 'cus_gone', returnUrl: RETURN_URL },
1325
+ {}
1326
+ )
1327
+ expect(result).toEqual({ ok: 'false', url: '', error: 'No such customer: cus_gone' })
1328
+ expect(calls.map((call) => call.method)).toEqual(['sessions.create'])
1329
+ })
1330
+ })
1331
+
1332
+ it("sends a PayPal subscriber to the automatic-payments page of the store's environment", async () => {
1333
+ for (const [sandboxAnswers, expected] of [
1334
+ [true, 'https://www.sandbox.paypal.com/myaccount/autopay/'],
1335
+ [false, 'https://www.paypal.com/myaccount/autopay/'],
1336
+ ] as Array<[boolean, string]>) {
1337
+ await withEnv(PAYPAL_ENV, () =>
1338
+ withFetch(
1339
+ (url) =>
1340
+ url.startsWith('https://api-m.sandbox.paypal.com') && !sandboxAnswers
1341
+ ? { ok: false, status: 401, body: { error: 'invalid_client' } }
1342
+ : { ok: true, body: { access_token: 'tok' } },
1343
+ async () => {
1344
+ expect(await handler({ providerId: 'paypal', returnUrl: RETURN_URL }, {})).toEqual({
1345
+ ok: 'true',
1346
+ url: expected,
1347
+ })
1348
+ }
1349
+ )
1350
+ )
1351
+ }
1352
+ await withEnv({ PAYPAL_CLIENT_ID: undefined, PAYPAL_CLIENT_SECRET: undefined }, async () => {
1353
+ expect(await handler({ providerId: 'paypal' }, {})).toEqual({
1354
+ ok: 'false',
1355
+ url: '',
1356
+ error: 'PayPal credentials are not configured',
1357
+ })
1358
+ })
1359
+ })
1360
+ })