@volter/twin-stripe 2.0.38 → 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
@@ -0,0 +1,27 @@
1
+ export declare const STRIPE_CONSENT_SKIN = "\nbody { background: #f6f9fc; color: #1a1f36; font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Ubuntu, sans-serif; }\n.consent-badge { background: #ffffff; border: 1px solid #e3e8ee; color: #1a1f36; }\n.consent-vendor { background: #635bff; border-color: #635bff; }\n.consent-link { border-color: #c1c9d2; }\n.consent-box { background: #ffffff; border-color: #e3e8ee; }\n.consent-who small, .consent-permission summary small, .consent-note { color: #697386; }\n.consent-actions { border-color: #e3e8ee; }\n.consent-deny { background: #ffffff; border-color: #c1c9d2; color: #1a1f36; }\n.consent-allow { background: #635bff; border-color: #635bff; color: #ffffff; }\n";
2
+ /** The form fields a page's POST carries, as a browser posts them. */
3
+ export declare function formOf(request: Request): Promise<Record<string, string>>;
4
+ export declare const seeOther: (location: string) => Response;
5
+ export declare const DECLINES: Record<string, string>;
6
+ export declare const luhn: (digits: string) => boolean;
7
+ export declare const money: (minor: unknown, currency: unknown) => string;
8
+ export declare const COUNTRIES: {
9
+ value: string;
10
+ label: string;
11
+ }[];
12
+ /** Cards that are saved but decline when charged. */
13
+ export declare const DECLINES_WHEN_CHARGED: Record<string, string>;
14
+ /** The expiry as the customer typed it. Stripe's field formats itself as it is typed: the digits `1230` read `12 / 30`,
15
+ * and a first digit above 1 is a month on its own (`5` reads `05 / `), so a person types the digits straight through
16
+ * (Checkout's own field, seen on checkout.stripe.com; docs.stripe.com/payments/checkout names no format to type). The
17
+ * page's script (@volter/world-ui Payment, `format: 'card-expiry'`) shows it formatted; this reads what is posted either
18
+ * way: `MM / YY`, `MM/YYYY`, or the bare digits `MMYY`, `MYY` (`530`) and `MMYYYY`; a month past 12 is read, and refused
19
+ * as invalid by cardAnswer. */
20
+ export declare function parseExpiry(raw: string): {
21
+ month: number;
22
+ year: number;
23
+ } | undefined;
24
+ /** The card's answer: undefined when it pays, else what Checkout says under the button. */
25
+ export declare function cardAnswer(v: Record<string, string>, nowSeconds: number, chargesNow: boolean): string | undefined;
26
+ /** Stripe's answer for a page of one of its hosts the twin does not serve. */
27
+ export declare const notFound: () => Response;
@@ -0,0 +1,87 @@
1
+ // What Stripe's screens share (docs/contributing/architecture.md, "Pack layout": screens/shared.tsx): the skin over
2
+ // @volter/world-ui's consent piece for the flows where a person agrees to something (connected-account onboarding,
3
+ // identity verification, linking a bank), a page's form, and the card a customer types on Checkout and the portal.
4
+ export const STRIPE_CONSENT_SKIN = `
5
+ body { background: #f6f9fc; color: #1a1f36; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Ubuntu, sans-serif; }
6
+ .consent-badge { background: #ffffff; border: 1px solid #e3e8ee; color: #1a1f36; }
7
+ .consent-vendor { background: #635bff; border-color: #635bff; }
8
+ .consent-link { border-color: #c1c9d2; }
9
+ .consent-box { background: #ffffff; border-color: #e3e8ee; }
10
+ .consent-who small, .consent-permission summary small, .consent-note { color: #697386; }
11
+ .consent-actions { border-color: #e3e8ee; }
12
+ .consent-deny { background: #ffffff; border-color: #c1c9d2; color: #1a1f36; }
13
+ .consent-allow { background: #635bff; border-color: #635bff; color: #ffffff; }
14
+ `;
15
+ /** The form fields a page's POST carries, as a browser posts them. */
16
+ export async function formOf(request) {
17
+ return Object.fromEntries(new URLSearchParams(await request.text()));
18
+ }
19
+ export const seeOther = (location) => new Response(null, { status: 302, headers: { location } });
20
+ export const DECLINES = {
21
+ '4000000000000002': 'Your card was declined.',
22
+ '4000000000009995': 'Your card has insufficient funds.',
23
+ '4000000000000069': 'Your card has expired.',
24
+ '4000000000000127': "Your card's security code is incorrect.",
25
+ };
26
+ export const luhn = (digits) => {
27
+ let sum = 0;
28
+ for (let i = 0; i < digits.length; i++) {
29
+ let d = Number(digits[digits.length - 1 - i]);
30
+ if (i % 2 === 1) {
31
+ d *= 2;
32
+ if (d > 9)
33
+ d -= 9;
34
+ }
35
+ sum += d;
36
+ }
37
+ return digits.length >= 12 && sum % 10 === 0;
38
+ };
39
+ export const money = (minor, currency) => {
40
+ const c = typeof currency === 'string' ? currency.toUpperCase() : 'USD';
41
+ const zeroDecimal = ['JPY', 'KRW', 'VND', 'CLP', 'ISK', 'UGX', 'XAF', 'XOF'].includes(c);
42
+ return new Intl.NumberFormat('en-US', { style: 'currency', currency: c }).format((Number(minor) || 0) / (zeroDecimal ? 1 : 100));
43
+ };
44
+ export const COUNTRIES = [['US', 'United States'], ['GB', 'United Kingdom'], ['CA', 'Canada'], ['DE', 'Germany'], ['FR', 'France'], ['AU', 'Australia'], ['JP', 'Japan']].map(([value, label]) => ({ value: value, label: label }));
45
+ /** Cards that are saved but decline when charged. */
46
+ export const DECLINES_WHEN_CHARGED = { '4000000000000341': 'Your card was declined.' };
47
+ /** The expiry as the customer typed it. Stripe's field formats itself as it is typed: the digits `1230` read `12 / 30`,
48
+ * and a first digit above 1 is a month on its own (`5` reads `05 / `), so a person types the digits straight through
49
+ * (Checkout's own field, seen on checkout.stripe.com; docs.stripe.com/payments/checkout names no format to type). The
50
+ * page's script (@volter/world-ui Payment, `format: 'card-expiry'`) shows it formatted; this reads what is posted either
51
+ * way: `MM / YY`, `MM/YYYY`, or the bare digits `MMYY`, `MYY` (`530`) and `MMYYYY`; a month past 12 is read, and refused
52
+ * as invalid by cardAnswer. */
53
+ export function parseExpiry(raw) {
54
+ const split = /^\s*(\d{1,2})\s*\/\s*(\d{2}|\d{4})\s*$/.exec(raw);
55
+ const digits = raw.replace(/\s/g, '');
56
+ const bare = split ? undefined : /^(\d{2})(\d{2}|\d{4})$/.exec(digits) ?? /^([2-9])(\d{2})$/.exec(digits);
57
+ const m = split ?? bare;
58
+ if (!m)
59
+ return undefined;
60
+ return { month: Number(m[1]), year: m[2].length === 2 ? 2000 + Number(m[2]) : Number(m[2]) };
61
+ }
62
+ /** The card's answer: undefined when it pays, else what Checkout says under the button. */
63
+ export function cardAnswer(v, nowSeconds, chargesNow) {
64
+ const digits = (v.cardNumber ?? '').replace(/\D/g, '');
65
+ if (!digits)
66
+ return 'Your card number is incomplete.';
67
+ if (DECLINES[digits])
68
+ return DECLINES[digits];
69
+ if (chargesNow && DECLINES_WHEN_CHARGED[digits])
70
+ return DECLINES_WHEN_CHARGED[digits];
71
+ if (!luhn(digits))
72
+ return 'Your card number is invalid.';
73
+ const exp = parseExpiry(v.cardExpiry ?? '');
74
+ if (!exp)
75
+ return "Your card's expiration date is incomplete.";
76
+ const { month, year } = exp;
77
+ if (month < 1 || month > 12)
78
+ return "Your card's expiration date is invalid.";
79
+ const now = new Date(nowSeconds * 1000);
80
+ if (year < now.getUTCFullYear() || (year === now.getUTCFullYear() && month < now.getUTCMonth() + 1))
81
+ return "Your card's expiration year is in the past.";
82
+ if (!/^\d{3,4}$/.test(v.cardCvc ?? ''))
83
+ return "Your card's security code is incomplete.";
84
+ return undefined;
85
+ }
86
+ /** Stripe's answer for a page of one of its hosts the twin does not serve. */
87
+ export const notFound = () => new Response('Not Found', { status: 404, headers: { 'content-type': 'text/plain; charset=utf-8' } });
@@ -0,0 +1,3 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ /** js.stripe.com's script for a GET of its path; Stripe's 404 for anything else there. */
3
+ export declare function screen(ctx: HandlerContext): Promise<Response>;
@@ -0,0 +1,135 @@
1
+ import { notFound } from "./shared.js";
2
+ /** The release train a script path names: `/v3`, `/v3/` or `/v3/stripe.js` → 3, `/<train>/stripe.js` → the train. */
3
+ function stripeJsTrain(pathname) {
4
+ if (/^\/v3(\/|\/stripe\.js)?$/.test(pathname))
5
+ return 3;
6
+ return /^\/([a-z]+)\/stripe\.js$/.exec(pathname)?.[1];
7
+ }
8
+ function script(version) {
9
+ return `(function () {
10
+ var version = ${JSON.stringify(version)};
11
+ function gap(name) {
12
+ return function () { throw new Error("Stripe.js (Volter twin): stripe." + name + " is not modelled by this twin yet"); };
13
+ }
14
+ function Stripe(publishableKey) {
15
+ if (typeof publishableKey !== "string" || !publishableKey) throw new Error("Stripe.js (Volter twin): Stripe() needs a publishable key");
16
+ var api = "https://api.stripe.com/v1";
17
+ // the card fields every mounted element holds, the last mounted first
18
+ var mounted = [];
19
+ function cardOf(elements) {
20
+ var el = (elements && elements._mounted && elements._mounted[elements._mounted.length - 1]) || mounted[mounted.length - 1];
21
+ if (!el) return null;
22
+ var exp = String(el.expiry.value || "").split("/");
23
+ return { number: String(el.number.value || "").replace(/\s+/g, ""), exp_month: exp[0] ? String(Number(exp[0])) : "", exp_year: exp[1] ? String(2000 + Number(exp[1]) % 100) : "", cvc: String(el.cvc.value || "") };
24
+ }
25
+ function form(fields) {
26
+ return Object.keys(fields).filter(function (k) { return fields[k] !== undefined && fields[k] !== ""; }).map(function (k) { return encodeURIComponent(k) + "=" + encodeURIComponent(fields[k]); }).join("&");
27
+ }
28
+ function confirm(kind, options) {
29
+ options = options || {};
30
+ var elements = options.elements;
31
+ var secret = options.clientSecret || (elements && elements._options && elements._options.clientSecret);
32
+ if (typeof secret !== "string" || secret.indexOf("_secret_") < 0) return Promise.resolve({ error: { type: "invalid_request_error", message: "A clientSecret is required." } });
33
+ var id = secret.split("_secret_")[0];
34
+ var card = cardOf(elements);
35
+ var params = options.confirmParams || {};
36
+ var fields = { client_secret: secret };
37
+ if (card) { fields["payment_method_data[type]"] = "card"; fields["payment_method_data[card][number]"] = card.number; fields["payment_method_data[card][exp_month]"] = card.exp_month; fields["payment_method_data[card][exp_year]"] = card.exp_year; fields["payment_method_data[card][cvc]"] = card.cvc; }
38
+ if (params.return_url) fields.return_url = params.return_url;
39
+ var path = kind === "payment" ? "/payment_intents/" : "/setup_intents/";
40
+ return fetch(api + path + encodeURIComponent(id) + "/confirm", { method: "POST", headers: { authorization: "Bearer " + publishableKey, "content-type": "application/x-www-form-urlencoded" }, body: form(fields) })
41
+ .then(function (res) { return res.json().then(function (body) { return { ok: res.ok, body: body }; }); })
42
+ .then(function (r) {
43
+ if (!r.ok) return { error: r.body.error || { type: "api_error", message: "The confirmation failed." } };
44
+ var key = kind === "payment" ? "paymentIntent" : "setupIntent";
45
+ var out = {}; out[key] = r.body;
46
+ if (options.redirect === "if_required" || !params.return_url) return out;
47
+ var q = kind === "payment" ? "payment_intent" : "setup_intent";
48
+ var target = new URL(params.return_url);
49
+ target.searchParams.set(q, r.body.id);
50
+ target.searchParams.set(q + "_client_secret", secret);
51
+ target.searchParams.set("redirect_status", r.body.status === "succeeded" ? "succeeded" : r.body.status === "processing" ? "processing" : "failed");
52
+ window.location.assign(target.toString());
53
+ return new Promise(function () {});
54
+ });
55
+ }
56
+ function element(type, group) {
57
+ var handlers = {};
58
+ function emit(name, event) { (handlers[name] || []).forEach(function (h) { h(event); }); }
59
+ var el = {
60
+ _type: type,
61
+ mount: function (target) {
62
+ var node = typeof target === "string" ? document.querySelector(target) : target;
63
+ if (!node) throw new Error("Stripe.js (Volter twin): mount() found no element " + String(target));
64
+ node.innerHTML = "";
65
+ var wrap = document.createElement("div");
66
+ wrap.setAttribute("data-volter-twin-element", type);
67
+ function input(name, placeholder) { var i = document.createElement("input"); i.name = name; i.placeholder = placeholder; i.autocomplete = "off"; i.addEventListener("input", change); wrap.appendChild(i); return i; }
68
+ el.number = input("cardnumber", "Card number");
69
+ el.expiry = input("exp-date", "MM / YY");
70
+ el.cvc = input("cvc", "CVC");
71
+ node.appendChild(wrap);
72
+ mounted.push(el); group._mounted.push(el);
73
+ setTimeout(function () { emit("ready", { elementType: type }); }, 0);
74
+ },
75
+ on: function (name, handler) { (handlers[name] = handlers[name] || []).push(handler); return el; },
76
+ off: function (name, handler) { handlers[name] = (handlers[name] || []).filter(function (h) { return h !== handler; }); return el; },
77
+ update: function () {}, focus: function () { if (el.number) el.number.focus(); }, blur: function () {},
78
+ clear: function () { [el.number, el.expiry, el.cvc].forEach(function (i) { if (i) i.value = ""; }); change(); },
79
+ unmount: function () {}, destroy: function () { mounted = mounted.filter(function (m) { return m !== el; }); }
80
+ };
81
+ function change() {
82
+ var c = { number: el.number && el.number.value, expiry: el.expiry && el.expiry.value, cvc: el.cvc && el.cvc.value };
83
+ emit("change", { elementType: type, empty: !c.number && !c.expiry && !c.cvc, complete: !!(c.number && c.expiry && c.cvc), value: { type: "card" } });
84
+ }
85
+ return el;
86
+ }
87
+ var known = {
88
+ _registerWrapper: function () {},
89
+ elements: function (options) {
90
+ var group = { _options: options || {}, _mounted: [], _created: {} };
91
+ group.create = function (type) { var e = element(type, group); group._created[type] = e; return e; };
92
+ group.getElement = function (type) { return group._created[typeof type === "string" ? type : "card"] || null; };
93
+ group.update = function (next) { group._options = Object.assign({}, group._options, next || {}); };
94
+ group.fetchUpdates = function () { return Promise.resolve({}); };
95
+ group.submit = function () {
96
+ var card = cardOf(group);
97
+ if (!card || !card.number || !card.exp_month || !card.cvc) return Promise.resolve({ error: { type: "validation_error", message: "Your card details are incomplete." } });
98
+ return Promise.resolve({});
99
+ };
100
+ return group;
101
+ },
102
+ confirmPayment: function (options) { return confirm("payment", options); },
103
+ confirmSetup: function (options) { return confirm("setup", options); },
104
+ redirectToCheckout: function (options) {
105
+ if (!options || typeof options.sessionId !== "string" || !options.sessionId) return gap("redirectToCheckout without a sessionId")();
106
+ window.location.assign("https://checkout.stripe.com/c/pay/" + encodeURIComponent(options.sessionId));
107
+ return new Promise(function () {});
108
+ },
109
+ collectFinancialConnectionsAccounts: function (options) {
110
+ if (!options || typeof options.clientSecret !== "string" || !options.clientSecret) return gap("collectFinancialConnectionsAccounts without a clientSecret")();
111
+ window.location.assign("https://js.stripe.com/v3/financial-connections/" + encodeURIComponent(options.clientSecret));
112
+ return new Promise(function () {});
113
+ }
114
+ };
115
+ return new Proxy(known, {
116
+ get: function (target, name) {
117
+ if (name in target) return target[name];
118
+ if (typeof name === "symbol" || name === "then") return undefined;
119
+ return gap(String(name));
120
+ }
121
+ });
122
+ }
123
+ Stripe.version = version;
124
+ window.Stripe = Stripe;
125
+ })();
126
+ `;
127
+ }
128
+ /** js.stripe.com's script for a GET of its path; Stripe's 404 for anything else there. */
129
+ export async function screen(ctx) {
130
+ const request = ctx.call.request;
131
+ const train = request.method === 'GET' || request.method === 'HEAD' ? stripeJsTrain(new URL(request.url).pathname) : undefined;
132
+ if (train === undefined)
133
+ return notFound();
134
+ return new Response(script(train), { headers: { 'content-type': 'application/javascript; charset=utf-8', 'access-control-allow-origin': '*' } });
135
+ }
@@ -0,0 +1,2 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ export declare function PostAccountLinks(ctx: HandlerContext): Promise<Response>;
@@ -0,0 +1,22 @@
1
+ import { nowUnix } from "../engine/stripe.js";
2
+ import { accountMissing, fail } from "./shared.js";
3
+ // ── hosted onboarding links and embedded-component sessions ──
4
+ export async function PostAccountLinks(ctx) {
5
+ const account = typeof ctx.params.account === 'string' ? ctx.params.account : '';
6
+ if (!account)
7
+ return fail(ctx, 'Missing required param: account.', 400, 'parameter_missing');
8
+ if (!ctx.get('account', account))
9
+ return accountMissing(ctx, account, 400);
10
+ const linkType = typeof ctx.params.type === 'string' ? ctx.params.type : '';
11
+ if (linkType !== 'account_onboarding' && linkType !== 'account_update')
12
+ return fail(ctx, 'Invalid account link type: must be account_onboarding or account_update.', 400, 'parameter_invalid_string_enum');
13
+ // the owner is sent back to return_url when done, and to refresh_url for a new link once this one is used or expired
14
+ for (const k of ['refresh_url', 'return_url'])
15
+ if (typeof ctx.params[k] !== 'string' || !ctx.params[k])
16
+ return fail(ctx, `Missing required param: ${k}.`, 400, 'parameter_missing');
17
+ const now = Number(nowUnix(ctx.occurredAt));
18
+ const id = ctx.mint('account_link');
19
+ const link = { object: 'account_link', created: now, expires_at: now + 300, url: `https://connect.stripe.com/setup/${id}` };
20
+ await ctx.write('account_link', id, { ...link, account, type: linkType, refresh_url: ctx.params.refresh_url, return_url: ctx.params.return_url, used: false }, 'account_link.create');
21
+ return ctx.reply(link);
22
+ }
@@ -0,0 +1,4 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ export declare function GetAccountsAccountExternalAccounts(ctx: HandlerContext): Promise<Response>;
3
+ export declare function PostAccounts(ctx: HandlerContext): Promise<Response>;
4
+ export declare function PostAccountsAccountLoginLinks(ctx: HandlerContext): Promise<Response>;
@@ -0,0 +1,38 @@
1
+ import { externalList } from "../engine/common.js";
2
+ import { controllerOf, expressRequirements, keptKyc } from "../engine/connect.js";
3
+ import { ACCOUNT_TYPES, accountCapabilities, accountRequirements, accountSettings, nowUnix } from "../engine/stripe.js";
4
+ import { accountMissing, accountRow, at, connectReview, created, fail, list, newest } from "./shared.js";
5
+ export async function GetAccountsAccountExternalAccounts(ctx) {
6
+ const account = at(ctx, 'account');
7
+ if (!accountRow(ctx, account))
8
+ return accountMissing(ctx, account);
9
+ return list(ctx, 'external_account', newest(ctx, 'external_account').filter((e) => e.account === account));
10
+ }
11
+ // the requested capabilities become Stripe's status map, and settings its canonical shape
12
+ export async function PostAccounts(ctx) {
13
+ const params = ctx.params;
14
+ const type = typeof params.type === 'string' ? params.type : 'standard';
15
+ if (!ACCOUNT_TYPES.has(type))
16
+ return fail(ctx, 'Invalid account type: must be one of express, standard, or custom.', 400, 'parameter_invalid_string_enum');
17
+ const { capabilities: _caps, settings: _settings, ...accountParams } = keptKyc(params);
18
+ const id = ctx.mint('account');
19
+ const made = await created(ctx, 'account', { ...accountParams, id, type }, {
20
+ business_type: null, charges_enabled: false, payouts_enabled: false, details_submitted: false,
21
+ capabilities: accountCapabilities(params), requirements: type === 'express' ? expressRequirements(params) : accountRequirements(),
22
+ country: typeof params.country === 'string' ? params.country : 'US',
23
+ default_currency: 'usd', email: params.email ?? null, metadata: {}, livemode: false,
24
+ settings: accountSettings(params.settings), business_profile: {},
25
+ controller: controllerOf(type), external_accounts: externalList(id, []),
26
+ future_requirements: { alternatives: [], current_deadline: null, currently_due: [], disabled_reason: null, errors: [], eventually_due: [], past_due: [], pending_verification: [] },
27
+ tos_acceptance: { date: null, ip: null, user_agent: null },
28
+ });
29
+ await connectReview(ctx, String(made.id));
30
+ return ctx.reply(ctx.get('account', String(made.id)));
31
+ }
32
+ // a single-use Express dashboard link, not stored
33
+ export async function PostAccountsAccountLoginLinks(ctx) {
34
+ const id = at(ctx, 'account');
35
+ if (!ctx.get('account', id))
36
+ return accountMissing(ctx, id);
37
+ return ctx.reply({ object: 'login_link', created: nowUnix(ctx.occurredAt), url: `https://connect.twin.local/express/${id}` });
38
+ }
@@ -0,0 +1,4 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ export declare function GetAppsSecretsFind(ctx: HandlerContext): Promise<Response>;
3
+ export declare function PostAppsSecrets(ctx: HandlerContext): Promise<Response>;
4
+ export declare function PostAppsSecretsDelete(ctx: HandlerContext): Promise<Response>;
@@ -1,12 +1,14 @@
1
- import { created, fail, list, newest, kept } from "./shared.js";
2
- const SECRET = 'apps.secret';
3
- function scopeKeyOf(ctx) {
4
- const scope = ctx.params.scope && typeof ctx.params.scope === 'object' ? ctx.params.scope : undefined;
5
- const scopeType = scope && typeof scope.type === 'string' ? scope.type : 'account';
6
- return scopeType === 'user' ? `user:${String(scope.user)}` : 'account';
1
+ import { SECRET } from "../engine/apps-secrets.js";
2
+ import { nowUnix } from "../engine/stripe.js";
3
+ import { created, fail, named, scopeKeyOf } from "./shared.js";
4
+ export async function GetAppsSecretsFind(ctx) {
5
+ const name = typeof ctx.params.name === 'string' ? ctx.params.name : '';
6
+ if (!name)
7
+ return fail(ctx, 'Missing required param: name.', 400, 'parameter_missing');
8
+ const s = named(ctx, name);
9
+ return s ? ctx.reply(s) : fail(ctx, `No such secret: '${name}'`, 404, 'resource_missing');
7
10
  }
8
- const named = (ctx, name) => ctx.rows(SECRET).find((s) => s.name === name && kept(ctx, SECRET, s, '_scope_key') === scopeKeyOf(ctx));
9
- const set = async (ctx) => {
11
+ export async function PostAppsSecrets(ctx) {
10
12
  const params = ctx.params;
11
13
  const name = typeof params.name === 'string' ? params.name : '';
12
14
  if (!name)
@@ -22,21 +24,14 @@ const set = async (ctx) => {
22
24
  const expiresAt = params.expires_at !== undefined ? Math.trunc(Number(params.expires_at)) : null;
23
25
  const existing = named(ctx, name);
24
26
  if (existing)
25
- return ctx.reply(await ctx.write(SECRET, String(existing.id), { payload: params.payload, expires_at: expiresAt, _updated: ctx.now() }, 'apps_secret.update'));
27
+ return ctx.reply(await ctx.write(SECRET, String(existing.id), { payload: params.payload, expires_at: expiresAt, _updated: nowUnix(ctx.occurredAt) }, 'apps_secret.update'));
26
28
  return ctx.reply(await created(ctx, SECRET, { name }, {
27
29
  livemode: false, deleted: false, expires_at: expiresAt, payload: params.payload,
28
30
  scope: scopeType === 'user' ? { type: 'user', user: scope.user } : { type: 'account' },
29
31
  _scope_key: scopeKeyOf(ctx),
30
32
  }));
31
- };
32
- const find = async (ctx) => {
33
- const name = typeof ctx.params.name === 'string' ? ctx.params.name : '';
34
- if (!name)
35
- return fail(ctx, 'Missing required param: name.', 400, 'parameter_missing');
36
- const s = named(ctx, name);
37
- return s ? ctx.reply(s) : fail(ctx, `No such secret: '${name}'`, 404, 'resource_missing');
38
- };
39
- const remove = async (ctx) => {
33
+ }
34
+ export async function PostAppsSecretsDelete(ctx) {
40
35
  const name = typeof ctx.params.name === 'string' ? ctx.params.name : '';
41
36
  if (!name)
42
37
  return fail(ctx, 'Missing required param: name.', 400, 'parameter_missing');
@@ -44,11 +39,4 @@ const remove = async (ctx) => {
44
39
  if (!s)
45
40
  return fail(ctx, `No such secret: '${name}'`, 404, 'resource_missing');
46
41
  return ctx.reply(await ctx.write(SECRET, String(s.id), { deleted: true }, 'apps_secret.delete'));
47
- };
48
- const listSecrets = async (ctx) => list(ctx, SECRET, newest(ctx, SECRET).filter((s) => kept(ctx, SECRET, s, '_scope_key') === scopeKeyOf(ctx)));
49
- export const appsSecrets = {
50
- PostAppsSecrets: set,
51
- GetAppsSecretsFind: find,
52
- PostAppsSecretsDelete: remove,
53
- GetAppsSecrets: listSecrets,
54
- };
42
+ }
@@ -0,0 +1,2 @@
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ export declare function around(ctx: HandlerContext, next: (request?: Request) => Promise<Response>): Promise<Response>;
@@ -0,0 +1,16 @@
1
+ import { actingAsOAuthKey, platformKeyRefused, publishableKeyRefused, refuseParameters, rendered, revokedAccountRefused, withMetadata } from "./shared.js";
2
+ export async function around(ctx, next) {
3
+ const arrived = ctx.call.request;
4
+ const unkeyed = platformKeyRefused(ctx, arrived);
5
+ if (unkeyed)
6
+ return unkeyed;
7
+ const acting = await actingAsOAuthKey(ctx, arrived.clone());
8
+ if (acting instanceof Response)
9
+ return acting;
10
+ if (ctx.call.operation.id !== 'unmatched') {
11
+ const refused = publishableKeyRefused(ctx) ?? revokedAccountRefused(ctx) ?? refuseParameters(ctx);
12
+ if (refused)
13
+ return refused;
14
+ }
15
+ return rendered(arrived, await next(withMetadata(ctx, acting)));
16
+ }
@@ -1,11 +1,2 @@
1
- import type { Semantics, SemanticsContext } from '@volter/world-core';
2
- import { type Row } from './shared.js';
3
- /** The acting account's Balance object (docs.stripe.com/api/balance/balance_object). */
4
- export declare function balanceBody(ctx: SemanticsContext): Row;
5
- /** Time's arrivals, written: each of the acting account's payouts whose arrival date has come moves pending → paid
6
- * (the clock's move, as asOf reads it), written as `payout.paid`, the event Stripe sends for it. Answers their ids. */
7
- export declare function payDuePayouts(ctx: SemanticsContext): Promise<string[]>;
8
- /** Time's payouts, caught up to the World's clock: each account on an automatic schedule is paid out, on each of its
9
- * scheduled days that has come, what became available by then. */
10
- export declare function advancePayouts(ctx: SemanticsContext): Promise<void>;
11
- export declare const balances: Record<string, Semantics>;
1
+ import type { HandlerContext } from '@volter/world-core';
2
+ export declare function GetBalance(ctx: HandlerContext): Promise<Response>;
@@ -1,195 +1,4 @@
1
- import { validateMoney } from "../stripe-twin.js";
2
- import { accountSettings, PLATFORM_ACCOUNT_ID } from "../stripe-twin.js";
3
- import { actingAccount, balanceOf, refusePayout, settleAutomaticPayout, settlePayout, unpaidEntries } from "./ledger.js";
4
- import { at, at_, created, fail, inRange, list, newest, send, where, kept } from "./shared.js";
5
- const account = actingAccount;
6
- const DAY = 86_400;
7
- const payoutMissing = (ctx, id) => fail(ctx, `No such payout: '${id}'`, 404, 'resource_missing');
8
- /** The acting account's Balance object (docs.stripe.com/api/balance/balance_object). */
9
- export function balanceBody(ctx) {
10
- const { available, pending, issuing } = balanceOf(ctx);
11
- const toArr = (m) => {
12
- const out = [...m.entries()].map(([currency, amount]) => ({ amount, currency, source_types: { card: amount } }));
13
- return out.length ? out : [{ amount: 0, currency: 'usd', source_types: { card: 0 } }];
14
- };
15
- // a platform's balance holds its connected accounts' reserve, "Funds held due to negative balances on connected accounts
16
- // where account.controller.requirement_collection is `application`" (docs.stripe.com/api/balance/balance_object, whose
17
- // example answers `[{"amount": 0, "currency": "usd"}]`); the twin models no such reserve, so it is zero in each currency
18
- const reserved = account(ctx) ? {} : { connect_reserved: toArr(available).map((b) => ({ amount: 0, currency: b.currency })) };
19
- return {
20
- object: 'balance', available: toArr(available), pending: toArr(pending), ...reserved, livemode: false,
21
- ...(issuing.size ? { issuing: { available: [...issuing.entries()].map(([currency, amount]) => ({ amount, currency, source_types: { card: amount } })) } } : {}),
22
- };
1
+ import { balanceBody } from "./shared.js";
2
+ export async function GetBalance(ctx) {
3
+ return ctx.reply(balanceBody(ctx));
23
4
  }
24
- const balance = async (ctx) => ctx.reply(balanceBody(ctx));
25
- /** Time's arrivals, written: each of the acting account's payouts whose arrival date has come moves pending → paid
26
- * (the clock's move, as asOf reads it), written as `payout.paid`, the event Stripe sends for it. Answers their ids. */
27
- export async function payDuePayouts(ctx) {
28
- const acct = account(ctx);
29
- const now = Number(ctx.now());
30
- const paid = [];
31
- for (const p of newest(ctx, 'payout')) {
32
- if ((acct ? kept(ctx, 'payout', p, '_account') !== acct : !!kept(ctx, 'payout', p, '_account')) || p.status !== 'pending' || Number(p.arrival_date) > now)
33
- continue;
34
- if (ctx.legal('payout', 'status', ctx.call.operation.id, 'pending', 'paid', String(p.id), 'time'))
35
- continue;
36
- await ctx.write('payout', String(p.id), { status: 'paid' }, 'payout.paid');
37
- paid.push(String(p.id));
38
- }
39
- return paid;
40
- }
41
- /** Where a connected account's payout goes: "ID of the bank account or card the payout is sent to" (served spec,
42
- * payout.destination), its default external account for the currency, "When multiple accounts are available for a given
43
- * currency, Stripe uses the one set as `default_for_currency`" (docs.stripe.com/connect/payouts-bank-accounts), the
44
- * newest such. Where the documentation stops and the twin decides: the platform's own bank account is not modelled, so
45
- * its payouts name none. */
46
- function payoutBank(ctx, account, currency) {
47
- const banks = newest(ctx, 'external_account').filter((e) => e.account === account && String(e.currency ?? currency) === currency);
48
- return String((banks.find((e) => e.default_for_currency === true) ?? banks[0])?.id ?? '') || null;
49
- }
50
- const payoutDefaults = (ctx) => ({
51
- method: 'standard', type: 'bank_account', source_type: 'card', automatic: false,
52
- reconciliation_status: 'not_applicable', arrival_date: Number(ctx.now()) + 2 * DAY, livemode: false, metadata: {},
53
- });
54
- /** A payout as the clock reads it: paid once its arrival date has come, the clock's move, asked of the
55
- * machine as a write asks it. */
56
- function asOf(ctx, p) {
57
- if (p.status !== 'pending' || Number(p.arrival_date) > Number(ctx.now()))
58
- return p;
59
- ctx.legal('payout', 'status', ctx.call.operation.id, 'pending', 'paid', String(p.id), 'time');
60
- return { ...p, status: 'paid' };
61
- }
62
- /** A connected account's payout in a currency none of its bank accounts takes. */
63
- function noExternalAccount(ctx, currency) {
64
- return fail(ctx, `Sorry, you don't have any external accounts in that currency (${currency}).`, 400);
65
- }
66
- const createPayout = async (ctx) => {
67
- const bad = validateMoney(ctx.params);
68
- if (bad)
69
- return send(ctx, bad);
70
- const acct = account(ctx);
71
- if (acct && !ctx.get('account', acct))
72
- return fail(ctx, `No such account: '${acct}'`, 400, 'account_invalid');
73
- const amount = Math.trunc(Number(ctx.params.amount) || 0);
74
- const currency = String(ctx.params.currency ?? 'usd');
75
- // a connected account is paid out to its own bank account
76
- if (acct && !ctx.rows('external_account').some((e) => e.account === acct && (e.currency ?? currency) === currency))
77
- return noExternalAccount(ctx, currency);
78
- const refused = refusePayout(ctx, amount, currency);
79
- if (refused)
80
- return refused;
81
- const id = ctx.mint('payout');
82
- const bt = await settlePayout(ctx, id, -amount, currency);
83
- return ctx.reply(await created(ctx, 'payout', { ...ctx.params, id }, { status: 'pending', ...payoutDefaults(ctx), balance_transaction: bt, destination: acct ? payoutBank(ctx, acct, currency) : null, ...(acct ? { _account: acct } : {}) }));
84
- };
85
- const listPayouts = async (ctx) => {
86
- const acct = account(ctx);
87
- const scoped = newest(ctx, 'payout').filter((p) => (acct ? kept(ctx, 'payout', p, '_account') === acct : !kept(ctx, 'payout', p, '_account'))).map((p) => asOf(ctx, p));
88
- return list(ctx, 'payout', where(ctx, scoped, { status: (p, v) => p.status === v, created: (p, v) => inRange(p.created, v), arrival_date: (p, v) => inRange(p.arrival_date, v) }));
89
- };
90
- const DAYS = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'];
91
- /** The first scheduled payout time on or after `from`: midnight UTC of a day the schedule pays out on. */
92
- function payoutDay(from, schedule) {
93
- const first = Math.ceil(from / DAY) * DAY;
94
- const pays = (day) => {
95
- const d = new Date(day * 1000);
96
- if (schedule.interval === 'weekly')
97
- return DAYS[d.getUTCDay()] === String(schedule.weekly_anchor ?? 'monday');
98
- if (schedule.interval === 'monthly')
99
- return d.getUTCDate() === Math.min(Number(schedule.monthly_anchor ?? 1), new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate());
100
- return true;
101
- };
102
- return Array.from({ length: 62 }, (_, i) => first + i * DAY).find(pays) ?? first;
103
- }
104
- /** Time's payouts, caught up to the World's clock: each account on an automatic schedule is paid out, on each of its
105
- * scheduled days that has come, what became available by then. */
106
- export async function advancePayouts(ctx) {
107
- const now = Number(ctx.now());
108
- const platform = ctx.get('account', PLATFORM_ACCOUNT_ID);
109
- const accounts = [{ id: undefined, settings: platform?.settings }];
110
- for (const a of ctx.rows('account')) {
111
- if (a.id === PLATFORM_ACCOUNT_ID || a.payouts_enabled !== true)
112
- continue;
113
- if (!ctx.rows('external_account').some((e) => e.account === a.id))
114
- continue;
115
- accounts.push({ id: String(a.id), settings: a.settings });
116
- }
117
- for (const acct of accounts) {
118
- const schedule = (accountSettings(acct.settings, acct.settings ?? undefined).payouts.schedule ?? {});
119
- if (schedule.interval === 'manual')
120
- continue;
121
- const unpaid = unpaidEntries(ctx, acct.id);
122
- const days = [...new Set(unpaid.map((t) => payoutDay(Number(t.available_on) || 0, schedule)))].filter((d) => d <= now).sort((x, y) => x - y);
123
- const paid = new Set();
124
- for (const day of days) {
125
- const due = unpaid.filter((t) => !paid.has(t.id) && (Number(t.available_on) || 0) <= day);
126
- const byCurrency = new Map();
127
- for (const t of due)
128
- byCurrency.set(String(t.currency ?? 'usd'), [...(byCurrency.get(String(t.currency ?? 'usd')) ?? []), t]);
129
- for (const [currency, entries] of byCurrency) {
130
- const amount = entries.reduce((n, t) => n + (Number(t.net) || 0), 0);
131
- // nothing to pay yet: what came due is carried to the next payout
132
- if (amount <= 0)
133
- continue;
134
- // made on its day, as Stripe makes it, whenever the request that catches it up comes
135
- const c = await at_(ctx)(day);
136
- const id = c.mint('payout');
137
- const bt = await settleAutomaticPayout(c, id, amount, currency, acct.id, day, entries);
138
- await created(c, 'payout', { id, amount, currency }, {
139
- status: 'pending', ...payoutDefaults(c), arrival_date: day + 2 * DAY, automatic: true, balance_transaction: bt, destination: acct.id ? payoutBank(c, String(acct.id), currency) : null,
140
- description: 'STRIPE PAYOUT', ...(acct.id ? { _account: acct.id } : {}),
141
- });
142
- for (const t of entries)
143
- paid.add(t.id);
144
- }
145
- }
146
- }
147
- }
148
- const retrievePayout = async (ctx) => {
149
- const p = ctx.get('payout', at(ctx, 'payout'));
150
- return p ? ctx.reply(asOf(ctx, p)) : payoutMissing(ctx, at(ctx, 'payout'));
151
- };
152
- const cancelPayout = async (ctx) => {
153
- const id = at(ctx, 'payout');
154
- const po = ctx.get('payout', id);
155
- if (!po)
156
- return payoutMissing(ctx, id);
157
- const refused = ctx.legal('payout', 'status', 'PostPayoutsPayoutCancel', asOf(ctx, po).status, undefined, id);
158
- if (refused)
159
- return ctx.refuse(refused);
160
- // the money comes back to the balance it left
161
- const owner = kept(ctx, 'payout', po, '_account');
162
- await settlePayout(ctx, id, Number(po.amount) || 0, String(po.currency ?? 'usd'), typeof owner === 'string' ? owner : null);
163
- return ctx.reply(await ctx.write('payout', id, { status: 'canceled' }, 'payout.cancel'));
164
- };
165
- // a reversal is itself a payout in the other direction, back into the connected account's balance, as the reverse page's
166
- // example answers it: a negative amount, pending until it arrives, carrying the request's metadata
167
- // (docs.stripe.com/api/payouts/reverse); the original stays paid and names it
168
- const reversePayout = async (ctx) => {
169
- const id = at(ctx, 'payout');
170
- const po = ctx.get('payout', id);
171
- if (!po)
172
- return payoutMissing(ctx, id);
173
- const owner = kept(ctx, 'payout', po, '_account');
174
- if (typeof owner !== 'string')
175
- return fail(ctx, "Payout reversals are only supported for payouts to connected accounts' bank accounts.", 400);
176
- const status = String(asOf(ctx, po).status);
177
- if (po.reversed_by || status !== 'paid')
178
- return ctx.refuse({ status: 400, code: 'payout_reversal_not_allowed', message: po.reversed_by ? 'This payout has already been reversed.' : `This payout cannot be reversed because it has a status of ${status}. A pending payout can be canceled instead.` });
179
- const reversalId = ctx.mint('payout');
180
- const bt = await settlePayout(ctx, reversalId, Number(po.amount) || 0, String(po.currency ?? 'usd'), owner);
181
- const metadata = ctx.params.metadata && typeof ctx.params.metadata === 'object' ? { metadata: ctx.params.metadata } : {};
182
- const reversal = await created(ctx, 'payout', { id: reversalId, amount: -(Number(po.amount) || 0), currency: po.currency, ...metadata }, {
183
- status: 'pending', ...payoutDefaults(ctx), balance_transaction: bt, original_payout: id, destination: po.destination ?? null, _account: owner,
184
- });
185
- await ctx.write('payout', id, { reversed_by: reversal.id }, 'payout.reversed');
186
- return ctx.reply(reversal);
187
- };
188
- export const balances = {
189
- GetBalance: balance,
190
- PostPayouts: createPayout,
191
- GetPayouts: listPayouts,
192
- GetPayoutsPayout: retrievePayout,
193
- PostPayoutsPayoutCancel: cancelPayout,
194
- PostPayoutsPayoutReverse: reversePayout,
195
- };