@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
package/src/stripe-js.ts DELETED
@@ -1,70 +0,0 @@
1
- // STRIPE.JS — the client library an application's page loads from js.stripe.com (docs/contributing/architecture.md,
2
- // "Screens": a widget the vendor ships into the application's own page "is not a screen: it is a client library,
3
- // twinned from its published types as an SDK surface is"). Written from @stripe/stripe-js's published loader and types
4
- // (7.x: dist/index.mjs, dist/stripe-js/stripe.d.ts, dist/stripe-js/hosted-checkout.d.ts), nothing of Stripe's script
5
- // copied:
6
- // - the loader injects https://js.stripe.com/<release train>/stripe.js (or /v3/), and accepts a script already on the
7
- // page whose src matches `/^https:\/\/js\.stripe\.com\/(v3|[a-z]+)\/stripe\.js(\?.*)?$/` (so /v3/stripe.js too);
8
- // it resolves `window.Stripe`, reads `Stripe.version` (3 is the v3 URL, otherwise the train's name) and calls the
9
- // instance's `_registerWrapper` when it has one;
10
- // - `stripe.redirectToCheckout({ sessionId })` sends the customer to that Checkout Session's page (hosted-checkout.d.ts,
11
- // RedirectToCheckoutServerOptions), which this twin serves at checkout.stripe.com/c/pay/{id} (screens/checkout.tsx),
12
- // and its promise settles only on failure (`Promise<never | {error}>`);
13
- // - `stripe.collectFinancialConnectionsAccounts({ clientSecret })` loads the Financial Connections authentication
14
- // flow for the session whose client_secret it is (stripe.d.ts; docs.stripe.com/js/financial_connections/
15
- // collect_financial_connections_accounts: "it will load the Authentication Flow, an on-page modal UI"). Where the
16
- // twin decides: it navigates to the flow's page, js.stripe.com/v3/financial-connections/{client_secret}
17
- // (screens/financial-connections.tsx), instead of a modal, so its promise does not settle; the flow returns the
18
- // holder to the session's return_url, where the application reads the session's accounts.
19
- // Demand: Dub's upgrade button (apps/web/ui/workspaces/upgrade-plan-button.tsx) creates a session on its server and
20
- // calls redirectToCheckout. Every other member of the library throws, naming itself, when called: an application
21
- // reaching one finds the gap instead of a silent no-op.
22
-
23
- /** The release train a script path names: `/v3`, `/v3/` or `/v3/stripe.js` → 3, `/<train>/stripe.js` → the train. */
24
- export function stripeJsTrain(pathname: string): 3 | string | undefined {
25
- if (/^\/v3(\/|\/stripe\.js)?$/.test(pathname)) return 3;
26
- return /^\/([a-z]+)\/stripe\.js$/.exec(pathname)?.[1];
27
- }
28
-
29
- function script(version: 3 | string): string {
30
- return `(function () {
31
- var version = ${JSON.stringify(version)};
32
- function gap(name) {
33
- return function () { throw new Error("Stripe.js (Volter twin): stripe." + name + " is not modelled by this twin yet"); };
34
- }
35
- function Stripe(publishableKey) {
36
- if (typeof publishableKey !== "string" || !publishableKey) throw new Error("Stripe.js (Volter twin): Stripe() needs a publishable key");
37
- var known = {
38
- _registerWrapper: function () {},
39
- redirectToCheckout: function (options) {
40
- if (!options || typeof options.sessionId !== "string" || !options.sessionId) return gap("redirectToCheckout without a sessionId")();
41
- window.location.assign("https://checkout.stripe.com/c/pay/" + encodeURIComponent(options.sessionId));
42
- return new Promise(function () {});
43
- },
44
- collectFinancialConnectionsAccounts: function (options) {
45
- if (!options || typeof options.clientSecret !== "string" || !options.clientSecret) return gap("collectFinancialConnectionsAccounts without a clientSecret")();
46
- window.location.assign("https://js.stripe.com/v3/financial-connections/" + encodeURIComponent(options.clientSecret));
47
- return new Promise(function () {});
48
- }
49
- };
50
- return new Proxy(known, {
51
- get: function (target, name) {
52
- if (name in target) return target[name];
53
- if (typeof name === "symbol" || name === "then") return undefined;
54
- return gap(String(name));
55
- }
56
- });
57
- }
58
- Stripe.version = version;
59
- window.Stripe = Stripe;
60
- })();
61
- `;
62
- }
63
-
64
- /** js.stripe.com's script for a GET of its path, or undefined for any other request. */
65
- export function stripeJs(request: Request): Response | undefined {
66
- if (request.method !== 'GET') return undefined;
67
- const train = stripeJsTrain(new URL(request.url).pathname);
68
- if (train === undefined) return undefined;
69
- return new Response(script(train), { headers: { 'content-type': 'application/javascript; charset=utf-8', 'access-control-allow-origin': '*' } });
70
- }
@@ -1,90 +0,0 @@
1
- // The Stripe Dashboard (manifest screen `dashboard`, dashboard.stripe.com/test/{section}): a React app
2
- // (Bun-bundled) served beside the twin. A PURE FRONTEND (runtime contract R3): this module is the shell, its
3
- // assets and one listener that mounts the pack's OWN fetch adapter beside them. It imports no handler and no
4
- // twin internals; the client reads and writes only through Stripe's API (`/v1/...`, client/dashboard-api.ts),
5
- // so it renders a twin or a real account's test data unchanged, pointed at any origin by configuration.
6
- import { readFile } from 'node:fs/promises';
7
- import { bundleClient, fileResponse, filePathOf } from '@volter/world-core';
8
- import { serveHttp } from '@volter/world-core';
9
- import { createStripeTwinFetch } from './stripe-server.ts';
10
-
11
- const CLIENT_ENTRY = () => filePathOf(new URL('../client/stripe-mirror.tsx', import.meta.url)); // lazy: workerd rejects top-level relative URL from import.meta.url (bundled via pack index)
12
- const CLIENT_CSS = () => filePathOf(new URL('../client/stripe-mirror.css', import.meta.url)); // lazy: workerd rejects top-level relative URL from import.meta.url (bundled via pack index)
13
-
14
- // ---------------------------------------------------------------------------
15
- // Pure, dependency-free render/format/resolution helpers.
16
- //
17
- // These are intentionally framework-agnostic (plain data in → plain data out) so
18
- // they can be unit-tested in isolation AND imported by the React/TSX client
19
- // (Bun tree-shakes the server-only exports below out of the browser bundle).
20
- // Keep them free of any `@volter/world-core`/`Bun`/twin-adapter usage.
21
- // ---------------------------------------------------------------------------
22
-
23
- export * from './stripe-shared.ts';
24
- import { flattenStripeValue, resolveCrossRefs, type CrossRefs, type FlatLine, type StripeRow } from './stripe-shared.ts';
25
- void flattenStripeValue; void resolveCrossRefs;
26
-
27
- const APP_SHELL = `<!doctype html>
28
- <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
29
- <base href="/"><title>Dashboard – Stripe</title><link rel="stylesheet" href="assets/styles.css"></head>
30
- <body><div id="root"></div><script type="module" src="assets/app.js"></script></body></html>`;
31
- let clientBundle: Promise<string> | null = null;
32
-
33
- /** Build the React/TSX dashboard client to browser JS (Bun bundles TSX); cached. */
34
- export function buildStripeMirrorClient(): Promise<string> {
35
- if (!clientBundle) {
36
- clientBundle = bundleClient(CLIENT_ENTRY())
37
- .catch((error) => { clientBundle = null; throw error; });
38
- }
39
- return clientBundle;
40
- }
41
-
42
- /** Serve the Stripe Dashboard (React app) with the twin's own fetch adapter mounted beside it. */
43
- export async function createStripeMirrorServer(options: { root?: string; port?: number }): Promise<{ port: number; stop: () => void }> {
44
- const twin = createStripeTwinFetch(options);
45
- const server = await serveHttp({
46
- // LOOPBACK-SPECIFIC bind (2026-08-20, the roving ui-verify flake): with the default
47
- // wildcard hostname, `port: 0` can be handed a port some long-running app already LISTENS
48
- // on at 127.0.0.1 (SO_REUSEADDR allows the overlapping non-identical bind), and the more
49
- // specific loopback listener then shadows this server for every 127.0.0.1 fetch — the
50
- // verify talks to a STRANGER (captured: a desktop app's asset server answering 404s on the
51
- // mirror's port). Binding 127.0.0.1 makes the kernel allocate a port that is actually free
52
- // on loopback, so the verify's fetches deterministically reach THIS server.
53
- hostname: '127.0.0.1',
54
- port: options.port ?? 0,
55
- idleTimeout: 60,
56
- async fetch(request) {
57
- const url = new URL(request.url);
58
- if (request.method === 'GET' && url.pathname === '/assets/app.js') {
59
- try { return new Response(await buildStripeMirrorClient(), { headers: { 'content-type': 'text/javascript; charset=utf-8' } }); }
60
- catch (error) { return new Response(String(error), { status: 500 }); }
61
- }
62
- if (request.method === 'GET' && url.pathname === '/assets/styles.css') {
63
- return fileResponse(CLIENT_CSS(), { headers: { 'content-type': 'text/css; charset=utf-8' } });
64
- }
65
- // the Dashboard's own paths (/test/payments, /test/customers/cus_…) are the app; `/` opens Home
66
- if (request.method === 'GET' && (url.pathname === '/' || url.pathname === '' || url.pathname === '/test' || url.pathname.startsWith('/test/'))) {
67
- return new Response(APP_SHELL, { headers: { 'content-type': 'text/html; charset=utf-8' } });
68
- }
69
- // everything else → the twin's OWN FETCH ADAPTER (composition, R2): the React client fetches
70
- // the vendor's real paths (/v1/<collection>) and this is the same closure
71
- // `createStripeTwinServer` mounts, so there is exactly ONE serving code path — the `/twin`
72
- // manifest door, the form-encoded body passed through byte-for-byte, the Idempotency-Key /
73
- // Stripe-Version / Stripe-Account threading, the `request-id` response header, the world
74
- // clock and an honorable `readOnly` all come from it, and the mirror port cannot drift from
75
- // the API port.
76
- return twin(request);
77
- },
78
- });
79
- return { port: server.port ?? options.port ?? 0, stop: () => server.stop(true) };
80
- }
81
-
82
- /** The app-shell HTML (pure, for tests). The Dashboard itself is the React client. */
83
- export function stripeMirrorHtml(): string {
84
- return APP_SHELL;
85
- }
86
-
87
- /** The mirror's stylesheet, for a host serving the shell's `assets/styles.css` itself (the hosted mirror mount). */
88
- export function stripeMirrorStyles(): Promise<string> {
89
- return readFile(CLIENT_CSS(), 'utf8');
90
- }
@@ -1,29 +0,0 @@
1
- // A MINIATURE OF THE HEAD, for this pack's own claims and suites (protocol 2). The kernel's loop
2
- // (`performEntries`) needs a bound root and a sealed credential a unit test does not have; this is the same
3
- // shape without one — the same `deployableEntries`, the pack's own push, the same `confirmAction`. Not on
4
- // the serve path, not exported from the pack.
5
- import { confirmAction, deployableEntries, worldNow } from '@volter/world-core';
6
- import { INTERNAL_SUBJECT_TYPES, isPushable, pushStripeAction, type StripeExecute } from './stripe-connector.ts';
7
-
8
- export async function performPending(
9
- execute: StripeExecute,
10
- opts: { root?: string; occurredAt: string },
11
- ): Promise<{ pushed: number; confirmed: string[]; externalIds: Record<string, string> }> {
12
- const confirmed: string[] = [];
13
- const externalIds: Record<string, string> = {};
14
- for (const entry of deployableEntries('stripe', opts.root)) {
15
- const op = entry.operation ?? `${entry.subject.type}.update`;
16
- // the twin's own records — the recorded event envelopes and the idempotency bookkeeping — are local
17
- // state and are never sent
18
- if (INTERNAL_SUBJECT_TYPES.has(entry.subject.type) || !isPushable(op)) continue;
19
- const { externalId } = await pushStripeAction(execute, { operation: op, subject: entry.subject, fields: entry.fields ?? {} });
20
- confirmAction({
21
- service: 'stripe', actionId: entry.id, subject: entry.subject, fields: entry.fields ?? {},
22
- occurredAt: opts.occurredAt ?? worldNow(), vendorSubjectId: externalId, receipt: { status: 'deployed' },
23
- ...(opts.root !== undefined ? { root: opts.root } : {}),
24
- });
25
- confirmed.push(entry.id);
26
- externalIds[entry.id] = externalId;
27
- }
28
- return { pushed: confirmed.length, confirmed, externalIds };
29
- }
@@ -1,393 +0,0 @@
1
- // Stripe twin HTTP server — serve the full Stripe twin handler over HTTP so the
2
- // real `stripe` SDK ({host,port,protocol}) works unmodified (R1), or route the QA
3
- // backend sandbox's api.stripe.com interception at it. Form-encoded bodies (what
4
- // the SDK sends) pass through to the handler. Writable by default (the local stack
5
- // uses the twin as its authoritative Stripe); pass readOnly to reject writes (R4).
6
- //
7
- // The surface is a plain `fetch` (`createStripeTwinFetch`) and the SERVER is one line of
8
- // `Bun.serve` around it — see that factory's docstring for why (a serverless entry has no
9
- // port to bind, so it mounts the fetch in-process).
10
- import { bindSemantics, coreFor, createDerivedFetch, crossCutting, derivedRequestScopes, readParams, runAsVendorMove, runWithRequestTrace, semanticsContext, serveHttp, vendorError, type DerivedCall, type DerivedFetch } from '@volter/world-core';
11
- import { stripeCheckoutFlow } from './screens/checkout.tsx';
12
- import { stripeJs } from './stripe-js.ts';
13
- import { stripeFinancialConnectionsFlow } from './screens/financial-connections.tsx';
14
- import { stripeIdentityFlow } from './screens/identity.tsx';
15
- import { stripeOnboardingFlow } from './screens/onboarding.tsx';
16
- import { stripePortalFlow } from './screens/portal.tsx';
17
- import { stripePublicDetailsFlow } from './screens/public-details.tsx';
18
- import { connectionRevoked, oauthKeyAccount, redactKey, stripeConnectOAuthFlow } from './screens/connect-oauth.tsx';
19
- import { stripeConnectSettingsFlow } from './screens/connect-settings.tsx';
20
- import surface from './generated/surface.gen.json' with { type: 'json' };
21
- import { manifest } from './manifest.ts';
22
- import { appsSecrets } from './semantics/apps-secrets.ts';
23
- import { balances } from './semantics/balance.ts';
24
- import { billing } from './semantics/billing.ts';
25
- import { charges } from './semantics/charges.ts';
26
- import { checkout } from './semantics/checkout.ts';
27
- import { connect } from './semantics/connect.ts';
28
- import { coupons } from './semantics/coupons.ts';
29
- import { creditNotes } from './semantics/credit-notes.ts';
30
- import { customers } from './semantics/customers.ts';
31
- import { disputes } from './semantics/disputes.ts';
32
- import { entitlements } from './semantics/entitlements.ts';
33
- import { ephemeralKeys } from './semantics/ephemeral-keys.ts';
34
- import { files } from './semantics/files.ts';
35
- import { invoices } from './semantics/invoices.ts';
36
- import { issuing, lapseRealtimeRequests } from './semantics/issuing.ts';
37
- import { paymentIntents } from './semantics/payment-intents.ts';
38
- import { paymentLinks } from './semantics/payment-links.ts';
39
- import { paymentMethods } from './semantics/payment-methods.ts';
40
- import { platform } from './semantics/platform.ts';
41
- import { plans } from './semantics/plans.ts';
42
- import { products } from './semantics/products.ts';
43
- import { radar } from './semantics/radar.ts';
44
- import { refunds } from './semantics/refunds.ts';
45
- import { setupIntents } from './semantics/setup-intents.ts';
46
- import { subscriptionSchedules } from './semantics/subscription-schedules.ts';
47
- import { subscriptions } from './semantics/subscriptions.ts';
48
- import { tax } from './semantics/tax.ts';
49
- import { terminal } from './semantics/terminal.ts';
50
- import { testClocks } from './semantics/test-clocks.ts';
51
- import { ledger } from './semantics/ledger.ts';
52
- import { tokens } from './semantics/tokens.ts';
53
- import { transfers } from './semantics/transfers.ts';
54
- import { treasury } from './semantics/treasury.ts';
55
- import { webhookEndpoints } from './semantics/webhook-endpoints.ts';
56
- import { advancePayouts, balanceBody, payDuePayouts } from './semantics/balance.ts';
57
- import { settleDueEntries } from './semantics/ledger.ts';
58
- import { settleHeldRefunds } from './semantics/refunds.ts';
59
- import { settleBankDebits } from './semantics/payment-intents.ts';
60
- import { lapseCoupons } from './semantics/coupons.ts';
61
- import { finishClockAdvances } from './semantics/test-clocks.ts';
62
- import { settleTopups } from './semantics/terminal.ts';
63
- import { finishReportRuns } from './semantics/platform.ts';
64
- import { advanceBilling } from './semantics/renewals.ts';
65
- import { refuseParameters } from './stripe-params.ts';
66
- import { afterStripeWrite, handleStripeDoor, PLATFORM_ACCOUNT_ID } from './stripe-twin.ts';
67
- import { worldNow, statefulTwinManifest} from '@volter/world-core';
68
- import { expandOf, render, servesCurrent, withoutEndpointSecret } from './stripe-version.ts';
69
-
70
- /** Options shared by the fetch handler and the Bun.serve wrapper around it. `port` is a
71
- * BIND concern the fetch ignores; it stays in one shape so a caller configures the twin
72
- * once whichever way it is mounted. */
73
- export type StripeTwinOptions = { root?: string; port?: number; readOnly?: boolean; /** the World instant, when a caller pins it */ clock?: () => string };
74
-
75
- // ── what a publishable key may call ──
76
- // "Publishable API key pk_... | Safe to expose: Yes | API key for Stripe.js, Elements, and mobile SDKs. It can identify
77
- // your account and create tokens or PaymentMethods from payment details, but it can't perform sensitive operations such
78
- // as creating charges or reading account data" (docs.stripe.com/keys). The served spec names the calls a publishable key
79
- // makes with an object's client secret: "You can retrieve a PaymentIntent client-side using a publishable key when the
80
- // client_secret is provided in the query string" (GET /v1/payment_intents/{intent}), "Client-side retrieval using a
81
- // publishable key is allowed when the client_secret is provided" (GET /v1/setup_intents/{intent}), "Required if a
82
- // publishable key is used to retrieve the source" (GET /v1/sources/{source}), and the confirm and verify_microdeposits
83
- // calls that take "The client secret of the PaymentIntent" (or SetupIntent). Anything else is refused with Stripe's
84
- // code: "secret_key_required | The API key provided is a publishable key, but a secret key is required"
85
- // (docs.stripe.com/error-codes), as 403, "The API key doesn't have permissions to perform the request"
86
- // (docs.stripe.com/api/errors).
87
- // Where the documentation stops and the twin decides: the list above is the whole of what a publishable key may call
88
- // (Stripe publishes no complete list); a client-secret call without the secret answers parameter_missing, and one with a
89
- // secret that is not the object's answers the object's 404, as though the key could not see it.
90
- const PUBLISHABLE_CREATES = new Set(['PostTokens', 'PostPaymentMethods']);
91
- const BY_CLIENT_SECRET: Record<string, { type: string; param: string }> = {
92
- GetPaymentIntentsIntent: { type: 'payment_intent', param: 'intent' },
93
- PostPaymentIntentsIntentConfirm: { type: 'payment_intent', param: 'intent' },
94
- PostPaymentIntentsIntentVerifyMicrodeposits: { type: 'payment_intent', param: 'intent' },
95
- GetSetupIntentsIntent: { type: 'setup_intent', param: 'intent' },
96
- PostSetupIntentsIntentConfirm: { type: 'setup_intent', param: 'intent' },
97
- PostSetupIntentsIntentVerifyMicrodeposits: { type: 'setup_intent', param: 'intent' },
98
- GetSourcesSource: { type: 'source', param: 'source' },
99
- };
100
-
101
- /** Stripe's refusal of a call a publishable key may not make, or undefined when the key may make it. */
102
- async function publishableKeyRefused(call: DerivedCall, scope: { root?: string; clock?: () => string }): Promise<Response | undefined> {
103
- const key = /^bearer\s+(\S+)/i.exec(call.request.headers.get('authorization') ?? '')?.[1] ?? '';
104
- if (!key.startsWith('pk_')) return undefined;
105
- if (PUBLISHABLE_CREATES.has(call.operation.id)) return undefined;
106
- const scoped = BY_CLIENT_SECRET[call.operation.id];
107
- if (!scoped) return vendorError(manifest, { status: 403, code: 'secret_key_required', message: 'The API key provided is a publishable key, but a secret key is required.' });
108
- const params = await readParams(manifest, call.request.clone(), call.operation);
109
- const secret = typeof params.client_secret === 'string' ? params.client_secret : '';
110
- if (!secret) return vendorError(manifest, { status: 400, code: 'parameter_missing', param: 'client_secret', message: 'Missing required param: client_secret.' });
111
- const id = call.params[scoped.param] ?? '';
112
- // the context reads a body of its own, so the handler after this still has the request's
113
- const ctx = await semanticsContext(manifest, call.request.clone(), call.operation, scope);
114
- return ctx.get(scoped.type, id)?.client_secret === secret ? undefined : wrongClientSecret(scoped, id);
115
- }
116
-
117
- // ── an account whose OAuth connection was revoked ──
118
- // "After revocation, the account can't be accessed by your platform in the Dashboard or through the API"
119
- // (docs.stripe.com/connect/oauth-reference, deauthorize; so too a connection revoked by a reused code). A call made as it
120
- // (the Stripe-Account header) or naming it (/v1/accounts/{account}…) is refused with the error Stripe documents for a
121
- // Stripe-Account the key cannot use: "account_invalid | The account ID provided as a value for the Stripe-Account header
122
- // is invalid" (docs.stripe.com/error-codes), as 403, "The API key doesn't have permissions to perform the request"
123
- // (docs.stripe.com/api/errors). Where the documentation stops and the twin decides: the message's wording; an account
124
- // the platform created itself, or never connected by OAuth, is not affected.
125
- async function revokedAccountRefused(call: DerivedCall, scope: { root?: string; clock?: () => string }): Promise<Response | undefined> {
126
- const named = [call.request.headers.get('stripe-account') ?? undefined, call.operation.path.startsWith('/v1/accounts/{account}') ? call.params.account : undefined].filter((a): a is string => !!a);
127
- if (!named.length) return undefined;
128
- const ctx = await semanticsContext(manifest, new Request(call.request.url), call.operation, scope); // the rows only: no body read
129
- const revoked = named.find((a) => connectionRevoked(ctx, a));
130
- if (!revoked) return undefined;
131
- const key = requestKey(call.request);
132
- return vendorError(manifest, { status: 403, code: 'account_invalid', message: `The provided key '${redactKey(key)}' does not have access to account '${revoked}' (or that account does not exist). Application access may have been revoked.` });
133
- }
134
-
135
- /** The API key a request carries: Bearer, or Basic's user (`curl -u sk_…:`, docs.stripe.com/api/authentication). */
136
- function requestKey(request: Request): string {
137
- const header = request.headers.get('authorization') ?? '';
138
- const bearer = /^bearer\s+(\S+)/i.exec(header)?.[1];
139
- if (bearer) return bearer;
140
- const basic = /^basic\s+(\S+)/i.exec(header)?.[1];
141
- if (basic) { try { return atob(basic).split(':')[0] ?? ''; } catch { return ''; } }
142
- return '';
143
- }
144
-
145
- /** A client-secret call whose secret is not the object's: answered as though the key could not see it (the twin's
146
- * decision, above). */
147
- function wrongClientSecret(scoped: { type: string; param: string }, id: string): Response {
148
- return vendorError(manifest, { status: 404, code: 'resource_missing', param: scoped.param, message: `No such ${scoped.type}: '${id}'` });
149
- }
150
-
151
- /**
152
- * The whole Stripe serve path as a plain `(Request) => Response` — the `/twin` manifest
153
- * door, the header threading (idempotency key, pinned API version, Connect account) and
154
- * the derived dispatch over the hand-written routes. NOTHING about it is port-bound.
155
- *
156
- * Why this is the factory and `createStripeTwinServer` is a wrapper (runtime contract R12,
157
- * the Cloudflare ruling): a Durable Object / Worker entry has no loopback ports — it mounts
158
- * pack fetches IN-PROCESS behind one router. Handing that entry `Bun.serve` is not an
159
- * option, so the vendor HTTP adaptation has to be a value it can call. Keeping the server a
160
- * thin `Bun.serve(fetch)` also means the local and hosted lanes execute the SAME bytes of
161
- * serving code — the parity claim (R9) is about one code path, not two that resemble each
162
- * other.
163
- *
164
- * SCOPING THE STORES AROUND IT: this fetch is ASYNC, so install the world store with
165
- * `setActiveWorldStore(store)` in a try/finally — **not** `withWorldStore(store, fn)`, whose
166
- * `finally` fires when `fn` RETURNS, i.e. at the first `await`, restoring the previous store
167
- * under the rest of the request.
168
- */
169
- export function createStripeTwinFetch(options: StripeTwinOptions): DerivedFetch {
170
- const readOnly = options.readOnly ?? false;
171
- const scope = { ...(options.root !== undefined ? { root: options.root } : {}), ...(options.clock ? { clock: options.clock } : {}) };
172
- // The derived dispatch owns the API: an operation with a semantics handler is served by it, one on a
173
- // resource the manifest declares by the derived core, and one neither models answers Stripe's
174
- // unrecognized-URL 404.
175
- const guard = crossCutting(manifest, { readOnly, ...scope });
176
- const handlerMap = { ...billing, ...paymentIntents, ...customers, ...products, ...plans, ...charges, ...refunds, ...setupIntents, ...paymentMethods, ...subscriptions, ...invoices, ...checkout, ...ephemeralKeys, ...disputes, ...balances, ...coupons, ...creditNotes, ...subscriptionSchedules, ...entitlements, ...testClocks, ...webhookEndpoints, ...connect, ...transfers, ...appsSecrets, ...tokens, ...files, ...tax, ...paymentLinks, ...radar, ...issuing, ...terminal, ...treasury, ...platform, ...ledger };
177
- const core = coreFor(manifest, scope);
178
- const derived = createDerivedFetch({
179
- surface,
180
- handlers: bindSemantics(manifest, handlerMap, scope),
181
- core,
182
- // after the credential and the version, a publishable key is held to the client-side calls, then a request's
183
- // parameters are checked against the operation's (stripe-params.ts)
184
- around: (call, next) => guard(call, async () => (await publishableKeyRefused(call, scope)) ?? (await revokedAccountRefused(call, scope)) ?? (await refuseParameters(call)) ?? next()),
185
- gap: (request) => vendorError(manifest, { status: 404, message: `Unrecognized request URL (${request.method}: ${new URL(request.url).pathname}).` }),
186
- });
187
- // the hosted flows sit beside the API: checkout.stripe.com's payment page, billing.stripe.com's customer portal,
188
- // connect.stripe.com's onboarding and its OAuth endpoints (screens/connect-oauth.tsx), verify.stripe.com's identity
189
- // check and the bank-linking flow Stripe.js opens, and the Dashboard's Public details page
190
- // (dashboard.stripe.com/settings/public, the platform's customer-facing name) and Connect OAuth settings
191
- // (dashboard.stripe.com/settings/connect/onboarding-options/oauth: the client_id, OAuth on, the redirect URIs);
192
- // a read-only twin takes no payments and moves nothing
193
- const flows = [stripeCheckoutFlow(scope), stripePortalFlow(scope), stripeOnboardingFlow(scope), stripeIdentityFlow(scope), stripeFinancialConnectionsFlow(scope), stripePublicDetailsFlow(scope), stripeConnectOAuthFlow(scope), stripeConnectSettingsFlow(scope)];
194
- // the twin's own doors sit in front of the API: discovery, and what stands in for an act Stripe's API
195
- // does not have (stripe-twin.ts)
196
- // GET /twin: what this twin is (not Stripe's; a host reads it)
197
- function discovery(): Response {
198
- return Response.json(statefulTwinManifest({ vendor: 'stripe', twinOf: 'the Stripe REST API', stores: 'customers, payment objects, checkout sessions, products/prices and webhook endpoints (signed events)' }));
199
- }
200
- // /_twin/…: a door's body is read as the API's is: a form, or JSON
201
- const twinDoor = async (request: Request, url: URL): Promise<Response | undefined> => {
202
- const answer = await handleStripeDoor({
203
- method: request.method, path: url.pathname, readOnly,
204
- occurredAt: options.clock ? options.clock() : worldNow(),
205
- ...(options.root !== undefined ? { root: options.root } : {}),
206
- }, await readParams(manifest, request));
207
- return answer && Response.json(answer.body, { status: answer.status, headers: { 'request-id': 'req_twin' } });
208
- };
209
- const door = async (request: Request): Promise<Response | undefined> => {
210
- const url = new URL(request.url);
211
- if (request.method === 'GET' && url.pathname.replace(/\/+$/, '') === '/twin') return discovery();
212
- return url.pathname.startsWith('/_twin/') ? twinDoor(request, url) : undefined;
213
- };
214
- // time's moves Stripe makes on its own (a subscription renewing at its period's end, its renewal charged an hour
215
- // later: semantics/renewals.ts; each account's automatic payouts: semantics/balance.ts) are caught up to the World's clock before anything is answered, so every door
216
- // (the API, the hosted pages) reads the account as it stands now
217
- const billingClock = (surface.operations as Array<{ id: string; method: string; path: string; class: string }>).find((o) => o.id === 'GetSubscriptions')!;
218
- // time's moves are Stripe's own, not the caller's: they land under a read-only request too (runAsVendorMove)
219
- const catchUp = async (request: Request): Promise<void> => {
220
- if (readOnly) return;
221
- await runAsVendorMove(async () => {
222
- const ctx = await semanticsContext(manifest, new Request(request.url), billingClock, scope);
223
- // a test clock advanced by the last request has reached its time (semantics/test-clocks.ts)
224
- await finishClockAdvances(ctx);
225
- await advanceBilling(ctx);
226
- // a submitted bank debit settles (in test mode at once) before anything is answered (semantics/payment-intents.ts)
227
- await settleBankDebits(ctx);
228
- // a coupon past its redeem_by is no longer valid (semantics/coupons.ts)
229
- await lapseCoupons(ctx);
230
- // a top-up's funds arrive five days after it is made (semantics/terminal.ts)
231
- await settleTopups(ctx);
232
- // a report run completes (semantics/platform.ts)
233
- await finishReportRuns(ctx);
234
- // a real-time authorization request no one answered is decided when its window ends (semantics/issuing.ts)
235
- await lapseRealtimeRequests(ctx);
236
- // a refund held for want of balance is made when funds cover it, before any payout takes them (semantics/refunds.ts)
237
- await settleHeldRefunds(ctx);
238
- await advancePayouts(ctx);
239
- });
240
- };
241
- // Time's EVENTS, sent on the vendor's clock through a twin-only drain door, as the qstash and vercel twins send
242
- // theirs (a caller — a runner's drainer — drives each move). POST /_twin/drain catches time up as every request
243
- // does, then writes what time settled on each account: payouts whose arrival date came (pending → paid, sent as
244
- // payout.paid) and funds that came due (pending → available), for which the account is sent one balance.available
245
- // ("Occurs whenever your Stripe balance has been updated (e.g., when a charge is available to be paid out)",
246
- // docs.stripe.com/api/events/types) carrying its Balance, when an entry that settled adds to it ("This event is not
247
- // fired for negative transactions", the same page); a connected account's events go to Connect endpoints.
248
- // A read already sees these moves; the drain is what makes Stripe's events about them arrive. Answers what it sent.
249
- const drain = async (request: Request): Promise<Response> => {
250
- if (readOnly) return Response.json({ error: 'twin is read-only; omit readOnly to accept writes' }, { status: 405 });
251
- await catchUp(request);
252
- const at = (account?: string) => semanticsContext(manifest, new Request(request.url, account ? { headers: { 'stripe-account': account } } : {}), billingClock, scope);
253
- const platformCtx = await at();
254
- const accounts = [undefined, ...platformCtx.rows('account').map((a) => String(a.id)).filter((id) => id !== PLATFORM_ACCOUNT_ID)];
255
- const delivered: Array<{ type: string; id?: string; account?: string }> = [];
256
- for (const account of accounts) {
257
- const ctx = account ? await at(account) : platformCtx;
258
- for (const id of await payDuePayouts(ctx)) delivered.push({ type: 'payout.paid', id, ...(account ? { account } : {}) });
259
- if ((await settleDueEntries(ctx)).some((t) => Number(t.net) > 0)) {
260
- await afterStripeWrite('balance', 'balance.available', balanceBody(ctx), options.root, ctx.occurredAt, undefined, account);
261
- delivered.push({ type: 'balance.available', ...(account ? { account } : {}) });
262
- }
263
- }
264
- return Response.json({ delivered });
265
- };
266
- const served = async (request: Request): Promise<Response> => {
267
- if (request.method === 'POST' && new URL(request.url).pathname.replace(/\/+$/, '') === '/_twin/drain') return drain(request);
268
- const opened = await door(request);
269
- if (opened) return opened;
270
- // the client library an application's page loads from js.stripe.com (stripe-js.ts); it moves nothing, so a
271
- // read-only twin serves it too
272
- const library = stripeJs(request);
273
- if (library) return library;
274
- await catchUp(request);
275
- if (!readOnly) for (const flow of flows) { const page = await flow(request); if (page) return page; }
276
- const acting = await actingAsOAuthKey(request);
277
- if (acting instanceof Response) return acting;
278
- // an update's metadata is merged into what the object holds before the handler or the core serves it (mergeMetadata)
279
- return derived(readOnly ? acting : await mergeMetadata(acting, (op) => !(op.id in handlerMap) && core.owns(op), scope));
280
- };
281
- // A connected account's OAuth keys (screens/connect-oauth.tsx): the token endpoint's access_token is "Use the
282
- // Stripe-Account header with your platform's secret key (that can make requests on behalf of this Stripe account)" and
283
- // its stripe_publishable_key the same with the publishable key (docs.stripe.com/connect/oauth-reference): a request made
284
- // with one acts as that account, as a request with the Stripe-Account header does. A key no live connection holds (its
285
- // connection revoked, or replaced by a refresh: "Any existing access token with the same scope and mode ... is
286
- // revoked") is Stripe's unknown key, 401 "Invalid API Key provided" (docs.stripe.com/api/authentication, docs.stripe.com
287
- // /error-codes); one sent with a Stripe-Account header naming another account cannot act as it (account_invalid).
288
- // Where the documentation stops and the twin decides: the messages' wording; a read_only key is not held to reads
289
- // (manifest todo stripe.connect.oauth_scope_enforcement).
290
- const actingAsOAuthKey = async (request: Request): Promise<Request | Response> => {
291
- const key = requestKey(request);
292
- if (!/^(sk|pk)_test_oauth_/.test(key)) return request;
293
- const held = oauthKeyAccount(await semanticsContext(manifest, new Request(request.url), billingClock, scope), key);
294
- if (!held) return vendorError(manifest, { status: 401, message: `Invalid API Key provided: ${redactKey(key)}` });
295
- const named = request.headers.get('stripe-account');
296
- if (named && named !== held.account) return vendorError(manifest, { status: 403, code: 'account_invalid', message: `The provided key '${redactKey(key)}' does not have access to account '${named}' (or that account does not exist). Application access may have been revoked.` });
297
- const headers = new Headers(request.headers);
298
- headers.set('stripe-account', held.account);
299
- const bodied = request.method !== 'GET' && request.method !== 'HEAD';
300
- return new Request(request.url, { method: request.method, headers, ...(bodied ? { body: await request.arrayBuffer() } : {}) });
301
- };
302
- // every answer in the shape of the API version the caller is served (stripe-version.ts)
303
- const rendered = async (request: Request): Promise<Response> => {
304
- const expand = expandOf(request.clone());
305
- const creates = request.method === 'POST' && new URL(request.url).pathname.replace(/\/+$/, '') === '/v1/webhook_endpoints';
306
- const res = await served(request);
307
- const pinned = request.headers.get('stripe-version');
308
- if (!(res.headers.get('content-type') ?? '').includes('json')) return res;
309
- if (!servesCurrent(pinned) && creates) return res;
310
- const body = await res.json();
311
- // a webhook endpoint's `secret` is "Only returned at creation" (docs.stripe.com/api/webhook_endpoints/object)
312
- const answered = creates ? body : withoutEndpointSecret(body);
313
- return new Response(JSON.stringify(servesCurrent(pinned) ? render(answered, pinned, await expand) : answered), { status: res.status, statusText: res.statusText, headers: res.headers });
314
- };
315
- // the request's W3C trace context scopes every door (the API, the hosted flows, the drain): their writes record it and
316
- // the webhooks they cause continue it (world-core trace-context)
317
- // a read-only request (x-volter-read-only) writes nothing, answered with Stripe's read-only error
318
- return derivedRequestScopes(manifest, Object.assign((request: Request) => runWithRequestTrace(request, () => rendered(request)), { owners: derived.owners }));
319
- }
320
-
321
- export async function createStripeTwinServer(options: StripeTwinOptions): Promise<{ port: number; stop: () => void }> {
322
- const server = await serveHttp({
323
- port: options.port ?? 0,
324
- idleTimeout: 60,
325
- fetch: createStripeTwinFetch(options),
326
- });
327
- return { port: server.port ?? options.port ?? 0, stop: () => server.stop(true) };
328
- }
329
-
330
- /** A create's `metadata` holds no key posted empty. "Individual keys can be unset by posting an empty value to them. All
331
- * keys can be unset by posting an empty value to `metadata`" (every metadata parameter of docs.stripe.com/api): an empty
332
- * value is the absence of the key, on a create as on an update, so an object never holds a key set to "". Clients post
333
- * one without meaning to: stripe-node encodes a `null` value as `metadata[key]=` (Cal.com's PaymentIntent metadata
334
- * carries `bookerPhoneNumber: null` for a guest who gave no phone). The request is rewritten as JSON without them. */
335
- async function createMetadata(request: Request, path: string): Promise<Request> {
336
- const op = CREATES.find((c) => c.re.test(path))?.op;
337
- if (!op) return request;
338
- const params = await readParams(manifest, request.clone(), op);
339
- if (!('metadata' in params)) return request;
340
- const given = params.metadata;
341
- let metadata: Record<string, unknown>;
342
- if (given === '') metadata = {};
343
- else if (given && typeof given === 'object' && !Array.isArray(given) && Object.values(given).includes('')) {
344
- metadata = Object.fromEntries(Object.entries(given as Record<string, unknown>).filter(([, v]) => v !== ''));
345
- } else return request;
346
- const headers = new Headers(request.headers);
347
- headers.set('content-type', 'application/json');
348
- return new Request(request.url, { method: request.method, headers, body: JSON.stringify({ ...params, metadata }) });
349
- }
350
-
351
- // the create operations, by their path as a pattern, for createMetadata
352
- const CREATES = (surface.operations as Array<DerivedCall['operation']>).filter((o) => o.class === 'create' && o.method.toUpperCase() === 'POST')
353
- .map((op) => ({ op, re: new RegExp(`^${op.path.replace(/[.*+?^$()|[\]\\]/g, '\\$&').replace(/\\\{[^}]+\\\}|\{[^}]+\}/g, '([^/]+)')}/?$`) }));
354
-
355
- // the update operations, by their path as a pattern, for mergeMetadata
356
- const UPDATES = (surface.operations as Array<DerivedCall['operation']>).filter((o) => o.class === 'update' && o.method.toUpperCase() === 'POST')
357
- .map((op) => ({ op, re: new RegExp(`^${op.path.replace(/[.*+?^$()|[\]\\]/g, '\\$&').replace(/\\\{[^}]+\\\}|\{[^}]+\}/g, '([^/]+)')}/?$`) }));
358
-
359
- /** An update's `metadata`, merged into what the object holds before anything serves the update. "This parameter uses a
360
- * merge mechanism, which allows you to add new key-value pairs to an object in an update call without affecting any
361
- * existing metadata"; "Pass in the key with an empty string as the value to remove the key from the metadata"; "Pass an
362
- * empty string as the value for the metadata attribute to delete all of the keys simultaneously"
363
- * (docs.stripe.com/metadata). The derived core already merges a nested hash where the manifest leaves `update` at
364
- * `merge` (dropping keys set to ""), so only a clear-all is rewritten for it; where a handler or a `replace` update
365
- * stores the request's metadata whole, the request is rewritten to carry the merged hash, so every door stores the same
366
- * answer. The request is rewritten as JSON (readParams reads either). */
367
- async function mergeMetadata(request: Request, coreMerges: (op: DerivedCall['operation']) => boolean, scope: { root?: string; clock?: () => string }): Promise<Request> {
368
- if (request.method !== 'POST' || (request.headers.get('content-type') ?? '').includes('multipart')) return request;
369
- const path = new URL(request.url).pathname;
370
- let op: DerivedCall['operation'] | undefined;
371
- let id = '';
372
- for (const u of UPDATES) { const m = u.re.exec(path); if (m) { op = u.op; id = decodeURIComponent(m.at(-1) ?? ''); break; } }
373
- if (!op) return createMetadata(request, path);
374
- if (!op.resource) return request;
375
- const params = await readParams(manifest, request.clone(), op);
376
- if (!('metadata' in params)) return request;
377
- const given = params.metadata;
378
- // a plan is kept as the recurring price it is (semantics/plans.ts)
379
- const resource = op.resource === 'plan' ? 'price' : op.resource;
380
- const ctx = await semanticsContext(manifest, request.clone(), op, scope);
381
- const held = ctx.get(resource, id)?.metadata;
382
- const prior = held && typeof held === 'object' ? (held as Record<string, unknown>) : {};
383
- const merges = coreMerges(op) && manifest.resources[resource]?.update !== 'replace';
384
- let metadata: Record<string, unknown>;
385
- if (given === '') metadata = merges ? Object.fromEntries(Object.keys(prior).map((k) => [k, ''])) : {};
386
- else if (given && typeof given === 'object' && !Array.isArray(given)) {
387
- if (merges) return request;
388
- metadata = Object.fromEntries(Object.entries({ ...prior, ...(given as Record<string, unknown>) }).filter(([, v]) => v !== ''));
389
- } else return request;
390
- const headers = new Headers(request.headers);
391
- headers.set('content-type', 'application/json');
392
- return new Request(request.url, { method: request.method, headers, body: JSON.stringify({ ...params, metadata }) });
393
- }