@volter/twin-stripe 2.0.38 → 3.0.1

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 (402) hide show
  1. package/README.md +112 -207
  2. package/dist/generated/pack-facts.json +94 -0
  3. package/dist/journeys/coverage.json +596 -0
  4. package/dist/journeys/customer-life.json +6108 -0
  5. package/dist/journeys/customer-life.outline.md +371 -0
  6. package/dist/journeys/decisions.json +677 -0
  7. package/dist/journeys/demand.json +706 -0
  8. package/dist/journeys/score.json +853 -0
  9. package/dist/journeys/unreachable.json +102 -0
  10. package/dist/journeys/vendor-examples.json +8010 -0
  11. package/dist/spec/SOURCE.md +18 -0
  12. package/dist/spec/doc-examples.json +445 -0
  13. package/dist/spec/fixtures3.json.gz +0 -0
  14. package/dist/spec/openapi.json.gz +0 -0
  15. package/dist/spec/patches.json +34 -0
  16. package/dist/spec/sources.json +306 -0
  17. package/dist/src/cli.d.ts +0 -1
  18. package/dist/src/cli.js +11 -31
  19. package/dist/src/engine/after-payment.d.ts +8 -0
  20. package/dist/src/engine/after-payment.js +27 -0
  21. package/dist/src/engine/apps-secrets.d.ts +1 -0
  22. package/dist/src/engine/apps-secrets.js +3 -0
  23. package/dist/src/engine/balance.d.ts +5 -0
  24. package/dist/src/engine/balance.js +15 -0
  25. package/dist/src/engine/checkout.d.ts +24 -0
  26. package/dist/src/engine/checkout.js +30 -0
  27. package/dist/src/engine/common.d.ts +19 -0
  28. package/dist/src/engine/common.js +34 -0
  29. package/dist/src/engine/connect.d.ts +45 -0
  30. package/dist/src/engine/connect.js +108 -0
  31. package/dist/src/engine/customers.d.ts +4 -0
  32. package/dist/src/engine/customers.js +8 -0
  33. package/dist/src/engine/display.d.ts +11 -0
  34. package/dist/src/engine/display.js +13 -0
  35. package/dist/src/engine/files.d.ts +11 -0
  36. package/dist/src/engine/files.js +23 -0
  37. package/dist/src/engine/invoices.d.ts +21 -0
  38. package/dist/src/engine/invoices.js +84 -0
  39. package/dist/src/engine/issuing.d.ts +33 -0
  40. package/dist/src/engine/issuing.js +54 -0
  41. package/dist/src/engine/ledger.d.ts +8 -0
  42. package/dist/src/engine/ledger.js +8 -0
  43. package/dist/src/engine/oauth.d.ts +4 -0
  44. package/dist/src/engine/oauth.js +24 -0
  45. package/dist/src/engine/onboarding.d.ts +13 -0
  46. package/dist/src/engine/onboarding.js +42 -0
  47. package/dist/src/{stripe-params.d.ts → engine/params.d.ts} +20 -3
  48. package/dist/src/{stripe-params.js → engine/params.js} +7 -60
  49. package/dist/src/engine/payment-intents.d.ts +10 -0
  50. package/dist/src/engine/payment-intents.js +27 -0
  51. package/dist/src/engine/payment-methods.d.ts +16 -0
  52. package/dist/src/engine/payment-methods.js +22 -0
  53. package/dist/src/engine/radar.d.ts +2 -0
  54. package/dist/src/engine/radar.js +5 -0
  55. package/dist/src/engine/refunds.d.ts +1 -0
  56. package/dist/src/engine/refunds.js +3 -0
  57. package/dist/src/engine/renewals.d.ts +36 -0
  58. package/dist/src/engine/renewals.js +65 -0
  59. package/dist/src/{stripe-twin.d.ts → engine/stripe.d.ts} +12 -45
  60. package/dist/src/{stripe-twin.js → engine/stripe.js} +53 -387
  61. package/dist/src/engine/subscriptions.d.ts +11 -0
  62. package/dist/src/engine/subscriptions.js +30 -0
  63. package/dist/src/engine/transfers.d.ts +2 -0
  64. package/dist/src/engine/transfers.js +1 -0
  65. package/dist/src/{stripe-version.d.ts → engine/version.d.ts} +0 -2
  66. package/dist/src/{stripe-version.js → engine/version.js} +21 -9
  67. package/dist/src/engine/webhook-endpoints.d.ts +1 -0
  68. package/dist/src/engine/webhook-endpoints.js +12 -0
  69. package/dist/src/engine/webhooks.d.ts +31 -0
  70. package/dist/src/engine/webhooks.js +68 -0
  71. package/dist/src/fetch.d.ts +2 -0
  72. package/dist/src/fetch.js +26 -0
  73. package/dist/src/generated/surface.gen.json +1 -1
  74. package/dist/src/generated/ui.gen.json +1 -1
  75. package/dist/src/index.d.ts +5 -14
  76. package/dist/src/index.js +10 -75
  77. package/dist/src/manifest.js +478 -876
  78. package/dist/src/screens/billing-portal.d.ts +3 -0
  79. package/dist/src/screens/{portal.js → billing-portal.js} +32 -58
  80. package/dist/src/screens/checkout-js.d.ts +2 -0
  81. package/dist/src/screens/checkout-js.js +84 -0
  82. package/dist/src/screens/checkout.d.ts +2 -31
  83. package/dist/src/screens/checkout.js +32 -121
  84. package/dist/src/screens/connect-onboarding.d.ts +3 -0
  85. package/dist/src/screens/{onboarding.js → connect-onboarding.js} +38 -104
  86. package/dist/src/screens/dashboard.d.ts +3 -0
  87. package/dist/src/screens/dashboard.js +116 -0
  88. package/dist/src/screens/shared.d.ts +27 -0
  89. package/dist/src/screens/shared.js +87 -0
  90. package/dist/src/screens/stripe-js.d.ts +3 -0
  91. package/dist/src/screens/stripe-js.js +95 -0
  92. package/dist/src/semantics/account.d.ts +2 -0
  93. package/dist/src/semantics/account.js +8 -0
  94. package/dist/src/semantics/account_links.d.ts +2 -0
  95. package/dist/src/semantics/account_links.js +22 -0
  96. package/dist/src/semantics/accounts.d.ts +4 -0
  97. package/dist/src/semantics/accounts.js +40 -0
  98. package/dist/src/semantics/apps.d.ts +4 -0
  99. package/dist/src/semantics/{apps-secrets.js → apps.js} +14 -26
  100. package/dist/src/semantics/around.d.ts +2 -0
  101. package/dist/src/semantics/around.js +13 -0
  102. package/dist/src/semantics/balance.d.ts +2 -11
  103. package/dist/src/semantics/balance.js +3 -194
  104. package/dist/src/semantics/balance_transactions.d.ts +2 -0
  105. package/dist/src/semantics/balance_transactions.js +15 -0
  106. package/dist/src/semantics/billing_portal.d.ts +4 -0
  107. package/dist/src/semantics/billing_portal.js +36 -0
  108. package/dist/src/semantics/charges.d.ts +3 -28
  109. package/dist/src/semantics/charges.js +5 -202
  110. package/dist/src/semantics/checkout.d.ts +3 -20
  111. package/dist/src/semantics/checkout.js +21 -271
  112. package/dist/src/semantics/clock.d.ts +2 -0
  113. package/dist/src/semantics/clock.js +15 -0
  114. package/dist/src/semantics/coupons.d.ts +2 -6
  115. package/dist/src/semantics/coupons.js +2 -60
  116. package/dist/src/semantics/customers.d.ts +5 -6
  117. package/dist/src/semantics/customers.js +47 -413
  118. package/dist/src/semantics/doors.d.ts +23 -0
  119. package/dist/src/semantics/doors.js +73 -0
  120. package/dist/src/semantics/entitlements.d.ts +0 -2
  121. package/dist/src/semantics/entitlements.js +4 -95
  122. package/dist/src/semantics/events.d.ts +11 -0
  123. package/dist/src/semantics/events.js +31 -0
  124. package/dist/src/semantics/index.d.ts +2 -0
  125. package/dist/src/semantics/index.js +85 -0
  126. package/dist/src/semantics/invoice_payments.d.ts +2 -0
  127. package/dist/src/semantics/invoice_payments.js +12 -0
  128. package/dist/src/semantics/invoices.d.ts +11 -18
  129. package/dist/src/semantics/invoices.js +121 -440
  130. package/dist/src/semantics/issuing.d.ts +6 -13
  131. package/dist/src/semantics/issuing.js +58 -556
  132. package/dist/src/semantics/payment_intents.d.ts +3 -0
  133. package/dist/src/semantics/payment_intents.js +71 -0
  134. package/dist/src/semantics/payment_methods.d.ts +3 -0
  135. package/dist/src/semantics/payment_methods.js +15 -0
  136. package/dist/src/semantics/payouts.d.ts +3 -0
  137. package/dist/src/semantics/payouts.js +28 -0
  138. package/dist/src/semantics/prices.d.ts +4 -0
  139. package/dist/src/semantics/prices.js +37 -0
  140. package/dist/src/semantics/products.d.ts +4 -2
  141. package/dist/src/semantics/products.js +12 -138
  142. package/dist/src/semantics/promotion_codes.d.ts +3 -0
  143. package/dist/src/semantics/promotion_codes.js +35 -0
  144. package/dist/src/semantics/radar.d.ts +2 -2
  145. package/dist/src/semantics/radar.js +5 -74
  146. package/dist/src/semantics/refunds.d.ts +2 -9
  147. package/dist/src/semantics/refunds.js +3 -193
  148. package/dist/src/semantics/shared.d.ts +558 -55
  149. package/dist/src/semantics/shared.js +2070 -114
  150. package/dist/src/semantics/states.d.ts +462 -0
  151. package/dist/src/semantics/states.js +634 -0
  152. package/dist/src/semantics/subscriptions.d.ts +6 -11
  153. package/dist/src/semantics/subscriptions.js +37 -530
  154. package/dist/src/semantics/test_helpers.d.ts +3 -0
  155. package/dist/src/semantics/test_helpers.js +125 -0
  156. package/dist/src/semantics/transfers.d.ts +2 -2
  157. package/dist/src/semantics/transfers.js +6 -101
  158. package/dist/src/semantics/webhook_endpoints.d.ts +2 -0
  159. package/dist/src/semantics/webhook_endpoints.js +26 -0
  160. package/dist/src/server.d.ts +7 -0
  161. package/dist/src/server.js +7 -0
  162. package/generated/pack-facts.json +94 -0
  163. package/journeys/coverage.json +596 -0
  164. package/journeys/customer-life.json +6108 -0
  165. package/journeys/customer-life.outline.md +371 -0
  166. package/journeys/decisions.json +677 -0
  167. package/journeys/demand.json +706 -0
  168. package/journeys/score.json +853 -0
  169. package/journeys/unreachable.json +102 -0
  170. package/journeys/vendor-examples.json +8010 -0
  171. package/package.json +11 -20
  172. package/spec/SOURCE.md +18 -0
  173. package/spec/doc-examples.json +445 -0
  174. package/spec/fixtures3.json.gz +0 -0
  175. package/spec/openapi.json.gz +0 -0
  176. package/spec/patches.json +34 -0
  177. package/spec/sources.json +306 -0
  178. package/src/cli.ts +11 -28
  179. package/src/engine/after-payment.ts +29 -0
  180. package/src/engine/apps-secrets.ts +4 -0
  181. package/src/engine/balance.ts +32 -0
  182. package/src/engine/checkout.ts +39 -0
  183. package/src/engine/common.ts +49 -0
  184. package/src/engine/connect.ts +106 -0
  185. package/src/engine/customers.ts +10 -0
  186. package/src/engine/display.ts +18 -0
  187. package/src/engine/files.ts +28 -0
  188. package/src/engine/invoices.ts +102 -0
  189. package/src/engine/issuing.ts +66 -0
  190. package/src/engine/ledger.ts +48 -0
  191. package/src/engine/oauth.ts +18 -0
  192. package/src/engine/onboarding.ts +53 -0
  193. package/src/{stripe-params.ts → engine/params.ts} +7 -56
  194. package/src/engine/payment-intents.ts +32 -0
  195. package/src/engine/payment-methods.ts +24 -0
  196. package/src/engine/radar.ts +6 -0
  197. package/src/engine/refunds.ts +3 -0
  198. package/src/engine/renewals.ts +72 -0
  199. package/src/{stripe-twin.ts → engine/stripe.ts} +57 -400
  200. package/src/engine/subscriptions.ts +37 -0
  201. package/src/engine/transfers.ts +22 -0
  202. package/src/{stripe-version.ts → engine/version.ts} +19 -10
  203. package/src/engine/webhook-endpoints.ts +14 -0
  204. package/src/engine/webhooks.ts +70 -0
  205. package/src/fetch.ts +27 -0
  206. package/src/generated/surface.gen.json +1 -1
  207. package/src/generated/ui.gen.json +1 -1
  208. package/src/index.ts +10 -116
  209. package/src/manifest.ts +480 -904
  210. package/src/screens/{portal.tsx → billing-portal.tsx} +35 -42
  211. package/src/screens/checkout-js.ts +80 -0
  212. package/src/screens/checkout.tsx +32 -96
  213. package/src/screens/{onboarding.tsx → connect-onboarding.tsx} +39 -85
  214. package/src/screens/dashboard.tsx +178 -0
  215. package/src/screens/shared.tsx +84 -0
  216. package/src/screens/stripe-js.ts +102 -0
  217. package/src/semantics/account.ts +10 -0
  218. package/src/semantics/account_links.ts +20 -0
  219. package/src/semantics/accounts.ts +44 -0
  220. package/src/semantics/{apps-secrets.ts → apps.ts} +17 -33
  221. package/src/semantics/around.ts +17 -0
  222. package/src/semantics/balance.ts +6 -208
  223. package/src/semantics/balance_transactions.ts +18 -0
  224. package/src/semantics/billing_portal.ts +45 -0
  225. package/src/semantics/charges.ts +8 -212
  226. package/src/semantics/checkout.ts +25 -276
  227. package/src/semantics/clock.ts +19 -0
  228. package/src/semantics/coupons.ts +5 -68
  229. package/src/semantics/customers.ts +48 -414
  230. package/src/semantics/doors.ts +79 -0
  231. package/src/semantics/entitlements.ts +3 -94
  232. package/src/semantics/events.ts +37 -0
  233. package/src/semantics/index.ts +89 -0
  234. package/src/semantics/invoice_payments.ts +16 -0
  235. package/src/semantics/invoices.ts +112 -441
  236. package/src/semantics/issuing.ts +57 -573
  237. package/src/semantics/payment_intents.ts +76 -0
  238. package/src/semantics/payment_methods.ts +20 -0
  239. package/src/semantics/payouts.ts +29 -0
  240. package/src/semantics/prices.ts +41 -0
  241. package/src/semantics/products.ts +12 -146
  242. package/src/semantics/promotion_codes.ts +38 -0
  243. package/src/semantics/radar.ts +8 -79
  244. package/src/semantics/refunds.ts +4 -216
  245. package/src/semantics/shared.ts +2089 -135
  246. package/src/semantics/states.ts +662 -0
  247. package/src/semantics/subscriptions.ts +39 -542
  248. package/src/semantics/test_helpers.ts +119 -0
  249. package/src/semantics/transfers.ts +10 -132
  250. package/src/semantics/webhook_endpoints.ts +27 -0
  251. package/src/server.ts +7 -0
  252. package/client/dashboard-api.ts +0 -286
  253. package/client/stripe-mirror.css +0 -277
  254. package/client/stripe-mirror.tsx +0 -1559
  255. package/dist/client/dashboard-api.d.ts +0 -107
  256. package/dist/client/dashboard-api.js +0 -238
  257. package/dist/client/dashboard-api.ts +0 -286
  258. package/dist/client/stripe-mirror.bundle.js +0 -236
  259. package/dist/client/stripe-mirror.css +0 -277
  260. package/dist/client/stripe-mirror.d.ts +0 -134
  261. package/dist/client/stripe-mirror.js +0 -859
  262. package/dist/client/stripe-mirror.tsx +0 -1559
  263. package/dist/src/screens/connect-oauth.d.ts +0 -27
  264. package/dist/src/screens/connect-oauth.js +0 -414
  265. package/dist/src/screens/connect-settings.d.ts +0 -22
  266. package/dist/src/screens/connect-settings.js +0 -103
  267. package/dist/src/screens/consent-skin.d.ts +0 -4
  268. package/dist/src/screens/consent-skin.js +0 -18
  269. package/dist/src/screens/financial-connections.d.ts +0 -5
  270. package/dist/src/screens/financial-connections.js +0 -90
  271. package/dist/src/screens/identity.d.ts +0 -5
  272. package/dist/src/screens/identity.js +0 -86
  273. package/dist/src/screens/onboarding.d.ts +0 -13
  274. package/dist/src/screens/portal.d.ts +0 -5
  275. package/dist/src/screens/public-details.d.ts +0 -5
  276. package/dist/src/screens/public-details.js +0 -90
  277. package/dist/src/semantics/after-payment.d.ts +0 -22
  278. package/dist/src/semantics/after-payment.js +0 -99
  279. package/dist/src/semantics/apps-secrets.d.ts +0 -2
  280. package/dist/src/semantics/billing.d.ts +0 -2
  281. package/dist/src/semantics/billing.js +0 -220
  282. package/dist/src/semantics/connect.d.ts +0 -5
  283. package/dist/src/semantics/connect.js +0 -493
  284. package/dist/src/semantics/credit-notes.d.ts +0 -2
  285. package/dist/src/semantics/credit-notes.js +0 -172
  286. package/dist/src/semantics/disputes.d.ts +0 -2
  287. package/dist/src/semantics/disputes.js +0 -51
  288. package/dist/src/semantics/ephemeral-keys.d.ts +0 -2
  289. package/dist/src/semantics/ephemeral-keys.js +0 -34
  290. package/dist/src/semantics/files.d.ts +0 -2
  291. package/dist/src/semantics/files.js +0 -125
  292. package/dist/src/semantics/ledger.d.ts +0 -59
  293. package/dist/src/semantics/ledger.js +0 -200
  294. package/dist/src/semantics/payment-intents.d.ts +0 -18
  295. package/dist/src/semantics/payment-intents.js +0 -452
  296. package/dist/src/semantics/payment-links.d.ts +0 -2
  297. package/dist/src/semantics/payment-links.js +0 -133
  298. package/dist/src/semantics/payment-methods.d.ts +0 -20
  299. package/dist/src/semantics/payment-methods.js +0 -140
  300. package/dist/src/semantics/plans.d.ts +0 -5
  301. package/dist/src/semantics/plans.js +0 -121
  302. package/dist/src/semantics/platform.d.ts +0 -9
  303. package/dist/src/semantics/platform.js +0 -206
  304. package/dist/src/semantics/renewals.d.ts +0 -47
  305. package/dist/src/semantics/renewals.js +0 -281
  306. package/dist/src/semantics/setup-intents.d.ts +0 -2
  307. package/dist/src/semantics/setup-intents.js +0 -84
  308. package/dist/src/semantics/subscription-schedules.d.ts +0 -2
  309. package/dist/src/semantics/subscription-schedules.js +0 -119
  310. package/dist/src/semantics/tax.d.ts +0 -2
  311. package/dist/src/semantics/tax.js +0 -197
  312. package/dist/src/semantics/terminal.d.ts +0 -5
  313. package/dist/src/semantics/terminal.js +0 -182
  314. package/dist/src/semantics/test-clocks.d.ts +0 -6
  315. package/dist/src/semantics/test-clocks.js +0 -73
  316. package/dist/src/semantics/tokens.d.ts +0 -4
  317. package/dist/src/semantics/tokens.js +0 -44
  318. package/dist/src/semantics/treasury.d.ts +0 -2
  319. package/dist/src/semantics/treasury.js +0 -377
  320. package/dist/src/semantics/webhook-endpoints.d.ts +0 -3
  321. package/dist/src/semantics/webhook-endpoints.js +0 -85
  322. package/dist/src/stripe-budget.d.ts +0 -55
  323. package/dist/src/stripe-budget.js +0 -155
  324. package/dist/src/stripe-capabilities.d.ts +0 -3
  325. package/dist/src/stripe-capabilities.js +0 -5836
  326. package/dist/src/stripe-conformance.d.ts +0 -43
  327. package/dist/src/stripe-conformance.js +0 -105
  328. package/dist/src/stripe-connector.d.ts +0 -161
  329. package/dist/src/stripe-connector.js +0 -414
  330. package/dist/src/stripe-emit.d.ts +0 -2
  331. package/dist/src/stripe-emit.js +0 -145
  332. package/dist/src/stripe-events.d.ts +0 -93
  333. package/dist/src/stripe-events.js +0 -392
  334. package/dist/src/stripe-js.d.ts +0 -4
  335. package/dist/src/stripe-js.js +0 -70
  336. package/dist/src/stripe-mirror-ui.d.ts +0 -15
  337. package/dist/src/stripe-mirror-ui.js +0 -87
  338. package/dist/src/stripe-perform-harness.d.ts +0 -9
  339. package/dist/src/stripe-perform-harness.js +0 -26
  340. package/dist/src/stripe-server.d.ts +0 -33
  341. package/dist/src/stripe-server.js +0 -429
  342. package/dist/src/stripe-shared.d.ts +0 -109
  343. package/dist/src/stripe-shared.js +0 -276
  344. package/dist/src/stripe-ui-conformance.d.ts +0 -5
  345. package/dist/src/stripe-ui-conformance.js +0 -79
  346. package/dist/src/stripe-ui-structure.d.ts +0 -3
  347. package/dist/src/stripe-ui-structure.js +0 -168
  348. package/dist/test-fixtures/stripe-known-deviations.json +0 -110
  349. package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +0 -14
  350. package/dist/test-fixtures/stripe-openapi-operations.json +0 -4717
  351. package/dist/test-fixtures/stripe-schemas.SOURCE.md +0 -35
  352. package/dist/test-fixtures/stripe-schemas.json +0 -3813
  353. package/src/screens/connect-oauth.tsx +0 -400
  354. package/src/screens/connect-settings.tsx +0 -121
  355. package/src/screens/consent-skin.ts +0 -20
  356. package/src/screens/financial-connections.tsx +0 -101
  357. package/src/screens/identity.tsx +0 -96
  358. package/src/screens/public-details.tsx +0 -105
  359. package/src/semantics/after-payment.ts +0 -118
  360. package/src/semantics/billing.ts +0 -216
  361. package/src/semantics/connect.ts +0 -487
  362. package/src/semantics/credit-notes.ts +0 -168
  363. package/src/semantics/disputes.ts +0 -62
  364. package/src/semantics/ephemeral-keys.ts +0 -34
  365. package/src/semantics/files.ts +0 -143
  366. package/src/semantics/ledger.ts +0 -253
  367. package/src/semantics/payment-intents.ts +0 -463
  368. package/src/semantics/payment-links.ts +0 -148
  369. package/src/semantics/payment-methods.ts +0 -145
  370. package/src/semantics/plans.ts +0 -131
  371. package/src/semantics/platform.ts +0 -220
  372. package/src/semantics/renewals.ts +0 -279
  373. package/src/semantics/setup-intents.ts +0 -87
  374. package/src/semantics/subscription-schedules.ts +0 -129
  375. package/src/semantics/tax.ts +0 -220
  376. package/src/semantics/terminal.ts +0 -195
  377. package/src/semantics/test-clocks.ts +0 -77
  378. package/src/semantics/tokens.ts +0 -52
  379. package/src/semantics/treasury.ts +0 -383
  380. package/src/semantics/webhook-endpoints.ts +0 -87
  381. package/src/stripe-budget.ts +0 -181
  382. package/src/stripe-capabilities.ts +0 -5651
  383. package/src/stripe-conformance.ts +0 -124
  384. package/src/stripe-connector.ts +0 -462
  385. package/src/stripe-emit.ts +0 -157
  386. package/src/stripe-events.ts +0 -434
  387. package/src/stripe-js.ts +0 -70
  388. package/src/stripe-mirror-ui.ts +0 -90
  389. package/src/stripe-perform-harness.ts +0 -29
  390. package/src/stripe-server.ts +0 -393
  391. package/src/stripe-shared.ts +0 -297
  392. package/src/stripe-ui-conformance.ts +0 -88
  393. package/src/stripe-ui-structure.ts +0 -182
  394. package/test-fixtures/stripe-known-deviations.json +0 -110
  395. package/test-fixtures/stripe-openapi-operations.json +0 -4717
  396. package/test-fixtures/stripe-schemas.json +0 -3813
  397. /package/dist/src/{screens → engine}/industries.d.ts +0 -0
  398. /package/dist/src/{screens → engine}/industries.js +0 -0
  399. /package/dist/src/{semantics → engine}/test-cards.d.ts +0 -0
  400. /package/dist/src/{semantics → engine}/test-cards.js +0 -0
  401. /package/src/{screens → engine}/industries.ts +0 -0
  402. /package/src/{semantics → engine}/test-cards.ts +0 -0
@@ -1,281 +0,0 @@
1
- // A subscription's invoices over time: the first one Checkout pays, and each renewal. Time's moves are made
2
- // as the twin's trial end already made them: caught up to the customer's clock (the World's, or its test
3
- // clock) whenever the twin is asked anything (../stripe-server.ts), each checked against the machines in
4
- // ../manifest.ts.
5
- //
6
- // - Checkout's subscription session pays the first invoice with the card the customer entered, which becomes the
7
- // subscription's default payment method (docs.stripe.com/payments/checkout/how-checkout-works); nothing is due
8
- // on a trial's.
9
- // - At each period's end Stripe drafts a `subscription_cycle` invoice for the next period and advances the
10
- // period; a trial's end is the first such renewal, and the subscription is active from then
11
- // (docs.stripe.com/billing/subscriptions/overview#how-payments-work-subscriptions,
12
- // docs.stripe.com/billing/subscriptions/trials).
13
- // - About an hour after, Stripe finalizes the draft and charges the subscription's default payment method,
14
- // else the customer's (docs.stripe.com/invoicing/integration/workflow-transitions#finalized,
15
- // docs.stripe.com/api/subscriptions/object#subscription_object-default_payment_method).
16
- // - A declined renewal leaves the invoice open with its attempt counted and the subscription past_due
17
- // (docs.stripe.com/billing/subscriptions/overview#payment-status); paying the invoice later, through the API
18
- // (docs.stripe.com/api/invoices/pay) or on the customer portal (docs.stripe.com/customer-management), makes it
19
- // active again.
20
- //
21
- // Where the documentation stops and the twin decides: Stripe retries a failed renewal on its Smart Retries
22
- // schedule and may then cancel or mark the subscription unpaid; the twin makes no retry (next_payment_attempt
23
- // is null) and leaves it past_due until the invoice is paid. A paused subscription (pause_collection) is not renewed.
24
- // - One set to cancel at its period's end is canceled when the period ends, with no renewal
25
- // (docs.stripe.com/billing/subscriptions/cancel#cancel-at-end-of-cycle).
26
- import { runAsVendorMove } from '@volter/world-core';
27
- import { addBillingInterval, applyCouponDiscount, declineFor, mintClientSecret, priceAmount, resolveSubscriptionBillingInterval } from "../stripe-twin.js";
28
- import { finalizedFields } from "./invoices.js";
29
- import { mintCharge } from "./payment-intents.js";
30
- import { at_, created, finder } from "./shared.js";
31
- const SUB = 'subscription';
32
- const INV = 'invoice';
33
- const HOUR = 3600;
34
- /** The statuses a subscription renews in. */
35
- const RENEWING = ['trialing', 'active', 'past_due'];
36
- /** A customer's now: its test clock's frozen time when it is on one (docs.stripe.com/billing/testing/test-clocks), the
37
- * World's otherwise. */
38
- export function clockNow(ctx, customer) {
39
- const clock = typeof customer === 'string' ? ctx.get('customer', customer)?.test_clock : undefined;
40
- const frozen = typeof clock === 'string' ? ctx.get('test_helpers.test_clock', clock)?.frozen_time : undefined;
41
- return frozen !== undefined ? Number(frozen) : Number(ctx.now());
42
- }
43
- /** What a subscription's invoices charge: its own default payment method, else its customer's. */
44
- export function payerOf(ctx, sub) {
45
- return typeof sub.default_payment_method === 'string' && sub.default_payment_method ? sub.default_payment_method : customerDefault(ctx, sub);
46
- }
47
- /** The customer's default for invoices, charged when the subscription names none of its own. */
48
- function customerDefault(ctx, sub) {
49
- const customer = typeof sub.customer === 'string' ? ctx.get('customer', sub.customer) : undefined;
50
- const settings = customer?.invoice_settings;
51
- return typeof settings?.default_payment_method === 'string' && settings.default_payment_method ? settings.default_payment_method : undefined;
52
- }
53
- const itemsOf = (sub) => (sub.items?.data) ?? [];
54
- /** An item's quantity as it bills: 1 when none is set, and 0 when 0 is (a quantity of 0 bills nothing). */
55
- export function itemQuantity(it) {
56
- return it.quantity === undefined || it.quantity === null ? 1 : Math.max(0, Math.trunc(Number(it.quantity) || 0));
57
- }
58
- /** The subscription's discounts with a `once` coupon's spent: "When a subscription uses a coupon with `duration=once`, the
59
- * coupon is considered used after the invoice finalizes and is removed from the subscription's `discounts` array"
60
- * (docs.stripe.com/billing/subscriptions/coupons#coupon-duration). */
61
- export function unspentDiscounts(discounts) {
62
- return (discounts ?? []).filter((d) => !(d && typeof d === 'object' && d.coupon?.duration === 'once'));
63
- }
64
- /** The coupon ids an invoice's discounts name. */
65
- const couponsOf = (discounts) => new Set((discounts ?? []).map((d) => {
66
- const c = d && typeof d === 'object' ? d.coupon : undefined;
67
- return typeof c === 'string' ? c : c && typeof c === 'object' ? String(c.id ?? '') : '';
68
- }).filter(Boolean));
69
- /** A subscription whose invoice has just been finalized: the `once` coupon that invoice took is spent, and a once coupon
70
- * it did not take (added after it was drafted) stays for the next (unspentDiscounts). */
71
- export async function spendOnceCoupon(ctx, invoice) {
72
- const subId = typeof invoice.subscription === 'string' ? invoice.subscription : undefined;
73
- const sub = subId ? ctx.get(SUB, subId) : undefined;
74
- if (!sub || !subId)
75
- return;
76
- const all = sub.discounts ?? [];
77
- const kept = keptAfter(all, invoice);
78
- if (kept.length !== all.length)
79
- await ctx.write(SUB, subId, { discounts: kept }, 'subscription.discount_spent');
80
- }
81
- /** A subscription's discounts after `invoice` finalizes: less the `once` coupons it took. */
82
- export function keptAfter(discounts, invoice) {
83
- const taken = couponsOf(invoice.discounts);
84
- return discounts.filter((d) => !(unspentDiscounts([d]).length === 0 && [...couponsOf([d])].some((c) => taken.has(c))));
85
- }
86
- /** A draft invoice for one period of a subscription, its lines the subscription's items and any one-time lines `once`
87
- * gives it (a Checkout session's one-time prices, "on the initial invoice only", docs.stripe.com/api/checkout/sessions/
88
- * create#create_checkout_session-line_items), under the subscription's discount. Answers the invoice id. */
89
- export async function draftSubscriptionInvoice(ctx, sub, o) {
90
- const id = o.id ?? ctx.mint(INV);
91
- const currency = String(sub.currency ?? 'usd');
92
- const lines = itemsOf(sub).map((it, i) => {
93
- const price = it.price && typeof it.price === 'object' ? it.price : ctx.get('price', String(it.price ?? ''));
94
- const quantity = itemQuantity(it);
95
- return {
96
- id: `il_twin_${id}_${i + 1}`, object: 'line_item', type: 'subscription',
97
- // a trial's first invoice bills nothing for the trial period (docs.stripe.com/billing/subscriptions/trials)
98
- amount: o.trial ? 0 : priceAmount(price, quantity), currency, quantity, proration: false,
99
- price: price ?? null, subscription: sub.id, subscription_item: it.id ?? null, invoice_item: null,
100
- period: { start: o.start, end: o.end }, description: o.trial ? `Trial period for ${String(ctx.get('product', String(price?.product ?? ''))?.name ?? 'the plan')}` : null,
101
- };
102
- });
103
- if (o.once?.length)
104
- lines.push(...oneTimeLines(id, sub, o.once, lines.length, o.start, currency));
105
- const subtotal = lines.reduce((s, l) => s + l.amount, 0);
106
- // a discount the subscription still carries applies; a `once` coupon is removed once an invoice finalizes
107
- // (spendOnceCoupon), so it discounts one invoice (docs.stripe.com/billing/subscriptions/coupons#coupon-duration)
108
- const discount = (sub.discounts ?? [])[0];
109
- const coupon = discount && typeof discount === 'object' ? discount.coupon : undefined;
110
- const off = coupon ? applyCouponDiscount(subtotal, coupon) : 0;
111
- const total = Math.max(0, subtotal - off);
112
- await created(ctx, INV, { id, customer: sub.customer, subscription: sub.id }, {
113
- created: o.start, status: 'draft', livemode: false, currency, collection_method: 'charge_automatically',
114
- billing_reason: o.reason, auto_advance: true, attempt_count: 0, attempted: false, next_payment_attempt: null,
115
- amount_due: total, amount_paid: 0, amount_remaining: total, amount_overpaid: 0, amount_paid_off_stripe: 0, amount_shipping: 0,
116
- subtotal, total, starting_balance: 0, post_payment_credit_notes_amount: 0, pre_payment_credit_notes_amount: 0,
117
- // "The invoice that consumed the coupon still shows the applied discount" (docs.stripe.com/billing/subscriptions/coupons)
118
- period_start: o.start, period_end: o.end, default_tax_rates: [], discounts: coupon && discount ? [discount] : [],
119
- lines: { object: 'list', data: lines, has_more: false, total_count: lines.length, url: `/v1/invoices/${id}/lines` },
120
- automatic_tax: { enabled: false, liability: null, status: null },
121
- status_transitions: { finalized_at: null, marked_uncollectible_at: null, paid_at: null, voided_at: null },
122
- issuer: { type: 'self' }, payment_settings: { default_mandate: null, payment_method_options: null, payment_method_types: null },
123
- payment_intent: null, charge: null,
124
- });
125
- return id;
126
- }
127
- /** A Checkout session's one-time line items as lines of its subscription's first invoice, numbered after its `after` lines. */
128
- function oneTimeLines(invoiceId, sub, items, after, at, currency) {
129
- return items.map((it, i) => {
130
- const price = it.price && typeof it.price === 'object' ? it.price : null;
131
- const quantity = itemQuantity(it);
132
- return {
133
- id: `il_twin_${invoiceId}_${after + i + 1}`, object: 'line_item', type: 'subscription',
134
- amount: priceAmount(price ?? undefined, quantity), currency, quantity, proration: false,
135
- price, subscription: sub.id, subscription_item: null, invoice_item: null,
136
- period: { start: at, end: at }, description: typeof it.description === 'string' ? it.description : null,
137
- };
138
- });
139
- }
140
- /** Finalize a subscription's draft invoice at `at` and charge what its subscription pays with. The move is time's (a
141
- * renewal), the customer's (the Checkout page they paid on) or the API's (an update that ends a trial, which names the
142
- * payer, may ask for no attempt, and moves the subscription itself: semantics/subscriptions.ts applyTrialEnd). Answers
143
- * whether it was paid. */
144
- export async function collectSubscriptionInvoice(ctx, invoiceId, at, actor, opts = {}) {
145
- const inv = ctx.get(INV, invoiceId);
146
- const sub = inv && typeof inv.subscription === 'string' ? ctx.get(SUB, inv.subscription) : undefined;
147
- if (!inv || !sub || inv.status !== 'draft')
148
- return false;
149
- const total = Number(inv.total) || 0;
150
- const numbered = { ...finalizedFields(ctx, inv, at), status_transitions: { ...inv.status_transitions, finalized_at: at } };
151
- const op = ctx.call.operation.id;
152
- // nothing due (a trial's first invoice) is paid as it is finalized; finalizing spends a `once` coupon
153
- if (total <= 0) {
154
- if (ctx.legal(INV, 'status', op, 'draft', 'paid', invoiceId, actor))
155
- return false;
156
- await spendOnceCoupon(ctx, inv);
157
- await ctx.write(INV, invoiceId, { ...numbered, status: 'paid', paid: true, auto_advance: false, status_transitions: { ...numbered.status_transitions, paid_at: at } }, 'invoice.paid');
158
- return true;
159
- }
160
- const payer = actor === 'api' ? opts.payer : payerOf(ctx, sub);
161
- // default_incomplete finalizes the invoice without attempting payment (docs.stripe.com/api/subscriptions/update#update_subscription-payment_behavior)
162
- const attempt = opts.attempt !== false;
163
- const decline = payer && attempt ? declineFor(finder(ctx), { payment_method: payer }) : undefined;
164
- const pays = attempt && !!payer && !decline;
165
- if (ctx.legal(INV, 'status', op, 'draft', pays ? 'paid' : 'open', invoiceId, actor))
166
- return false;
167
- await spendOnceCoupon(ctx, inv);
168
- const piId = ctx.mint('payment_intent');
169
- const currency = String(inv.currency ?? 'usd');
170
- const chargeId = pays ? await mintCharge(ctx, piId, { currency, customer: inv.customer, payment_method: payer, invoice: invoiceId }, total) : null;
171
- await created(ctx, 'payment_intent', { id: piId, amount: total, currency, customer: inv.customer, invoice: invoiceId, payment_method: pays ? payer : null }, {
172
- status: pays ? 'succeeded' : 'requires_payment_method', client_secret: mintClientSecret(piId), livemode: false,
173
- capture_method: 'automatic', amount_capturable: 0, amount_received: pays ? total : 0, next_action: null, latest_charge: chargeId,
174
- last_payment_error: decline ? { type: 'card_error', code: decline.code, decline_code: decline.decline_code ?? null, message: decline.message, payment_method: { id: payer } } : null,
175
- automatic_payment_methods: null, payment_method_types: ['card'], payment_method_options: {},
176
- });
177
- await ctx.write(INV, invoiceId, {
178
- ...numbered, status: pays ? 'paid' : 'open', paid: pays, attempt_count: attempt ? 1 : 0, attempted: attempt, payment_intent: piId, charge: chargeId,
179
- amount_paid: pays ? total : 0, amount_remaining: pays ? 0 : total, auto_advance: attempt && !pays, next_payment_attempt: null,
180
- status_transitions: { ...numbered.status_transitions, paid_at: pays ? at : null },
181
- }, pays ? 'invoice.paid' : attempt ? 'invoice.payment_failed' : 'invoice.finalized');
182
- if (actor !== 'api' && !pays && sub.status !== 'past_due' && !ctx.legal(SUB, 'status', op, sub.status, 'past_due', String(sub.id), 'time')) {
183
- await ctx.write(SUB, String(sub.id), { status: 'past_due' }, 'customer.subscription.updated');
184
- }
185
- return pays;
186
- }
187
- /** Pay a subscription's open invoice with `paymentMethod` (the customer on the portal, `external`): the charge on the
188
- * invoice's PaymentIntent, the invoice paid, a past_due subscription active. Answers the decline, if the card is refused. */
189
- export async function payOpenInvoice(ctx, invoiceId, paymentMethod) {
190
- const inv = ctx.get(INV, invoiceId);
191
- if (!inv || inv.status !== 'open')
192
- return { code: 'invoice_not_open', message: 'This invoice is no longer open.' };
193
- const decline = declineFor(finder(ctx), { payment_method: paymentMethod });
194
- if (decline)
195
- return decline;
196
- const op = ctx.call.operation.id;
197
- const refused = ctx.legal(INV, 'status', op, 'open', 'paid', invoiceId, 'external');
198
- if (refused)
199
- return { code: refused.code ?? 'invoice_not_open', message: refused.message };
200
- const total = Number(inv.amount_remaining ?? inv.total) || 0;
201
- const now = Number(ctx.now());
202
- const piId = typeof inv.payment_intent === 'string' ? inv.payment_intent : undefined;
203
- let chargeId = null;
204
- const pi = piId ? ctx.get('payment_intent', piId) : undefined;
205
- if (piId && pi && !ctx.legal('payment_intent', 'status', op, pi.status, 'succeeded', piId, 'external')) {
206
- chargeId = await mintCharge(ctx, piId, { ...pi, payment_method: paymentMethod, invoice: invoiceId }, total);
207
- await ctx.write('payment_intent', piId, { status: 'succeeded', payment_method: paymentMethod, amount_received: total, last_payment_error: null, latest_charge: chargeId }, 'payment_intent.succeeded');
208
- }
209
- await ctx.write(INV, invoiceId, {
210
- status: 'paid', paid: true, amount_paid: total, amount_remaining: 0, charge: chargeId, auto_advance: false,
211
- attempt_count: (Number(inv.attempt_count) || 0) + 1, attempted: true,
212
- status_transitions: { ...inv.status_transitions, paid_at: now },
213
- }, 'invoice.paid');
214
- const sub = typeof inv.subscription === 'string' ? ctx.get(SUB, inv.subscription) : undefined;
215
- if (sub && sub.status === 'past_due' && !ctx.legal(SUB, 'status', op, 'past_due', 'active', String(sub.id), 'external')) {
216
- await ctx.write(SUB, String(sub.id), { status: 'active' }, 'customer.subscription.updated');
217
- }
218
- return undefined;
219
- }
220
- /** Time's moves on subscriptions, caught up to each customer's clock in the order they fell due, each made at the
221
- * moment it was due: a period that ended renews (a trial's end among them) or, set to cancel, cancels; a renewal
222
- * drafted an hour or more ago is finalized and charged. */
223
- export async function advanceBilling(ctx, only) {
224
- // the billing clock is the vendor's own move, wherever a handler reaches it: never the request's caller's
225
- return runAsVendorMove(() => advanceBillingDue(ctx, only));
226
- }
227
- async function advanceBillingDue(ctx, only) {
228
- const at = at_(ctx);
229
- for (let guard = 0; guard < 10_000 && (await billingStep(ctx, at, only)); guard++)
230
- ;
231
- }
232
- /** The earliest move that has come due, made at its moment; false when none has. */
233
- async function billingStep(ctx, at, only) {
234
- // the earliest move that has come due, of any subscription
235
- let next;
236
- for (const sub of ctx.rows(SUB)) {
237
- if (only && !only(sub))
238
- continue;
239
- if (!RENEWING.includes(String(sub.status)) || typeof sub.current_period_end !== 'number' || sub.pause_collection)
240
- continue;
241
- if (sub.current_period_end <= clockNow(ctx, sub.customer) && (!next || sub.current_period_end < next.t))
242
- next = { t: sub.current_period_end, kind: 'period', id: String(sub.id) };
243
- }
244
- for (const inv of ctx.rows(INV)) {
245
- if (inv.status !== 'draft' || inv.billing_reason !== 'subscription_cycle' || inv.auto_advance !== true)
246
- continue;
247
- const sub = typeof inv.subscription === 'string' ? ctx.get(SUB, inv.subscription) : undefined;
248
- if (!sub || (only && !only(sub)))
249
- continue;
250
- const t = Number(inv.created) + HOUR;
251
- if (t <= clockNow(ctx, sub.customer) && (!next || t < next.t))
252
- next = { t, kind: 'collect', id: String(inv.id) };
253
- }
254
- if (!next)
255
- return false;
256
- const c = await at(next.t);
257
- if (next.kind === 'collect') {
258
- await collectSubscriptionInvoice(c, next.id, next.t, 'time');
259
- return true;
260
- }
261
- const id = next.id;
262
- const sub = c.get(SUB, id);
263
- const op = c.call.operation.id;
264
- // one set to cancel at its period's end is canceled then, with no renewal
265
- // (docs.stripe.com/billing/subscriptions/cancel#cancel-at-end-of-cycle)
266
- if (sub.cancel_at_period_end === true) {
267
- if (c.legal(SUB, 'status', op, sub.status, 'canceled', id, 'time'))
268
- return false;
269
- await c.write(SUB, id, { status: 'canceled', ended_at: next.t, canceled_at: sub.canceled_at ?? next.t }, 'customer.subscription.deleted');
270
- return true;
271
- }
272
- const start = next.t;
273
- const { interval, interval_count } = resolveSubscriptionBillingInterval(itemsOf(sub), finder(c));
274
- const end = addBillingInterval(start, interval, interval_count);
275
- const trialEnds = sub.status === 'trialing';
276
- if (trialEnds && c.legal(SUB, 'status', op, 'trialing', 'active', id, 'time'))
277
- return false;
278
- const invoiceId = await draftSubscriptionInvoice(c, sub, { start, end, reason: 'subscription_cycle' });
279
- await c.write(SUB, id, { current_period_start: start, current_period_end: end, latest_invoice: invoiceId, ...(trialEnds ? { status: 'active' } : {}) }, 'customer.subscription.updated');
280
- return true;
281
- }
@@ -1,2 +0,0 @@
1
- import type { Semantics } from '@volter/world-core';
2
- export declare const setupIntents: Record<string, Semantics>;
@@ -1,84 +0,0 @@
1
- import { asBool, microdepositsNextAction, mintClientSecret, requiresMicrodeposits, verifyMicrodeposits } from "../stripe-twin.js";
2
- import { mintMandate } from "./after-payment.js";
3
- import { attachable, attachPaymentMethod, methodFromData, microdepositsAsked } from "./payment-methods.js";
4
- import { at, confirmOnly, created, fail, mergeUpdate, send } from "./shared.js";
5
- const SI = 'setup_intent';
6
- /** The intent the path names, and the machine's refusal when this operation may not move it. */
7
- function load(ctx, operationId) {
8
- const id = at(ctx, 'intent');
9
- const si = ctx.get(SI, id);
10
- if (!si)
11
- return { answer: fail(ctx, `No such setup_intent: '${id}'`, 404, 'resource_missing') };
12
- const refused = ctx.legal(SI, 'status', operationId, si.status, undefined, id);
13
- return refused ? { answer: ctx.refuse(refused) } : { si };
14
- }
15
- const create = async (ctx) => {
16
- // mandate_data and return_url each "can only be used with `confirm=true`" (the served spec; shared.ts confirmOnly)
17
- const unconfirmed = confirmOnly(ctx, ['mandate_data', 'return_url'], asBool(ctx.params.confirm));
18
- if (unconfirmed)
19
- return unconfirmed;
20
- // the id is minted first so the client secret can carry it: Stripe.js parses the id back out
21
- const id = typeof ctx.params.id === 'string' && ctx.params.id ? ctx.params.id : ctx.mint(SI);
22
- // it waits for a payment method until it has one, then for its confirmation (manifest.ts)
23
- const hasMethod = typeof ctx.params.payment_method === 'string' && ctx.params.payment_method !== '';
24
- if (hasMethod)
25
- ctx.legal(SI, 'status', 'PostSetupIntents', 'requires_payment_method', 'requires_confirmation', id);
26
- return ctx.reply(
27
- // allowed_payment_method_types in the served version names the methods (docs.stripe.com/api/setup_intents/create)
28
- await created(ctx, SI, { ...ctx.params, ...(Array.isArray(ctx.params.allowed_payment_method_types) ? { payment_method_types: ctx.params.allowed_payment_method_types.map(String) } : {}), id }, {
29
- status: hasMethod ? 'requires_confirmation' : 'requires_payment_method', usage: 'off_session', client_secret: mintClientSecret(id), payment_method_types: ['card'],
30
- next_action: null, latest_attempt: null, last_setup_error: null, livemode: false,
31
- }));
32
- };
33
- // a bank account that needs micro-deposit verification waits in requires_action; anything else succeeds. The confirm's
34
- // payment_method_data and mandate_data are instructions, not fields of the SetupIntent.
35
- const confirm = async (ctx) => {
36
- const loaded = load(ctx, 'PostSetupIntentsIntentConfirm');
37
- if ('answer' in loaded)
38
- return loaded.answer;
39
- const si = loaded.si;
40
- const id = String(si.id);
41
- const { payment_method_data: data, mandate_data: _mandate, ...fields } = ctx.params;
42
- const made = await methodFromData(ctx, data);
43
- const pm = made ?? (typeof ctx.params.payment_method === 'string' ? ctx.params.payment_method : typeof si.payment_method === 'string' ? si.payment_method : undefined);
44
- if (si.status !== 'requires_action' && (requiresMicrodeposits(ctx.params, si) || microdepositsAsked(ctx, ctx.params, si, pm))) {
45
- return ctx.reply(await ctx.write(SI, id, mergeUpdate(ctx, SI, id, { ...fields, ...(pm ? { payment_method: pm } : {}), status: 'requires_action', next_action: microdepositsNextAction() }), 'setup_intent.requires_action'));
46
- }
47
- // a setup for a customer saves the method to them (docs.stripe.com/payments/save-and-reuse): its payment method is attached
48
- const customer = typeof si.customer === 'string' ? si.customer : undefined;
49
- const saved = pm && customer && attachable(ctx, pm) && ctx.get('payment_method', pm)?.customer !== customer ? String((await attachPaymentMethod(ctx, pm, customer)).id) : pm;
50
- return ctx.reply(await ctx.write(SI, id, mergeUpdate(ctx, SI, id, { ...fields, ...(saved ? { payment_method: saved } : {}), status: 'succeeded' }), 'setup_intent.confirm'));
51
- };
52
- const cancel = async (ctx) => {
53
- const loaded = load(ctx, 'PostSetupIntentsIntentCancel');
54
- if ('answer' in loaded)
55
- return loaded.answer;
56
- const cancellation_reason = typeof ctx.params.cancellation_reason === 'string' ? ctx.params.cancellation_reason : 'abandoned';
57
- return ctx.reply(await ctx.write(SI, String(loaded.si.id), { status: 'canceled', cancellation_reason }, 'setup_intent.canceled'));
58
- };
59
- const verify = async (ctx) => {
60
- const id = at(ctx, 'intent');
61
- const si = ctx.get(SI, id);
62
- if (!si)
63
- return fail(ctx, `No such setup_intent: '${id}'`, 404, 'resource_missing');
64
- // the deposit amounts are checked before the intent's state, as Stripe does
65
- const wrong = verifyMicrodeposits(ctx.params, si);
66
- if (wrong)
67
- return send(ctx, wrong);
68
- const refused = ctx.legal(SI, 'status', 'PostSetupIntentsIntentVerifyMicrodeposits', si.status, undefined, id);
69
- if (refused)
70
- return ctx.refuse(refused);
71
- const mandate = await mintMandate(ctx, si.payment_method, 'multi_use');
72
- // verified, the bank account is saved to the setup's customer, as a confirmed setup's method is
73
- const pm = typeof si.payment_method === 'string' ? si.payment_method : undefined;
74
- const customer = typeof si.customer === 'string' ? si.customer : undefined;
75
- if (pm && customer && attachable(ctx, pm) && ctx.get('payment_method', pm)?.customer !== customer)
76
- await attachPaymentMethod(ctx, pm, customer);
77
- return ctx.reply(await ctx.write(SI, id, { status: 'succeeded', next_action: null, last_setup_error: null, mandate }, 'setup_intent.succeeded'));
78
- };
79
- export const setupIntents = {
80
- PostSetupIntents: create,
81
- PostSetupIntentsIntentConfirm: confirm,
82
- PostSetupIntentsIntentCancel: cancel,
83
- PostSetupIntentsIntentVerifyMicrodeposits: verify,
84
- };
@@ -1,2 +0,0 @@
1
- import type { Semantics } from '@volter/world-core';
2
- export declare const subscriptionSchedules: Record<string, Semantics>;
@@ -1,119 +0,0 @@
1
- import { addBillingInterval, buildSubscriptionItemsList } from "../stripe-twin.js";
2
- import { at, created, fail, finder } from "./shared.js";
3
- import { storeItems } from "./subscriptions.js";
4
- const SS = 'subscription_schedule';
5
- const scheduleMissing = (ctx, id) => fail(ctx, `No such subscription_schedule: '${id}'`, 404, 'resource_missing');
6
- /** A schedule's phases as Stripe answers them (the served spec's subscription_schedule_phase_configuration): each
7
- * starts where the last ended (the first at the schedule's start_date, "now" or a timestamp), and ends at its
8
- * end_date or after its duration ("duration: interval, interval_count", the served spec's phases[] parameter) on the
9
- * calendar; its currency is its first price's, each item carries its price, quantity and (empty) discounts. Where the
10
- * documentation stops and the twin decides: a phase with neither lasts one interval of its first price. */
11
- function phasesOf(ctx, given, start) {
12
- let cursor = start;
13
- return given.map((p) => {
14
- const items = (Array.isArray(p.items) ? p.items : []).map((it) => ({ price: it.price ?? null, quantity: Math.max(1, Math.trunc(Number(it.quantity) || 1)), discounts: [], metadata: {}, tax_rates: [], billing_thresholds: null }));
15
- const price = typeof items[0]?.price === 'string' ? ctx.get('price', items[0].price) : undefined;
16
- const recurring = price?.recurring ?? {};
17
- const d = p.duration && typeof p.duration === 'object' ? p.duration : undefined;
18
- const startDate = cursor;
19
- const end = p.end_date !== undefined && p.end_date !== 'now' ? Number(p.end_date)
20
- : d ? addBillingInterval(startDate, String(d.interval), Math.max(1, Number(d.interval_count) || 1))
21
- : addBillingInterval(startDate, String(recurring.interval ?? 'month'), Math.max(1, Number(recurring.interval_count) || 1));
22
- cursor = end;
23
- return {
24
- add_invoice_items: [], application_fee_percent: null, automatic_tax: { enabled: false, liability: null, disabled_reason: null }, billing_cycle_anchor: null,
25
- billing_thresholds: null, collection_method: null, currency: String(price?.currency ?? 'usd'), default_payment_method: null, default_tax_rates: [],
26
- description: null, discounts: [], end_date: end, invoice_settings: null, items, metadata: p.metadata && typeof p.metadata === 'object' ? p.metadata : {},
27
- on_behalf_of: null, proration_behavior: typeof p.proration_behavior === 'string' ? p.proration_behavior : 'create_prorations', start_date: startDate,
28
- transfer_data: null, trial_end: null,
29
- };
30
- });
31
- }
32
- // a schedule starts from a customer or from an existing subscription
33
- const create = async (ctx) => {
34
- const params = ctx.params;
35
- const customer = typeof params.customer === 'string' ? params.customer : '';
36
- const fromSub = typeof params.from_subscription === 'string' ? params.from_subscription : '';
37
- if (!customer && !fromSub)
38
- return fail(ctx, 'Missing required param: customer (or from_subscription).', 400, 'parameter_missing');
39
- if (customer && !ctx.get('customer', customer))
40
- return fail(ctx, `No such customer: '${customer}'`, 404, 'resource_missing');
41
- if (fromSub && !ctx.get('subscription', fromSub))
42
- return fail(ctx, `No such subscription: '${fromSub}'`, 404, 'resource_missing');
43
- // start_date is an instruction ("now" or when), not a field of the schedule
44
- const start = params.start_date !== undefined && params.start_date !== 'now' ? Number(params.start_date) : Number(ctx.now());
45
- const phases = phasesOf(ctx, Array.isArray(params.phases) ? params.phases : [], start);
46
- const { phases: _p, start_date: _s, default_settings: givenDefaults, ...rest } = params;
47
- const defaults = givenDefaults && typeof givenDefaults === 'object' ? givenDefaults : {};
48
- const schedId = ctx.mint(SS);
49
- // a schedule for a customer whose first phase starts now starts its subscription at once, on that phase's items
50
- // (docs.stripe.com/billing/subscriptions/subscription-schedules#managing)
51
- let subscription = fromSub || null;
52
- if (!fromSub && phases.length) {
53
- const now = Number(ctx.now());
54
- const subId = ctx.mint('subscription');
55
- const items = buildSubscriptionItemsList(phases[0].items, subId, now, finder(ctx));
56
- await created(ctx, 'subscription', { customer, id: subId }, {
57
- status: 'active', livemode: false, currency: 'usd', collection_method: String(params.default_settings?.collection_method ?? 'charge_automatically'),
58
- cancel_at_period_end: false, start_date: now, billing_cycle_anchor: now, metadata: {}, discounts: [], billing_schedules: [],
59
- trial_start: null, trial_end: null, current_period_start: now, current_period_end: phases[0].end_date, items, schedule: schedId,
60
- automatic_tax: { enabled: false, liability: null }, billing_mode: { type: 'classic' }, invoice_settings: { issuer: { type: 'self' } },
61
- });
62
- await storeItems(ctx, subId, items.data ?? []);
63
- subscription = subId;
64
- }
65
- return ctx.reply(await created(ctx, SS, { ...rest, id: schedId }, {
66
- status: 'active', livemode: false, phases, current_phase: phases.length ? { start_date: phases[0].start_date, end_date: phases[0].end_date } : null,
67
- subscription, released_subscription: null, released_at: null,
68
- canceled_at: null, completed_at: null, end_behavior: params.end_behavior ?? 'release',
69
- renewal_interval: null, metadata: {}, billing_mode: { type: 'classic' },
70
- // "billing_cycle_anchor: Possible values are phase_start or automatic" and invoice_settings are required (the
71
- // served spec's default settings); the rest answer what the request set, else null
72
- default_settings: {
73
- application_fee_percent: defaults.application_fee_percent ?? null, automatic_tax: { enabled: false, liability: null, disabled_reason: null },
74
- billing_cycle_anchor: typeof defaults.billing_cycle_anchor === 'string' ? defaults.billing_cycle_anchor : 'automatic', billing_thresholds: null,
75
- collection_method: typeof defaults.collection_method === 'string' ? defaults.collection_method : 'charge_automatically', default_payment_method: defaults.default_payment_method ?? null,
76
- description: defaults.description ?? null, invoice_settings: { account_tax_ids: null, days_until_due: null, issuer: { type: 'self' } }, on_behalf_of: null, transfer_data: null,
77
- },
78
- // a schedule made from a subscription is its customer's
79
- customer: customer || String(ctx.get('subscription', fromSub)?.customer ?? ''),
80
- }));
81
- };
82
- function end(kind) {
83
- return async (ctx) => {
84
- const id = at(ctx, 'schedule');
85
- const sched = ctx.get(SS, id);
86
- if (!sched)
87
- return scheduleMissing(ctx, id);
88
- const refused = ctx.legal(SS, 'status', kind === 'cancel' ? 'PostSubscriptionSchedulesScheduleCancel' : 'PostSubscriptionSchedulesScheduleRelease', sched.status, undefined, id);
89
- if (refused)
90
- return ctx.refuse(refused);
91
- const now = ctx.now();
92
- const subId = typeof sched.subscription === 'string' ? sched.subscription : undefined;
93
- const sub = subId ? ctx.get('subscription', subId) : undefined;
94
- // "Cancels a subscription schedule and its associated subscription immediately (if the subscription schedule has an
95
- // active subscription)" (docs.stripe.com/api/subscription_schedules/cancel); releasing "will remove its subscription
96
- // property and set the subscription's ID to the released_subscription property", leaving the subscription in place
97
- // (docs.stripe.com/api/subscription_schedules/release)
98
- if (kind === 'cancel' && subId && sub && sub.status !== 'canceled') {
99
- ctx.legal('subscription', 'status', 'PostSubscriptionSchedulesScheduleCancel', String(sub.status), 'canceled', subId);
100
- await ctx.write('subscription', subId, { status: 'canceled', canceled_at: now, ended_at: now }, 'subscription.cancel');
101
- }
102
- if (kind === 'release' && subId && sub)
103
- await ctx.write('subscription', subId, { schedule: null }, 'subscription.update');
104
- const fields = kind === 'cancel'
105
- ? { status: 'canceled', canceled_at: now, current_phase: null }
106
- : { status: 'released', released_at: now, released_subscription: subId ?? null, subscription: null, current_phase: null };
107
- return ctx.reply(await ctx.write(SS, id, fields, `subscription_schedule.${kind}`));
108
- };
109
- }
110
- const retrieve = async (ctx) => {
111
- const s = ctx.get(SS, at(ctx, 'schedule'));
112
- return s ? ctx.reply(s) : scheduleMissing(ctx, at(ctx, 'schedule'));
113
- };
114
- export const subscriptionSchedules = {
115
- PostSubscriptionSchedules: create,
116
- PostSubscriptionSchedulesScheduleCancel: end('cancel'),
117
- PostSubscriptionSchedulesScheduleRelease: end('release'),
118
- GetSubscriptionSchedulesSchedule: retrieve,
119
- };
@@ -1,2 +0,0 @@
1
- import type { Semantics } from '@volter/world-core';
2
- export declare const tax: Record<string, Semantics>;