@volter/twin-stripe 2.0.37 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. package/README.md +82 -207
  2. package/dist/generated/pack-facts.json +94 -0
  3. package/dist/spec/SOURCE.md +14 -0
  4. package/dist/spec/fixtures3.json.gz +0 -0
  5. package/dist/spec/openapi.json.gz +0 -0
  6. package/dist/spec/patches.json +34 -0
  7. package/dist/spec/sources.json +378 -0
  8. package/dist/src/cli.js +12 -30
  9. package/dist/src/engine/after-payment.d.ts +9 -0
  10. package/dist/src/engine/after-payment.js +28 -0
  11. package/dist/src/engine/apps-secrets.d.ts +1 -0
  12. package/dist/src/engine/apps-secrets.js +3 -0
  13. package/dist/src/engine/balance.d.ts +5 -0
  14. package/dist/src/engine/balance.js +15 -0
  15. package/dist/src/engine/billing.d.ts +5 -0
  16. package/dist/src/engine/billing.js +6 -0
  17. package/dist/src/engine/charges.d.ts +6 -0
  18. package/dist/src/engine/charges.js +13 -0
  19. package/dist/src/engine/checkout.d.ts +24 -0
  20. package/dist/src/engine/checkout.js +30 -0
  21. package/dist/src/engine/common.d.ts +19 -0
  22. package/dist/src/engine/common.js +32 -0
  23. package/dist/src/{screens → engine}/connect-settings.d.ts +1 -7
  24. package/dist/src/engine/connect-settings.js +26 -0
  25. package/dist/src/engine/connect.d.ts +66 -0
  26. package/dist/src/engine/connect.js +189 -0
  27. package/dist/src/engine/coupons.d.ts +0 -0
  28. package/dist/src/engine/coupons.js +5 -0
  29. package/dist/src/engine/credit-notes.d.ts +1 -0
  30. package/dist/src/engine/credit-notes.js +5 -0
  31. package/dist/src/engine/customers.d.ts +12 -0
  32. package/dist/src/engine/customers.js +30 -0
  33. package/dist/src/engine/display.d.ts +14 -0
  34. package/dist/src/engine/display.js +16 -0
  35. package/dist/src/engine/disputes.d.ts +0 -0
  36. package/dist/src/engine/disputes.js +9 -0
  37. package/dist/src/engine/entitlements.d.ts +1 -0
  38. package/dist/src/engine/entitlements.js +4 -0
  39. package/dist/src/engine/ephemeral-keys.d.ts +0 -0
  40. package/dist/src/engine/ephemeral-keys.js +4 -0
  41. package/dist/src/engine/files.d.ts +18 -0
  42. package/dist/src/engine/files.js +33 -0
  43. package/dist/src/engine/front.d.ts +5 -0
  44. package/dist/src/engine/front.js +25 -0
  45. package/dist/src/engine/invoices.d.ts +24 -0
  46. package/dist/src/engine/invoices.js +57 -0
  47. package/dist/src/engine/issuing.d.ts +35 -0
  48. package/dist/src/engine/issuing.js +45 -0
  49. package/dist/src/engine/ledger.d.ts +9 -0
  50. package/dist/src/engine/ledger.js +9 -0
  51. package/dist/src/engine/oauth.d.ts +4 -0
  52. package/dist/src/engine/oauth.js +25 -0
  53. package/dist/src/engine/onboarding.d.ts +13 -0
  54. package/dist/src/engine/onboarding.js +42 -0
  55. package/dist/src/{stripe-params.d.ts → engine/params.d.ts} +20 -3
  56. package/dist/src/{stripe-params.js → engine/params.js} +7 -60
  57. package/dist/src/engine/payment-intents.d.ts +10 -0
  58. package/dist/src/engine/payment-intents.js +27 -0
  59. package/dist/src/engine/payment-links.d.ts +1 -0
  60. package/dist/src/engine/payment-links.js +5 -0
  61. package/dist/src/engine/payment-methods.d.ts +16 -0
  62. package/dist/src/engine/payment-methods.js +22 -0
  63. package/dist/src/engine/plans.d.ts +6 -0
  64. package/dist/src/engine/plans.js +26 -0
  65. package/dist/src/engine/platform.d.ts +39 -0
  66. package/dist/src/engine/platform.js +34 -0
  67. package/dist/src/engine/products.d.ts +0 -0
  68. package/dist/src/engine/products.js +4 -0
  69. package/dist/src/engine/radar.d.ts +2 -0
  70. package/dist/src/engine/radar.js +5 -0
  71. package/dist/src/engine/refunds.d.ts +1 -0
  72. package/dist/src/engine/refunds.js +28 -0
  73. package/dist/src/engine/renewals.d.ts +36 -0
  74. package/dist/src/engine/renewals.js +65 -0
  75. package/dist/src/engine/setup-intents.d.ts +1 -0
  76. package/dist/src/engine/setup-intents.js +4 -0
  77. package/dist/src/{stripe-twin.d.ts → engine/stripe.d.ts} +11 -39
  78. package/dist/src/{stripe-twin.js → engine/stripe.js} +25 -310
  79. package/dist/src/engine/subscription-schedules.d.ts +3 -0
  80. package/dist/src/engine/subscription-schedules.js +1 -0
  81. package/dist/src/engine/subscriptions.d.ts +12 -0
  82. package/dist/src/engine/subscriptions.js +31 -0
  83. package/dist/src/engine/tax.d.ts +7 -0
  84. package/dist/src/engine/tax.js +28 -0
  85. package/dist/src/engine/terminal.d.ts +4 -0
  86. package/dist/src/engine/terminal.js +20 -0
  87. package/dist/src/engine/test-clocks.d.ts +5 -0
  88. package/dist/src/engine/test-clocks.js +9 -0
  89. package/dist/src/engine/tokens.d.ts +7 -0
  90. package/dist/src/engine/tokens.js +20 -0
  91. package/dist/src/engine/transfers.d.ts +2 -0
  92. package/dist/src/engine/transfers.js +1 -0
  93. package/dist/src/engine/treasury.d.ts +23 -0
  94. package/dist/src/engine/treasury.js +45 -0
  95. package/dist/src/{stripe-version.js → engine/version.js} +4 -3
  96. package/dist/src/engine/webhook-endpoints.d.ts +1 -0
  97. package/dist/src/engine/webhook-endpoints.js +12 -0
  98. package/dist/src/engine/webhooks.d.ts +31 -0
  99. package/dist/src/engine/webhooks.js +68 -0
  100. package/dist/src/fetch.d.ts +2 -0
  101. package/dist/src/fetch.js +26 -0
  102. package/dist/src/generated/surface.gen.json +1 -1
  103. package/dist/src/generated/ui.gen.json +1 -1
  104. package/dist/src/index.d.ts +5 -14
  105. package/dist/src/index.js +8 -75
  106. package/dist/src/manifest.js +232 -758
  107. package/dist/src/screens/billing-portal.d.ts +3 -0
  108. package/dist/src/screens/{portal.js → billing-portal.js} +28 -54
  109. package/dist/src/screens/checkout.d.ts +2 -31
  110. package/dist/src/screens/checkout.js +32 -121
  111. package/dist/src/screens/connect-oauth.d.ts +3 -27
  112. package/dist/src/screens/connect-oauth.js +51 -132
  113. package/dist/src/screens/connect-onboarding.d.ts +3 -0
  114. package/dist/src/screens/{onboarding.js → connect-onboarding.js} +36 -102
  115. package/dist/src/screens/dashboard.d.ts +3 -0
  116. package/dist/src/screens/dashboard.js +117 -0
  117. package/dist/src/screens/shared.d.ts +27 -0
  118. package/dist/src/screens/shared.js +87 -0
  119. package/dist/src/screens/stripe-js.d.ts +3 -0
  120. package/dist/src/screens/stripe-js.js +135 -0
  121. package/dist/src/semantics/account_links.d.ts +2 -0
  122. package/dist/src/semantics/account_links.js +22 -0
  123. package/dist/src/semantics/accounts.d.ts +4 -0
  124. package/dist/src/semantics/accounts.js +38 -0
  125. package/dist/src/semantics/apps.d.ts +4 -0
  126. package/dist/src/semantics/{apps-secrets.js → apps.js} +14 -26
  127. package/dist/src/semantics/around.d.ts +2 -0
  128. package/dist/src/semantics/around.js +16 -0
  129. package/dist/src/semantics/balance.d.ts +2 -11
  130. package/dist/src/semantics/balance.js +3 -194
  131. package/dist/src/semantics/balance_transactions.d.ts +2 -0
  132. package/dist/src/semantics/balance_transactions.js +15 -0
  133. package/dist/src/semantics/billing_portal.d.ts +5 -0
  134. package/dist/src/semantics/billing_portal.js +42 -0
  135. package/dist/src/semantics/charges.d.ts +3 -28
  136. package/dist/src/semantics/charges.js +5 -202
  137. package/dist/src/semantics/checkout.d.ts +3 -20
  138. package/dist/src/semantics/checkout.js +8 -261
  139. package/dist/src/semantics/clock.d.ts +2 -0
  140. package/dist/src/semantics/clock.js +21 -0
  141. package/dist/src/semantics/coupons.d.ts +2 -6
  142. package/dist/src/semantics/coupons.js +2 -60
  143. package/dist/src/semantics/customers.d.ts +6 -6
  144. package/dist/src/semantics/customers.js +27 -387
  145. package/dist/src/semantics/disputes.d.ts +2 -2
  146. package/dist/src/semantics/disputes.js +3 -49
  147. package/dist/src/semantics/doors.d.ts +23 -0
  148. package/dist/src/semantics/doors.js +73 -0
  149. package/dist/src/semantics/entitlements.d.ts +2 -2
  150. package/dist/src/semantics/entitlements.js +5 -50
  151. package/dist/src/semantics/events.d.ts +12 -0
  152. package/dist/src/semantics/events.js +36 -0
  153. package/dist/src/semantics/index.d.ts +2 -0
  154. package/dist/src/semantics/index.js +107 -0
  155. package/dist/src/semantics/invoice_payments.d.ts +2 -0
  156. package/dist/src/semantics/invoice_payments.js +12 -0
  157. package/dist/src/semantics/invoiceitems.d.ts +3 -0
  158. package/dist/src/semantics/invoiceitems.js +59 -0
  159. package/dist/src/semantics/invoices.d.ts +16 -18
  160. package/dist/src/semantics/invoices.js +118 -444
  161. package/dist/src/semantics/payment_intents.d.ts +4 -0
  162. package/dist/src/semantics/payment_intents.js +79 -0
  163. package/dist/src/semantics/payment_methods.d.ts +5 -0
  164. package/dist/src/semantics/payment_methods.js +39 -0
  165. package/dist/src/semantics/payouts.d.ts +2 -0
  166. package/dist/src/semantics/payouts.js +21 -0
  167. package/dist/src/semantics/prices.d.ts +4 -0
  168. package/dist/src/semantics/prices.js +37 -0
  169. package/dist/src/semantics/products.d.ts +6 -2
  170. package/dist/src/semantics/products.js +15 -130
  171. package/dist/src/semantics/promotion_codes.d.ts +3 -0
  172. package/dist/src/semantics/promotion_codes.js +35 -0
  173. package/dist/src/semantics/radar.d.ts +2 -2
  174. package/dist/src/semantics/radar.js +5 -74
  175. package/dist/src/semantics/refunds.d.ts +3 -9
  176. package/dist/src/semantics/refunds.js +6 -192
  177. package/dist/src/semantics/setup_intents.d.ts +3 -0
  178. package/dist/src/semantics/{setup-intents.js → setup_intents.js} +10 -53
  179. package/dist/src/semantics/shared.d.ts +822 -47
  180. package/dist/src/semantics/shared.js +3044 -78
  181. package/dist/src/semantics/states.d.ts +531 -0
  182. package/dist/src/semantics/states.js +852 -0
  183. package/dist/src/semantics/subscription_items.d.ts +5 -0
  184. package/dist/src/semantics/subscription_items.js +55 -0
  185. package/dist/src/semantics/subscription_schedules.d.ts +4 -0
  186. package/dist/src/semantics/subscription_schedules.js +60 -0
  187. package/dist/src/semantics/subscriptions.d.ts +7 -11
  188. package/dist/src/semantics/subscriptions.js +44 -415
  189. package/dist/src/semantics/test_helpers.d.ts +6 -0
  190. package/dist/src/semantics/{test-clocks.js → test_helpers.js} +14 -40
  191. package/dist/src/semantics/transfers.d.ts +2 -2
  192. package/dist/src/semantics/transfers.js +6 -101
  193. package/dist/src/server.d.ts +7 -0
  194. package/dist/src/server.js +7 -0
  195. package/generated/pack-facts.json +94 -0
  196. package/package.json +10 -20
  197. package/spec/SOURCE.md +14 -0
  198. package/spec/fixtures3.json.gz +0 -0
  199. package/spec/openapi.json.gz +0 -0
  200. package/spec/patches.json +34 -0
  201. package/spec/sources.json +378 -0
  202. package/src/cli.ts +12 -26
  203. package/src/engine/after-payment.ts +31 -0
  204. package/src/engine/apps-secrets.ts +4 -0
  205. package/src/engine/balance.ts +33 -0
  206. package/src/engine/billing.ts +16 -0
  207. package/src/engine/charges.ts +19 -0
  208. package/src/engine/checkout.ts +40 -0
  209. package/src/engine/common.ts +47 -0
  210. package/src/engine/connect-settings.ts +23 -0
  211. package/src/engine/connect.ts +184 -0
  212. package/src/engine/coupons.ts +5 -0
  213. package/src/engine/credit-notes.ts +6 -0
  214. package/src/engine/customers.ts +35 -0
  215. package/src/engine/display.ts +19 -0
  216. package/src/engine/disputes.ts +9 -0
  217. package/src/engine/entitlements.ts +5 -0
  218. package/src/engine/ephemeral-keys.ts +3 -0
  219. package/src/engine/files.ts +41 -0
  220. package/src/engine/front.ts +31 -0
  221. package/src/engine/invoices.ts +71 -0
  222. package/src/engine/issuing.ts +61 -0
  223. package/src/engine/ledger.ts +50 -0
  224. package/src/engine/oauth.ts +19 -0
  225. package/src/engine/onboarding.ts +54 -0
  226. package/src/{stripe-params.ts → engine/params.ts} +8 -56
  227. package/src/engine/payment-intents.ts +33 -0
  228. package/src/engine/payment-links.ts +6 -0
  229. package/src/engine/payment-methods.ts +25 -0
  230. package/src/engine/plans.ts +42 -0
  231. package/src/engine/platform.ts +47 -0
  232. package/src/engine/products.ts +3 -0
  233. package/src/engine/radar.ts +6 -0
  234. package/src/engine/refunds.ts +29 -0
  235. package/src/engine/renewals.ts +73 -0
  236. package/src/engine/setup-intents.ts +5 -0
  237. package/src/{stripe-twin.ts → engine/stripe.ts} +28 -323
  238. package/src/engine/subscription-schedules.ts +10 -0
  239. package/src/engine/subscriptions.ts +40 -0
  240. package/src/engine/tax.ts +39 -0
  241. package/src/engine/terminal.ts +23 -0
  242. package/src/engine/test-clocks.ts +11 -0
  243. package/src/engine/tokens.ts +22 -0
  244. package/src/engine/transfers.ts +23 -0
  245. package/src/engine/treasury.ts +47 -0
  246. package/src/{stripe-version.ts → engine/version.ts} +4 -3
  247. package/src/engine/webhook-endpoints.ts +14 -0
  248. package/src/engine/webhooks.ts +72 -0
  249. package/src/fetch.ts +27 -0
  250. package/src/generated/surface.gen.json +1 -1
  251. package/src/generated/ui.gen.json +1 -1
  252. package/src/index.ts +8 -116
  253. package/src/manifest.ts +234 -786
  254. package/src/screens/{portal.tsx → billing-portal.tsx} +32 -37
  255. package/src/screens/checkout.tsx +33 -95
  256. package/src/screens/connect-oauth.tsx +64 -88
  257. package/src/screens/{onboarding.tsx → connect-onboarding.tsx} +38 -82
  258. package/src/screens/dashboard.tsx +198 -0
  259. package/src/screens/shared.tsx +84 -0
  260. package/src/screens/stripe-js.ts +170 -0
  261. package/src/semantics/account_links.ts +21 -0
  262. package/src/semantics/accounts.ts +43 -0
  263. package/src/semantics/{apps-secrets.ts → apps.ts} +17 -32
  264. package/src/semantics/around.ts +20 -0
  265. package/src/semantics/balance.ts +6 -207
  266. package/src/semantics/balance_transactions.ts +20 -0
  267. package/src/semantics/billing_portal.ts +51 -0
  268. package/src/semantics/charges.ts +12 -211
  269. package/src/semantics/checkout.ts +13 -268
  270. package/src/semantics/clock.ts +26 -0
  271. package/src/semantics/coupons.ts +5 -67
  272. package/src/semantics/customers.ts +29 -392
  273. package/src/semantics/disputes.ts +9 -59
  274. package/src/semantics/doors.ts +80 -0
  275. package/src/semantics/entitlements.ts +9 -56
  276. package/src/semantics/events.ts +44 -0
  277. package/src/semantics/index.ts +111 -0
  278. package/src/semantics/invoice_payments.ts +18 -0
  279. package/src/semantics/invoiceitems.ts +59 -0
  280. package/src/semantics/invoices.ts +109 -443
  281. package/src/semantics/payment_intents.ts +83 -0
  282. package/src/semantics/payment_methods.ts +43 -0
  283. package/src/semantics/payouts.ts +23 -0
  284. package/src/semantics/prices.ts +42 -0
  285. package/src/semantics/products.ts +18 -142
  286. package/src/semantics/promotion_codes.ts +39 -0
  287. package/src/semantics/radar.ts +8 -77
  288. package/src/semantics/refunds.ts +9 -212
  289. package/src/semantics/setup_intents.ts +45 -0
  290. package/src/semantics/shared.ts +3092 -106
  291. package/src/semantics/states.ts +883 -0
  292. package/src/semantics/subscription_items.ts +54 -0
  293. package/src/semantics/subscription_schedules.ts +66 -0
  294. package/src/semantics/subscriptions.ts +49 -432
  295. package/src/semantics/{test-clocks.ts → test_helpers.ts} +23 -47
  296. package/src/semantics/transfers.ts +11 -131
  297. package/src/server.ts +8 -0
  298. package/client/dashboard-api.ts +0 -286
  299. package/client/stripe-mirror.css +0 -277
  300. package/client/stripe-mirror.tsx +0 -1559
  301. package/dist/client/dashboard-api.d.ts +0 -107
  302. package/dist/client/dashboard-api.js +0 -238
  303. package/dist/client/dashboard-api.ts +0 -286
  304. package/dist/client/stripe-mirror.bundle.js +0 -236
  305. package/dist/client/stripe-mirror.css +0 -277
  306. package/dist/client/stripe-mirror.d.ts +0 -134
  307. package/dist/client/stripe-mirror.js +0 -859
  308. package/dist/client/stripe-mirror.tsx +0 -1559
  309. package/dist/src/screens/connect-settings.js +0 -103
  310. package/dist/src/screens/consent-skin.d.ts +0 -4
  311. package/dist/src/screens/consent-skin.js +0 -18
  312. package/dist/src/screens/financial-connections.d.ts +0 -5
  313. package/dist/src/screens/financial-connections.js +0 -90
  314. package/dist/src/screens/identity.d.ts +0 -5
  315. package/dist/src/screens/identity.js +0 -86
  316. package/dist/src/screens/onboarding.d.ts +0 -13
  317. package/dist/src/screens/portal.d.ts +0 -5
  318. package/dist/src/screens/public-details.d.ts +0 -5
  319. package/dist/src/screens/public-details.js +0 -90
  320. package/dist/src/semantics/after-payment.d.ts +0 -22
  321. package/dist/src/semantics/after-payment.js +0 -99
  322. package/dist/src/semantics/apps-secrets.d.ts +0 -2
  323. package/dist/src/semantics/billing.d.ts +0 -2
  324. package/dist/src/semantics/billing.js +0 -220
  325. package/dist/src/semantics/connect.d.ts +0 -5
  326. package/dist/src/semantics/connect.js +0 -493
  327. package/dist/src/semantics/credit-notes.d.ts +0 -2
  328. package/dist/src/semantics/credit-notes.js +0 -172
  329. package/dist/src/semantics/ephemeral-keys.d.ts +0 -2
  330. package/dist/src/semantics/ephemeral-keys.js +0 -34
  331. package/dist/src/semantics/files.d.ts +0 -2
  332. package/dist/src/semantics/files.js +0 -125
  333. package/dist/src/semantics/issuing.d.ts +0 -13
  334. package/dist/src/semantics/issuing.js +0 -575
  335. package/dist/src/semantics/ledger.d.ts +0 -59
  336. package/dist/src/semantics/ledger.js +0 -200
  337. package/dist/src/semantics/payment-intents.d.ts +0 -18
  338. package/dist/src/semantics/payment-intents.js +0 -452
  339. package/dist/src/semantics/payment-links.d.ts +0 -2
  340. package/dist/src/semantics/payment-links.js +0 -133
  341. package/dist/src/semantics/payment-methods.d.ts +0 -20
  342. package/dist/src/semantics/payment-methods.js +0 -140
  343. package/dist/src/semantics/plans.d.ts +0 -5
  344. package/dist/src/semantics/plans.js +0 -121
  345. package/dist/src/semantics/platform.d.ts +0 -9
  346. package/dist/src/semantics/platform.js +0 -206
  347. package/dist/src/semantics/renewals.d.ts +0 -47
  348. package/dist/src/semantics/renewals.js +0 -281
  349. package/dist/src/semantics/setup-intents.d.ts +0 -2
  350. package/dist/src/semantics/subscription-schedules.d.ts +0 -2
  351. package/dist/src/semantics/subscription-schedules.js +0 -119
  352. package/dist/src/semantics/tax.d.ts +0 -2
  353. package/dist/src/semantics/tax.js +0 -197
  354. package/dist/src/semantics/terminal.d.ts +0 -5
  355. package/dist/src/semantics/terminal.js +0 -182
  356. package/dist/src/semantics/test-clocks.d.ts +0 -6
  357. package/dist/src/semantics/tokens.d.ts +0 -4
  358. package/dist/src/semantics/tokens.js +0 -44
  359. package/dist/src/semantics/treasury.d.ts +0 -2
  360. package/dist/src/semantics/treasury.js +0 -377
  361. package/dist/src/semantics/webhook-endpoints.d.ts +0 -3
  362. package/dist/src/semantics/webhook-endpoints.js +0 -85
  363. package/dist/src/stripe-budget.d.ts +0 -55
  364. package/dist/src/stripe-budget.js +0 -155
  365. package/dist/src/stripe-capabilities.d.ts +0 -3
  366. package/dist/src/stripe-capabilities.js +0 -5836
  367. package/dist/src/stripe-conformance.d.ts +0 -43
  368. package/dist/src/stripe-conformance.js +0 -105
  369. package/dist/src/stripe-connector.d.ts +0 -161
  370. package/dist/src/stripe-connector.js +0 -414
  371. package/dist/src/stripe-emit.d.ts +0 -2
  372. package/dist/src/stripe-emit.js +0 -145
  373. package/dist/src/stripe-events.d.ts +0 -93
  374. package/dist/src/stripe-events.js +0 -392
  375. package/dist/src/stripe-js.d.ts +0 -4
  376. package/dist/src/stripe-js.js +0 -70
  377. package/dist/src/stripe-mirror-ui.d.ts +0 -15
  378. package/dist/src/stripe-mirror-ui.js +0 -87
  379. package/dist/src/stripe-perform-harness.d.ts +0 -9
  380. package/dist/src/stripe-perform-harness.js +0 -26
  381. package/dist/src/stripe-server.d.ts +0 -33
  382. package/dist/src/stripe-server.js +0 -429
  383. package/dist/src/stripe-shared.d.ts +0 -109
  384. package/dist/src/stripe-shared.js +0 -276
  385. package/dist/src/stripe-ui-conformance.d.ts +0 -5
  386. package/dist/src/stripe-ui-conformance.js +0 -79
  387. package/dist/src/stripe-ui-structure.d.ts +0 -3
  388. package/dist/src/stripe-ui-structure.js +0 -168
  389. package/dist/test-fixtures/stripe-known-deviations.json +0 -110
  390. package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +0 -14
  391. package/dist/test-fixtures/stripe-openapi-operations.json +0 -4717
  392. package/dist/test-fixtures/stripe-schemas.SOURCE.md +0 -35
  393. package/dist/test-fixtures/stripe-schemas.json +0 -3813
  394. package/src/screens/connect-settings.tsx +0 -121
  395. package/src/screens/consent-skin.ts +0 -20
  396. package/src/screens/financial-connections.tsx +0 -101
  397. package/src/screens/identity.tsx +0 -96
  398. package/src/screens/public-details.tsx +0 -105
  399. package/src/semantics/after-payment.ts +0 -118
  400. package/src/semantics/billing.ts +0 -216
  401. package/src/semantics/connect.ts +0 -487
  402. package/src/semantics/credit-notes.ts +0 -168
  403. package/src/semantics/ephemeral-keys.ts +0 -34
  404. package/src/semantics/files.ts +0 -143
  405. package/src/semantics/issuing.ts +0 -590
  406. package/src/semantics/ledger.ts +0 -253
  407. package/src/semantics/payment-intents.ts +0 -463
  408. package/src/semantics/payment-links.ts +0 -148
  409. package/src/semantics/payment-methods.ts +0 -145
  410. package/src/semantics/plans.ts +0 -131
  411. package/src/semantics/platform.ts +0 -220
  412. package/src/semantics/renewals.ts +0 -279
  413. package/src/semantics/setup-intents.ts +0 -87
  414. package/src/semantics/subscription-schedules.ts +0 -129
  415. package/src/semantics/tax.ts +0 -220
  416. package/src/semantics/terminal.ts +0 -195
  417. package/src/semantics/tokens.ts +0 -52
  418. package/src/semantics/treasury.ts +0 -383
  419. package/src/semantics/webhook-endpoints.ts +0 -87
  420. package/src/stripe-budget.ts +0 -181
  421. package/src/stripe-capabilities.ts +0 -5651
  422. package/src/stripe-conformance.ts +0 -124
  423. package/src/stripe-connector.ts +0 -462
  424. package/src/stripe-emit.ts +0 -157
  425. package/src/stripe-events.ts +0 -434
  426. package/src/stripe-js.ts +0 -70
  427. package/src/stripe-mirror-ui.ts +0 -90
  428. package/src/stripe-perform-harness.ts +0 -29
  429. package/src/stripe-server.ts +0 -393
  430. package/src/stripe-shared.ts +0 -297
  431. package/src/stripe-ui-conformance.ts +0 -88
  432. package/src/stripe-ui-structure.ts +0 -182
  433. package/test-fixtures/stripe-known-deviations.json +0 -110
  434. package/test-fixtures/stripe-openapi-operations.json +0 -4717
  435. package/test-fixtures/stripe-schemas.json +0 -3813
  436. /package/dist/src/{screens → engine}/industries.d.ts +0 -0
  437. /package/dist/src/{screens → engine}/industries.js +0 -0
  438. /package/dist/src/{semantics → engine}/test-cards.d.ts +0 -0
  439. /package/dist/src/{semantics → engine}/test-cards.js +0 -0
  440. /package/dist/src/{stripe-version.d.ts → engine/version.d.ts} +0 -0
  441. /package/src/{screens → engine}/industries.ts +0 -0
  442. /package/src/{semantics → engine}/test-cards.ts +0 -0
@@ -1,383 +0,0 @@
1
- // Treasury semantics: financial accounts and the flows that move their money (outbound payments
2
- // and transfers, inbound transfers), each posting a double entry to the account's ledger (a
3
- // transaction and its entry). An outbound flow stays processing (cancelable) until the network
4
- // settles it; an inbound transfer settles at once, as in test mode. The machines in
5
- // ../manifest.ts say which flows cancel. Lists and retrieves with no required scope are the
6
- // derived core's.
7
- import type { Semantics, SemanticsContext } from '@volter/world-core';
8
- import { PLATFORM_ACCOUNT_ID, validateMoney } from '../stripe-twin.ts';
9
- import { at, created, fail, list, newest, send, where, type Row } from './shared.ts';
10
-
11
- const FA = 'treasury.financial_account';
12
- const TX = 'treasury.transaction';
13
- const ENTRY = 'treasury.transaction_entry';
14
- const ENTRY_TYPES = new Set(['credit_reversal', 'debit_reversal', 'inbound_transfer', 'inbound_transfer_return', 'issuing_authorization_hold', 'issuing_authorization_release', 'outbound_payment', 'outbound_transfer', 'received_credit', 'received_debit']);
15
-
16
- const faMissing = (ctx: SemanticsContext, id: string, status = 404): Response => fail(ctx, `No such financial account: '${id}'`, status, 'resource_missing');
17
- const metadataOf = (ctx: SemanticsContext): unknown => (ctx.params.metadata && typeof ctx.params.metadata === 'object' ? ctx.params.metadata : {});
18
-
19
- /** A financial account's features as the served spec's treasury.financial_account_features gives them: a toggle
20
- * (card_issuing, deposit_insurance, intra_stripe_flows) or a feature per network (financial_addresses.aba,
21
- * inbound_transfers.ach, outbound_payments.ach and .us_domestic_wire, outbound_transfers likewise), each
22
- * { requested, status, status_details }. What a request asks for is laid over what the account had. Where the
23
- * documentation stops and the twin decides: a requested feature is active at once (test mode), and one never requested
24
- * is left out (each is optional in the served spec). Answers the features and the active features' paths. */
25
- const NETWORKS: Record<string, string[]> = { financial_addresses: ['aba'], inbound_transfers: ['ach'], outbound_payments: ['ach', 'us_domestic_wire'], outbound_transfers: ['ach', 'us_domestic_wire'] };
26
- const TOGGLES = ['card_issuing', 'deposit_insurance', 'intra_stripe_flows'];
27
- function featuresOf(requested: Row, had: Row = {}): { features: Row; active: string[] } {
28
- const on = (v: unknown): boolean => v === true || v === 'true';
29
- const setting = (asked: boolean) => ({ requested: asked, status: asked ? 'active' : 'restricted', status_details: [] });
30
- const features: Row = { ...had };
31
- for (const t of TOGGLES) {
32
- const r = requested[t] as Row | undefined;
33
- if (r && typeof r === 'object' && r.requested !== undefined) features[t] = setting(on(r.requested));
34
- }
35
- for (const [f, nets] of Object.entries(NETWORKS)) {
36
- const r = requested[f] as Row | undefined;
37
- if (!r || typeof r !== 'object') continue;
38
- const current = (features[f] as Row | undefined) ?? {};
39
- const next: Row = { ...current };
40
- for (const n of nets) {
41
- const nr = r[n] as Row | undefined;
42
- if (nr && typeof nr === 'object' && nr.requested !== undefined) next[n] = setting(on(nr.requested));
43
- }
44
- features[f] = next;
45
- }
46
- const active: string[] = [];
47
- for (const t of TOGGLES) if ((features[t] as Row | undefined)?.status === 'active') active.push(t);
48
- for (const [f, nets] of Object.entries(NETWORKS)) for (const n of nets) if (((features[f] as Row | undefined)?.[n] as Row | undefined)?.status === 'active') active.push(`${f}.${n}`);
49
- return { features, active };
50
- }
51
-
52
- /** The account's bank address once financial_addresses.aba is active: "The FinancialAccount gains a FinancialAddress
53
- * when the `financial_addresses.aba` feature is active", and "A FinancialAddress is not added until the
54
- * financial_addresses.aba feature has been activated" (docs.stripe.com/treasury/account-management/financial-accounts),
55
- * whose test example answers "bank_name": "Stripe Test Bank", "routing_number": "000000001" and the networks "ach",
56
- * "us_domestic_wire", "rtp"; "The full account_number is only returned if the request expands it" (the same page).
57
- * Where the documentation stops and the twin decides: the account number is ten digits drawn from the account's id,
58
- * answered by its last four (the full number is null: expanding it is not modelled), and the holder's name is the
59
- * platform account's business name, its dashboard name or, with neither, its id. */
60
- function abaAddress(ctx: SemanticsContext, faId: string): Row {
61
- let n = 0;
62
- for (const ch of faId) n = (n * 31 + ch.charCodeAt(0)) % 10_000_000_000;
63
- const number = String(n).padStart(10, '0');
64
- const platform = ctx.get('account', PLATFORM_ACCOUNT_ID) as Row | undefined;
65
- const name = ((platform?.business_profile as Row | undefined)?.name ?? ((platform?.settings as Row | undefined)?.dashboard as Row | undefined)?.display_name ?? PLATFORM_ACCOUNT_ID) as string;
66
- return { type: 'aba', supported_networks: ['ach', 'us_domestic_wire', 'rtp'], aba: { account_holder_name: name, account_number: null, account_number_last4: number.slice(-4), bank_name: 'Stripe Test Bank', routing_number: '000000001' } };
67
- }
68
- const addressesOf = (ctx: SemanticsContext, faId: string, active: string[]): Row[] => (active.includes('financial_addresses.aba') ? [abaAddress(ctx, faId)] : []);
69
-
70
- // an account opens with a zero balance in each supported currency and the requested features active
71
- const open: Semantics = async (ctx) => {
72
- const p = ctx.params;
73
- const currencies = Array.isArray(p.supported_currencies) ? p.supported_currencies.map(String) : typeof p.supported_currencies === 'string' ? [p.supported_currencies] : [];
74
- if (currencies.length === 0) return fail(ctx, 'Missing required param: supported_currencies.', 400, 'parameter_missing');
75
- const requested = p.features && typeof p.features === 'object' ? (p.features as Row) : {};
76
- const { features, active } = featuresOf(requested);
77
- const zero = Object.fromEntries(currencies.map((c) => [c, 0]));
78
- const id = ctx.mint(FA);
79
- return ctx.reply(
80
- await created(ctx, FA, { id }, {
81
- livemode: false, status: 'open', country: (p.country as string) ?? 'US',
82
- supported_currencies: currencies, active_features: active, pending_features: [], restricted_features: [],
83
- features, balance: { cash: zero, inbound_pending: zero, outbound_pending: zero },
84
- financial_addresses: addressesOf(ctx, id, active), platform_restrictions: null,
85
- status_details: { closed: null },
86
- metadata: metadataOf(ctx),
87
- }),
88
- );
89
- };
90
-
91
- // reading the features answers them; updating them lays the request over them (featuresOf)
92
- const features: Semantics = async (ctx) => {
93
- const id = at(ctx, 'financial_account');
94
- const f = ctx.get(FA, id);
95
- if (!f) return faMissing(ctx, id);
96
- if (ctx.call.request.method === 'GET') return ctx.reply({ object: 'treasury.financial_account_features', ...(f.features as object) });
97
- const next = featuresOf(ctx.params, (f.features as Row | undefined) ?? {});
98
- const updated = await ctx.write(FA, id, { features: next.features, active_features: next.active, financial_addresses: addressesOf(ctx, id, next.active) }, 'financial_account.features_updated');
99
- return ctx.reply({ object: 'treasury.financial_account_features', ...(updated.features as object) });
100
- };
101
-
102
- // only metadata and platform restrictions change
103
- const updateAccount: Semantics = async (ctx) => {
104
- const id = at(ctx, 'financial_account');
105
- if (!ctx.get(FA, id)) return faMissing(ctx, id);
106
- const patch: Row = {};
107
- if (ctx.params.metadata !== undefined) patch.metadata = ctx.params.metadata;
108
- if (ctx.params.platform_restrictions !== undefined) patch.platform_restrictions = ctx.params.platform_restrictions;
109
- return ctx.reply(await ctx.write(FA, id, patch, 'financial_account.updated'));
110
- };
111
-
112
- /** Post a flow's double entry: a ledger transaction with its net balance impact, and its one entry. */
113
- async function post(ctx: SemanticsContext, o: {
114
- financial_account: string; amount: number; currency: string; flow: string; flow_type: string;
115
- status: 'open' | 'posted'; balance_impact: Row; description: string; flowDetailKey?: string;
116
- }): Promise<string> {
117
- const now = ctx.now();
118
- const txnId = ctx.mint(TX);
119
- await ctx.write(TX, txnId, {
120
- object: 'treasury.transaction', created: now, livemode: false,
121
- amount: o.amount, currency: o.currency, financial_account: o.financial_account,
122
- flow: o.flow, flow_type: o.flow_type, flow_details: null,
123
- status: o.status, balance_impact: o.balance_impact, description: o.description,
124
- entries: { object: 'list', has_more: false, url: `/v1/treasury/transaction_entries?transaction=${txnId}`, data: [] },
125
- status_transitions: { posted_at: o.status === 'posted' ? now : null, void_at: null },
126
- }, 'treasury_transaction.created');
127
- await ctx.write(ENTRY, ctx.mint(ENTRY), {
128
- object: 'treasury.transaction_entry', created: now, livemode: false,
129
- amount: o.amount, currency: o.currency, financial_account: o.financial_account,
130
- flow: o.flow, flow_type: o.flow_type,
131
- flow_details: o.flowDetailKey ? { type: o.flowDetailKey, [o.flowDetailKey]: o.flow } : null,
132
- transaction: txnId, effective_at: now,
133
- balance_impact: o.balance_impact,
134
- // what the entry records: its flow's kind where Stripe names one (docs.stripe.com/api/treasury/transaction_entries/object);
135
- // a vendor `type`, kept apart from the kernel's row type
136
- _stripe_type: ENTRY_TYPES.has(String(o.flow_type)) ? o.flow_type : 'other',
137
- }, 'treasury_transaction_entry.created');
138
- // the account's balance moves by the entry's impact: cash "Funds the user can spend right now", inbound_pending
139
- // "Funds not spendable yet", outbound_pending "held for pending outbound flows" (the served spec's balance)
140
- const account = ctx.get(FA, o.financial_account);
141
- if (account) {
142
- const bal = (account.balance as Record<string, Record<string, number>> | undefined) ?? { cash: {}, inbound_pending: {}, outbound_pending: {} };
143
- const moved = Object.fromEntries((['cash', 'inbound_pending', 'outbound_pending'] as const).map((k) => [k, { ...(bal[k] ?? {}), [o.currency]: ((bal[k] ?? {})[o.currency] ?? 0) + (Number(o.balance_impact[k]) || 0) }]));
144
- await ctx.write(FA, o.financial_account, { balance: moved }, 'financial_account.balance_updated');
145
- }
146
- return txnId;
147
- }
148
-
149
- /** The request's funding account, or the refusal. */
150
- function fundingAccount(ctx: SemanticsContext): string | Response {
151
- const bad = validateMoney(ctx.params);
152
- if (bad) return send(ctx, bad);
153
- const fa = typeof ctx.params.financial_account === 'string' ? ctx.params.financial_account : '';
154
- if (!fa) return fail(ctx, 'Missing required param: financial_account.', 400, 'parameter_missing');
155
- return ctx.get(FA, fa) ? fa : faMissing(ctx, fa, 400);
156
- }
157
-
158
- const noTransitions = { canceled_at: null, failed_at: null, posted_at: null, returned_at: null };
159
-
160
- /** Where an outbound flow sends its money, as the served spec's payment method details give it: the bank account's
161
- * holder type, last four digits and routing number from what the request sent (a saved method's, or the test bank's
162
- * when none is given), and its billing details (required): the name and email sent, the address lines null where not
163
- * given. Where the documentation stops and the twin decides: a saved method's details are the test bank's. */
164
- function destinationDetails(ctx: SemanticsContext, dest: string | null): Row {
165
- const data = ctx.params.destination_payment_method_data && typeof ctx.params.destination_payment_method_data === 'object' ? (ctx.params.destination_payment_method_data as Row) : {};
166
- const bank = data.us_bank_account && typeof data.us_bank_account === 'object' ? (data.us_bank_account as Row) : {};
167
- const billing = data.billing_details && typeof data.billing_details === 'object' ? (data.billing_details as Row) : {};
168
- const address = billing.address && typeof billing.address === 'object' ? (billing.address as Row) : {};
169
- const number = typeof bank.account_number === 'string' ? bank.account_number.replace(/\D/g, '') : '';
170
- const billing_details = { name: billing.name ?? null, email: billing.email ?? null, address: Object.fromEntries(['city', 'country', 'line1', 'line2', 'postal_code', 'state'].map((k) => [k, address[k] ?? null])) };
171
- if (dest && data.type === undefined && dest.startsWith('fa_')) return { type: 'financial_account', financial_account: { id: dest, network: 'stripe' }, billing_details };
172
- return {
173
- type: 'us_bank_account', billing_details,
174
- us_bank_account: { last4: number ? number.slice(-4) : '6789', network: 'ach', routing_number: typeof bank.routing_number === 'string' ? bank.routing_number : '110000000', account_holder_type: typeof bank.account_holder_type === 'string' ? bank.account_holder_type : 'individual', account_type: typeof bank.account_type === 'string' ? bank.account_type : 'checking', bank_name: 'STRIPE TEST BANK', mandate: null },
175
- };
176
- }
177
-
178
- /** An outbound payment that names no destination: "You must provide either destination_payment_method or
179
- * destination_payment_method_data" (the served spec's outbound payment create). */
180
- function noDestination(ctx: SemanticsContext): Response {
181
- return fail(ctx, 'You must provide either `destination_payment_method` or `destination_payment_method_data`.', 400, 'parameter_missing');
182
- }
183
-
184
- const outboundPayment: Semantics = async (ctx) => {
185
- const fa = fundingAccount(ctx);
186
- if (fa instanceof Response) return fa;
187
- const dest = typeof ctx.params.destination_payment_method === 'string' ? ctx.params.destination_payment_method : null;
188
- if (!dest && !(ctx.params.destination_payment_method_data && typeof ctx.params.destination_payment_method_data === 'object')) return noDestination(ctx);
189
- const amount = ctx.params.amount as number;
190
- const currency = String(ctx.params.currency);
191
- const id = ctx.mint('treasury.outbound_payment');
192
- const txn = await post(ctx, { financial_account: fa, amount: -amount, currency, flow: id, flow_type: 'outbound_payment', status: 'open', balance_impact: { cash: -amount, inbound_pending: 0, outbound_pending: amount }, description: 'OutboundPayment' });
193
- return ctx.reply(
194
- await created(ctx, 'treasury.outbound_payment', { id }, {
195
- amount, currency, financial_account: fa, livemode: false, status: 'processing', cancelable: true,
196
- destination_payment_method: dest,
197
- destination_payment_method_details: destinationDetails(ctx, dest),
198
- destination_payment_method_data: null, end_user_details: null, expected_arrival_date: Number(ctx.now()) + 2 * 86400,
199
- hosted_regulatory_receipt_url: null, returned_details: null, statement_descriptor: (ctx.params.statement_descriptor as string) ?? 'payment',
200
- description: typeof ctx.params.description === 'string' ? ctx.params.description : null, transaction: txn, status_transitions: noTransitions, metadata: metadataOf(ctx),
201
- }),
202
- );
203
- };
204
-
205
- const outboundTransfer: Semantics = async (ctx) => {
206
- const fa = fundingAccount(ctx);
207
- if (fa instanceof Response) return fa;
208
- const dest = typeof ctx.params.destination_payment_method === 'string' ? ctx.params.destination_payment_method : null;
209
- const amount = ctx.params.amount as number;
210
- const currency = String(ctx.params.currency);
211
- const id = ctx.mint('treasury.outbound_transfer');
212
- const txn = await post(ctx, { financial_account: fa, amount: -amount, currency, flow: id, flow_type: 'outbound_transfer', status: 'open', balance_impact: { cash: -amount, inbound_pending: 0, outbound_pending: amount }, description: 'OutboundTransfer' });
213
- return ctx.reply(
214
- await created(ctx, 'treasury.outbound_transfer', { id }, {
215
- amount, currency, financial_account: fa, livemode: false, status: 'processing', cancelable: true,
216
- destination_payment_method: dest, destination_payment_method_details: destinationDetails(ctx, dest),
217
- expected_arrival_date: Number(ctx.now()) + 2 * 86400, hosted_regulatory_receipt_url: null,
218
- returned_details: null, statement_descriptor: (ctx.params.statement_descriptor as string) ?? 'transfer',
219
- description: typeof ctx.params.description === 'string' ? ctx.params.description : null, transaction: txn, status_transitions: noTransitions, metadata: metadataOf(ctx),
220
- }),
221
- );
222
- };
223
-
224
- /** The bank account an inbound transfer may pull from: "You must first set up the account-attached payment method for
225
- * inbound flows and verify the bank account using a SetupIntent", and invalid ones ("of unsupported types, containing
226
- * an unverified bank account, or not set up for inbound flows") "throw the same errors as in live mode"
227
- * (docs.stripe.com/treasury/moving-money/financial-accounts/into/inbound-transfers). A payment method is set up for
228
- * inbound flows by a SetupIntent whose flow_directions holds `inbound`, and verified when that SetupIntent succeeded
229
- * ("The bank account has been instantly verified or verification isn't necessary", its `succeeded` status,
230
- * docs.stripe.com/treasury/connect/legacy/v1/moving-money/working-with-bankaccount-objects).
231
- * Where the documentation stops and the twin decides: the page quotes no error, so the twin answers the documented code
232
- * for the class, payment_method_unexpected_state ("The provided payment method's state was incompatible with the
233
- * operation you were trying to perform", docs.stripe.com/error-codes), in its own words; an existing verified
234
- * BankAccount (`ba_`), which the page also allows, is not checked. Answers the payment method, or the refusal. */
235
- function inboundOrigin(ctx: SemanticsContext, origin: string): Row | Response | undefined {
236
- if (origin.startsWith('ba_')) return undefined;
237
- const pm = ctx.get('payment_method', origin);
238
- if (!pm) return fail(ctx, `No such PaymentMethod: '${origin}'`, 400, 'resource_missing');
239
- if (pm.type !== 'us_bank_account') return fail(ctx, `The PaymentMethod '${origin}' is of type ${String(pm.type)}; an InboundTransfer pulls from a us_bank_account.`, 400, 'payment_method_unexpected_state');
240
- const setUp = ctx.rows('setup_intent').some((si) => si.payment_method === origin && si.status === 'succeeded' && Array.isArray(si.flow_directions) && si.flow_directions.map(String).includes('inbound'));
241
- if (!setUp) return fail(ctx, `The PaymentMethod '${origin}' has not been set up for inbound flows and verified with a SetupIntent.`, 400, 'payment_method_unexpected_state');
242
- return pm;
243
- }
244
-
245
- const inboundTransfer: Semantics = async (ctx) => {
246
- const fa = fundingAccount(ctx);
247
- if (fa instanceof Response) return fa;
248
- const origin = typeof ctx.params.origin_payment_method === 'string' ? ctx.params.origin_payment_method : '';
249
- if (!origin) return fail(ctx, 'Missing required param: origin_payment_method.', 400, 'parameter_missing');
250
- const pm = inboundOrigin(ctx, origin);
251
- if (pm instanceof Response) return pm;
252
- const bank = (pm?.us_bank_account ?? {}) as Row;
253
- const billing = (pm?.billing_details ?? {}) as Row;
254
- // the debit mandate the account's verification made (docs.stripe.com/payments/setup-intents#mandates)
255
- const mandate = ctx.rows('setup_intent').find((si) => si.payment_method === origin && si.status === 'succeeded' && typeof si.mandate === 'string')?.mandate;
256
- const amount = ctx.params.amount as number;
257
- const currency = String(ctx.params.currency);
258
- const id = ctx.mint('treasury.inbound_transfer');
259
- // it starts processing, its funds pending inbound, until confirmed (succeedInbound)
260
- const txn = await post(ctx, { financial_account: fa, amount, currency, flow: id, flow_type: 'inbound_transfer', status: 'open', balance_impact: { cash: 0, inbound_pending: amount, outbound_pending: 0 }, description: 'InboundTransfer', flowDetailKey: 'inbound_transfer' });
261
- return ctx.reply(
262
- await created(ctx, 'treasury.inbound_transfer', { id }, {
263
- amount, currency, financial_account: fa, origin_payment_method: origin, livemode: false,
264
- status: 'processing', cancelable: true, returned: null,
265
- // the pulled account as its payment method holds it
266
- origin_payment_method_details: {
267
- type: 'us_bank_account',
268
- us_bank_account: { last4: bank.last4 ?? '6789', routing_number: bank.routing_number ?? '110000000', bank_name: bank.bank_name ?? 'STRIPE TEST BANK', account_holder_type: bank.account_holder_type ?? null, account_type: bank.account_type ?? null, fingerprint: bank.fingerprint ?? null, ...(mandate ? { mandate } : {}), network: 'ach' },
269
- billing_details: { address: billing.address ?? {}, email: billing.email ?? null, name: billing.name ?? null },
270
- },
271
- failure_details: null, hosted_regulatory_receipt_url: null,
272
- linked_flows: { received_debit: null }, statement_descriptor: (ctx.params.statement_descriptor as string) ?? 'transfer',
273
- description: typeof ctx.params.description === 'string' ? ctx.params.description : null, transaction: txn, status_transitions: { succeeded_at: null, failed_at: null, canceled_at: null },
274
- metadata: metadataOf(ctx),
275
- }),
276
- );
277
- };
278
-
279
- // test mode's stand-ins for money another party sends to the account or pulls from it
280
- // (docs.stripe.com/treasury/moving-money/receiving-funds, docs.stripe.com/api/treasury/received_credits/test_mode_create)
281
- function received(kind: 'received_credit' | 'received_debit'): Semantics {
282
- return async (ctx) => {
283
- const fa = fundingAccount(ctx);
284
- if (fa instanceof Response) return fa;
285
- const network = typeof ctx.params.network === 'string' ? ctx.params.network : '';
286
- if (!['ach', 'us_domestic_wire', 'stripe'].includes(network)) return fail(ctx, 'Missing required param: network.', 400, 'parameter_missing');
287
- const amount = ctx.params.amount as number;
288
- const currency = String(ctx.params.currency);
289
- const id = ctx.mint(`treasury.${kind}`);
290
- const signed = kind === 'received_credit' ? amount : -amount;
291
- const txn = await post(ctx, { financial_account: fa, amount: signed, currency, flow: id, flow_type: kind, status: 'posted', balance_impact: { cash: signed, inbound_pending: 0, outbound_pending: 0 }, description: kind === 'received_credit' ? 'ReceivedCredit' : 'ReceivedDebit', flowDetailKey: kind });
292
- return ctx.reply(
293
- await created(ctx, `treasury.${kind}`, { id }, {
294
- amount, currency, financial_account: fa, network, livemode: false, status: 'succeeded', failure_code: null,
295
- description: typeof ctx.params.description === 'string' ? ctx.params.description : kind === 'received_credit' ? 'Received credit' : 'Received debit',
296
- hosted_regulatory_receipt_url: null, transaction: txn, reversal_details: null,
297
- initiating_payment_method_details: { type: 'us_bank_account', billing_details: { address: {}, email: null, name: null }, us_bank_account: { bank_name: 'STRIPE TEST BANK', last4: '6789', routing_number: '110000000' } },
298
- linked_flows: kind === 'received_credit' ? { credit_reversal: null, issuing_authorization: null, issuing_transaction: null, source_flow: null, source_flow_type: null } : { debit_reversal: null, inbound_transfer: null, issuing_authorization: null, issuing_transaction: null, payout: null },
299
- }),
300
- );
301
- };
302
- }
303
-
304
- /** Test mode's confirmation of a processing inbound transfer: it succeeds, its transaction posts and the pending funds
305
- * become cash ("The status changes to succeeded once the funds have been "confirmed" and a transaction is created and
306
- * posted", docs.stripe.com/api/treasury/inbound_transfers). */
307
- const succeedInbound: Semantics = async (ctx) => {
308
- const id = at(ctx, 'id');
309
- const flow = ctx.get('treasury.inbound_transfer', id);
310
- if (!flow) return fail(ctx, `No such inbound transfer: '${id}'`, 404, 'resource_missing');
311
- const refused = ctx.legal('treasury.inbound_transfer', 'status', 'PostTestHelpersTreasuryInboundTransfersIdSucceed', flow.status, 'succeeded', id);
312
- if (refused) return ctx.refuse(refused);
313
- const txn = typeof flow.transaction === 'string' ? ctx.get(TX, flow.transaction) : undefined;
314
- const amount = Number(flow.amount) || 0;
315
- const cur = String(flow.currency ?? 'usd');
316
- if (txn && txn.status === 'open') {
317
- await ctx.write(TX, String(txn.id), { status: 'posted', balance_impact: { cash: amount, inbound_pending: 0, outbound_pending: 0 }, status_transitions: { ...(txn.status_transitions as object), posted_at: ctx.now() } }, 'treasury_transaction.posted');
318
- const account = ctx.get(FA, String(txn.financial_account));
319
- if (account) {
320
- const bal = (account.balance as Record<string, Record<string, number>> | undefined) ?? { cash: {}, inbound_pending: {}, outbound_pending: {} };
321
- await ctx.write(FA, String(account.id), { balance: { ...bal, cash: { ...(bal.cash ?? {}), [cur]: ((bal.cash ?? {})[cur] ?? 0) + amount }, inbound_pending: { ...(bal.inbound_pending ?? {}), [cur]: ((bal.inbound_pending ?? {})[cur] ?? 0) - amount } } }, 'financial_account.balance_updated');
322
- }
323
- }
324
- return ctx.reply(await ctx.write('treasury.inbound_transfer', id, { status: 'succeeded', cancelable: false, status_transitions: { ...(flow.status_transitions as object), succeeded_at: ctx.now() } }, 'inbound_transfer.succeeded'));
325
- };
326
-
327
- /** Cancel a flow still processing; an outbound one must also still be cancelable. */
328
- function cancel(resource: string, param: string, name: string, operationId: string, op: string, checkCancelable: boolean): Semantics {
329
- return async (ctx) => {
330
- const id = at(ctx, param);
331
- const flow = ctx.get(resource, id);
332
- if (!flow) return fail(ctx, `No such ${name}: '${id}'`, 404, 'resource_missing');
333
- // a processing flow that is no longer cancelable is refused as one no longer processing
334
- const refused = ctx.legal(resource, 'status', operationId, checkCancelable && flow.cancelable !== true ? 'not_cancelable' : flow.status, undefined, id);
335
- if (refused) return ctx.refuse(refused);
336
- // a canceled flow's open transaction is voided and what it held returns to the account (the reverse of its
337
- // balance impact). Where the documentation stops and the twin decides: a flow already posted is only marked canceled
338
- const txn = typeof flow.transaction === 'string' ? ctx.get(TX, flow.transaction) : undefined;
339
- if (txn && txn.status === 'open') {
340
- await ctx.write(TX, String(txn.id), { status: 'void', status_transitions: { ...(txn.status_transitions as object), void_at: ctx.now() } }, 'treasury_transaction.voided');
341
- const account = ctx.get(FA, String(txn.financial_account));
342
- const impact = (txn.balance_impact as Record<string, number> | undefined) ?? {};
343
- const cur = String(txn.currency ?? 'usd');
344
- if (account) {
345
- const bal = (account.balance as Record<string, Record<string, number>> | undefined) ?? { cash: {}, inbound_pending: {}, outbound_pending: {} };
346
- const back = Object.fromEntries((['cash', 'inbound_pending', 'outbound_pending'] as const).map((k) => [k, { ...(bal[k] ?? {}), [cur]: ((bal[k] ?? {})[cur] ?? 0) - (Number(impact[k]) || 0) }]));
347
- await ctx.write(FA, String(account.id), { balance: back }, 'financial_account.balance_updated');
348
- }
349
- }
350
- return ctx.reply(await ctx.write(resource, id, { status: 'canceled', cancelable: false, status_transitions: { ...(flow.status_transitions as object), canceled_at: ctx.now() } }, op));
351
- };
352
- }
353
-
354
- // the ledger is always read for one account
355
- function ledger(resource: string, spec: Record<string, (r: Row, v: unknown) => boolean>): Semantics {
356
- return async (ctx) => {
357
- if (typeof ctx.params.financial_account !== 'string' || !ctx.params.financial_account) return fail(ctx, 'Missing required param: financial_account.', 400, 'parameter_missing');
358
- return list(ctx, resource, where(ctx, newest(ctx, resource), spec));
359
- };
360
- }
361
-
362
- export const treasury: Record<string, Semantics> = {
363
- PostTreasuryFinancialAccounts: open,
364
- GetTreasuryFinancialAccountsFinancialAccountFeatures: features,
365
- PostTreasuryFinancialAccountsFinancialAccountFeatures: features,
366
- PostTreasuryFinancialAccountsFinancialAccount: updateAccount,
367
- PostTreasuryOutboundPayments: outboundPayment,
368
- PostTreasuryOutboundPaymentsIdCancel: cancel('treasury.outbound_payment', 'id', 'outbound payment', 'PostTreasuryOutboundPaymentsIdCancel', 'outbound_payment.canceled', true),
369
- PostTreasuryOutboundTransfers: outboundTransfer,
370
- PostTreasuryOutboundTransfersOutboundTransferCancel: cancel('treasury.outbound_transfer', 'outbound_transfer', 'outbound transfer', 'PostTreasuryOutboundTransfersOutboundTransferCancel', 'outbound_transfer.canceled', true),
371
- PostTreasuryInboundTransfers: inboundTransfer,
372
- PostTestHelpersTreasuryInboundTransfersIdSucceed: succeedInbound,
373
- PostTestHelpersTreasuryReceivedCredits: received('received_credit'),
374
- PostTestHelpersTreasuryReceivedDebits: received('received_debit'),
375
- PostTreasuryInboundTransfersInboundTransferCancel: cancel('treasury.inbound_transfer', 'inbound_transfer', 'inbound transfer', 'PostTreasuryInboundTransfersInboundTransferCancel', 'inbound_transfer.canceled', false),
376
- GetTreasuryTransactions: ledger(TX, {
377
- financial_account: (r, v) => r.financial_account === v, status: (r, v) => r.status === v,
378
- flow: (r, v) => r.flow === v, flow_type: (r, v) => r.flow_type === v,
379
- }),
380
- GetTreasuryTransactionEntries: ledger(ENTRY, {
381
- financial_account: (r, v) => r.financial_account === v, flow: (r, v) => r.flow === v, transaction: (r, v) => r.transaction === v,
382
- }),
383
- };
@@ -1,87 +0,0 @@
1
- // Webhook endpoint semantics: registering a URL and the events it subscribes to. Delivery reads
2
- // the endpoints from the tree, signing each POST with the endpoint's own secret; a disabled one
3
- // (the machine in ../manifest.ts) receives nothing. Endpoint list, retrieve and delete are the derived core's.
4
- //
5
- // The Events API lists and retrieves the stored events of the account a request acts for: an event of a connected
6
- // account carries it ("Each event for a connected account contains a top-level `account` property that identifies the
7
- // connected account. Because the connected account owns the object that triggered the event, you must make API
8
- // requests for that object as the connected account", docs.stripe.com/connect/webhooks; the event's `account`: "The
9
- // connected account that originates the event", spec/openapi.json.gz), so a request with the Stripe-Account header
10
- // sees that account's events and one without it the platform's, those with no `account`. Where the documentation
11
- // stops and the twin decides: a platform request does not see its connected accounts' events.
12
- import { worldEnvValue, type Semantics, type SemanticsContext } from '@volter/world-core';
13
- import { asBool } from '../stripe-twin.ts';
14
- import { actingAccount } from './ledger.ts';
15
- import { at, created, fail, inRange, list, newest, where, type Row } from './shared.ts';
16
-
17
- const WE = 'webhook_endpoint';
18
-
19
- // The signing secret is the World's where the World set one. Stripe mints an endpoint's secret and the app is given it
20
- // (the dashboard, `stripe listen`); in a World the app's env is the World's, made at boot, so the World's value is the
21
- // one the app verifies with, and an endpoint the app registers is signed with it: the twin's decision, since Stripe
22
- // lets no one choose a secret. A Connect endpoint (`connect`) takes a Connect name first. Only a value the World sets
23
- // counts (worldEnvValue), never one the caller's shell passes through; with none (a twin outside a World) the twin
24
- // mints, as Stripe does.
25
- const ACCOUNT_SECRET_ENV = ['STRIPE_WEBHOOK_SECRET', 'STRIPE_WEBHOOK_SIGNING_SECRET', 'STRIPE_ENDPOINT_SECRET', 'STRIPE_WEBHOOK_SECRET_KEY', 'NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET'];
26
- const CONNECT_SECRET_ENV = ['STRIPE_CONNECT_WEBHOOK_SECRET', 'STRIPE_WEBHOOK_SECRET_CONNECT', 'STRIPE_CONNECT_WEBHOOK_SIGNING_SECRET'];
27
- export function worldEndpointSecret(connect: boolean): string | undefined {
28
- for (const name of connect ? [...CONNECT_SECRET_ENV, ...ACCOUNT_SECRET_ENV] : ACCOUNT_SECRET_ENV) { const value = worldEnvValue(name); if (value) return value; }
29
- return undefined;
30
- }
31
-
32
- const create: Semantics = async (ctx) => {
33
- const params = ctx.params;
34
- const url = typeof params.url === 'string' ? params.url : '';
35
- if (!url) return fail(ctx, 'Missing required param: url.', 400, 'parameter_missing');
36
- const enabledEvents = Array.isArray(params.enabled_events) ? params.enabled_events.map(String) : typeof params.enabled_events === 'string' ? [params.enabled_events] : undefined;
37
- if (!enabledEvents || enabledEvents.length === 0) return fail(ctx, 'Missing required param: enabled_events.', 400, 'parameter_missing');
38
- const id = ctx.mint(WE);
39
- return ctx.reply(
40
- await created(ctx, WE, { ...params, id }, {
41
- url, enabled_events: enabledEvents, status: 'enabled', livemode: false, metadata: {},
42
- api_version: '2024-06-20', application: null, description: typeof params.description === 'string' ? params.description : null,
43
- secret: worldEndpointSecret(asBool(params.connect)) ?? `whsec_twin_${id}`,
44
- }),
45
- );
46
- };
47
-
48
- // `disabled` switches delivery off (status disabled) and back on; it is a parameter, not a field
49
- const update: Semantics = async (ctx) => {
50
- const id = at(ctx, 'webhook_endpoint');
51
- const we = ctx.get(WE, id);
52
- if (!we) return ctx.notFound(WE, id);
53
- const { disabled, ...fields }: Row = { ...ctx.params };
54
- if (Array.isArray(ctx.params.enabled_events)) fields.enabled_events = ctx.params.enabled_events.map(String);
55
- if (disabled !== undefined) return switchDelivery(ctx, id, we, fields, asBool(disabled));
56
- return ctx.reply(await ctx.write(WE, id, fields, 'webhook_endpoint.update'));
57
- };
58
-
59
- /** `disabled` switches delivery off or back on (docs.stripe.com/api/webhook_endpoints/update#update_webhook_endpoint-disabled). */
60
- async function switchDelivery(ctx: SemanticsContext, id: string, we: Row, fields: Row, off: boolean): Promise<Response> {
61
- const status = off ? 'disabled' : 'enabled';
62
- const refused = ctx.legal(WE, 'status', 'PostWebhookEndpointsWebhookEndpoint', we.status, status, id);
63
- if (refused) return ctx.refuse(refused);
64
- return ctx.reply(await ctx.write(WE, id, { ...fields, status }, 'webhook_endpoint.update'));
65
- }
66
-
67
- /** Whether a stored event is the acting account's (no `account`: the platform's). */
68
- const ownEvent = (ctx: SemanticsContext, e: Row): boolean => (typeof e.account === 'string' ? e.account : undefined) === actingAccount(ctx);
69
-
70
- const listEvents: Semantics = async (ctx) =>
71
- list(ctx, 'event', where(ctx, newest(ctx, 'event').filter((e) => ownEvent(ctx, e)), {
72
- type: (e, v) => e.type === v,
73
- types: (e, v) => (Array.isArray(v) ? v.map(String) : [String(v)]).includes(String(e.type)),
74
- created: (e, v) => inRange(e.created, v),
75
- }));
76
-
77
- const retrieveEvent: Semantics = async (ctx) => {
78
- const e = ctx.get('event', at(ctx, 'id'));
79
- return e && ownEvent(ctx, e) ? ctx.reply(e) : ctx.notFound('event', at(ctx, 'id'));
80
- };
81
-
82
- export const webhookEndpoints: Record<string, Semantics> = {
83
- GetEvents: listEvents,
84
- GetEventsId: retrieveEvent,
85
- PostWebhookEndpoints: create,
86
- PostWebhookEndpointsWebhookEndpoint: update,
87
- };