@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
@@ -1,28 +1,18 @@
1
- // Stripe twin REQUEST HANDLER — the canonical Stripe API surface for the twin and
2
- // the QA stack's authoritative Stripe (it replaced the old hand-made in-process
3
- // mock). Contract: handleStripeTwinRequest({method, path, body, mode}) -> {status,
4
- // body}. The whole point: this is backed by the event/action-log kernel and its
5
- // response SHAPES are conformant to real Stripe (see stripe-conformance), instead
6
- // of being invented — so the SDK/API call shapes the app relies on actually match
7
- // Stripe. HTTP wrapper: stripe-server.ts → createStripeTwinServer.
8
- //
9
- // State lives in the action log (R18): writes are local actions, reads are the
10
- // projection. No real Stripe is ever called.
11
- import { applyTwinWrite } from '@volter/world-core';
12
- import { projectResources } from '@volter/world-core';
13
- import { createStripeTwinFetch } from './stripe-server.ts';
14
- import { emitStripeEvent, eventTypeFor, type StripeWebhookTarget } from './stripe-events.ts';
15
- import { SERVED_VERSION } from './stripe-version.ts';
16
- import { planOf } from './semantics/plans.ts';
17
- import { platformAccountDefault } from './semantics/connect.ts';
18
- import { OAUTH_CONNECTIONS } from './stripe-shared.ts';
19
-
20
- const SERVICE = 'stripe';
1
+ // Stripe's own computation that its handlers share (docs/contributing/architecture.md, "Pack layout": the engine): money
2
+ // and its declines, 3-D Secure and micro-deposits, the list page and the search grammar, a subscription's items, billing
3
+ // intervals and discounts, Issuing's spending controls, a payment method's sub-object, a Connect account's settings and a
4
+ // Checkout Session's line items. None of it reads or writes state: a caller hands it what it looked up (FindStored).
5
+ import { ownFields, type TwinResource } from '@volter/world-core';
6
+ import { SERVED_VERSION } from './version.ts';
21
7
 
22
- export type StripeRequest = { method: string; path: string; body?: string; occurredAt?: string; root?: string; readOnly?: boolean; idempotencyKey?: string; apiVersion?: string; stripeAccount?: string };
23
8
  export type StripeResponse = { status: number; body: unknown };
24
9
 
25
- // The Stripe API version a request that pins none is served in: the vendored spec's (stripe-version.ts renders
10
+ /** Stripe's error body: an invalid_request_error with the message, and the code when there is one. */
11
+ export function err(message: string, status = 404, code?: string): StripeResponse {
12
+ return { status, body: { error: { type: 'invalid_request_error', message, ...(code ? { code } : {}) } } };
13
+ }
14
+
15
+ // The Stripe API version a request that pins none is served in: the vendored spec's (./version.ts renders
26
16
  // every answer in it). A request may override it via the `Stripe-Version` header (apiVersion);
27
17
  // the value is echoed onto every event the request produces, exactly like real Stripe,
28
18
  // whose stored Event.api_version reflects the version in force when the event was created.
@@ -34,63 +24,6 @@ export function isValidApiVersion(v: string): boolean {
34
24
  return API_VERSION_RE.test(v);
35
25
  }
36
26
 
37
- // resource type → id prefix (Stripe's conventions).
38
- const PREFIX: Record<string, string> = {
39
- charge: 'ch', customer: 'cus', payment_intent: 'pi', setup_intent: 'seti', payment_method: 'pm',
40
- subscription: 'sub', price: 'price', product: 'prod', invoice: 'in', invoiceitem: 'ii',
41
- refund: 're', verification_session: 'vs', ephemeral_key: 'ephkey', file_link: 'link',
42
- dispute: 'dp', payout: 'po', balance_transaction: 'txn', event: 'evt',
43
- checkout_session: 'cs', billing_portal_session: 'bps', billing_portal_configuration: 'bpc',
44
- account: 'acct', transfer: 'tr',
45
- tax_rate: 'txr', tax_calculation: 'taxcalc', tax_registration: 'taxreg',
46
- credit_note: 'cn', tax_id: 'txi', customer_balance_transaction: 'cbtxn',
47
- coupon: 'coupon', promotion_code: 'promo', payment_link: 'plink', quote: 'qt',
48
- webhook_endpoint: 'we',
49
- subscription_schedule: 'sub_sched', billing_meter: 'mtr', billing_meter_event: 'mtr_evt',
50
- usage_record: 'mbur', test_clock: 'clock',
51
- token: 'tok', mandate: 'mandate', application_fee: 'fee', fee_refund: 'fr',
52
- transfer_reversal: 'trr', account_link: 'acctlink', person: 'person',
53
- external_account: 'ba', file: 'file',
54
- subscription_item: 'si', tax_transaction: 'tax', radar_review: 'prv',
55
- radar_value_list: 'rsl', radar_value_list_item: 'rsli', radar_rule: 'rule',
56
- // Issuing family (vendor-faithful Stripe id prefixes).
57
- issuing_cardholder: 'ich', issuing_card: 'ic', issuing_authorization: 'iauth',
58
- issuing_transaction: 'ipi', issuing_dispute: 'idp',
59
- // Terminal family.
60
- terminal_location: 'tml', terminal_reader: 'tmr', terminal_configuration: 'tmc',
61
- // Top-ups, identity reports, reporting runs.
62
- topup: 'tu', verification_report: 'vr', report_run: 'frr',
63
- // Customer cash balance ledger + legacy sources.
64
- cash_balance_transaction: 'ccsbtxn', source: 'src',
65
- // Billing: prepaid credit grants + usage alerts.
66
- credit_grant: 'credgr', billing_alert: 'alert',
67
- // Entitlements: account-level features + per-customer active entitlements.
68
- entitlements_feature: 'feat', active_entitlement: 'ent',
69
- // Connect: embedded account sessions + apps secret store.
70
- account_session: 'accts', apps_secret: 'apmc',
71
- // Issuing: network tokens + card personalization designs.
72
- issuing_token: 'iss_tok', personalization_design: 'pd',
73
- // Treasury: financial accounts + money-movement flows + ledger.
74
- financial_account: 'fa',
75
- outbound_payment: 'obp', outbound_transfer: 'obt', inbound_transfer: 'ibt',
76
- received_credit: 'rc', received_debit: 'rd',
77
- treasury_transaction: 'trxn', treasury_transaction_entry: 'trxne',
78
- // Climate (carbon removal): orders. (products/suppliers are a fixed read-only catalog.)
79
- climate_order: 'climorder',
80
- // Financial Connections: sessions + linked accounts + account transactions.
81
- fc_session: 'fcsess', fc_account: 'fca', fc_transaction: 'fctxn',
82
- // Forwarding (PAN forwarding) requests + Crypto onramp sessions.
83
- forwarding_request: 'fwdr', onramp_session: 'cos',
84
- // Entitlements: a product↔feature grant.
85
- product_feature: 'prodft',
86
- // Tax settings singleton.
87
- tax_settings: 'taxset',
88
- };
89
-
90
- function err(message: string, status = 404, code?: string): StripeResponse {
91
- return { status, body: { error: { type: status === 404 ? 'invalid_request_error' : 'invalid_request_error', message, ...(code ? { code } : {}) } } };
92
- }
93
-
94
27
  // Fidelity: real Stripe rejects a charge/payment_intent missing or with a non-positive
95
28
  // amount, or missing currency, before any state change.
96
29
  export function validateMoney(params: Record<string, unknown>): StripeResponse | null {
@@ -188,7 +121,7 @@ function resolveCardRef(params: Record<string, unknown>): string | undefined {
188
121
  // that references it purely by id (the normal shape for a saved-card/off-session charge,
189
122
  // e.g. an invoice retry) could never reproduce the decline.
190
123
  /** A stored subject by stored type and id, in the pack's view (tombstones included): how the
191
- * semantics hand these helpers the tree they read (semantics/shared.ts `finder`). */
124
+ * semantics hand these helpers the tree they read (./common.ts `finder`). */
192
125
  export type FindStored = (storedType: string, id: string) => Record<string, unknown> | undefined;
193
126
 
194
127
  export function declineFor(find: FindStored, ...paramSets: Array<Record<string, unknown>>): DeclineOutcome | null | undefined {
@@ -304,19 +237,6 @@ export function cardError(outcome: DeclineOutcome, attach: { charge?: string; pa
304
237
  export function nowUnix(occurredAt?: string): number {
305
238
  return Math.floor((occurredAt ? Date.parse(occurredAt) : 0) / 1000);
306
239
  }
307
-
308
- function rows(type: string, root?: string) {
309
- return projectResources(SERVICE, root).filter((r) => r.type === type);
310
- }
311
- function nextId(type: string, root?: string): string {
312
- const prefix = PREFIX[type] ?? type;
313
- let max = 0;
314
- for (const r of rows(type, root)) {
315
- const m = new RegExp(`^${prefix}_twin_(\\d+)$`).exec(r.id);
316
- if (m) max = Math.max(max, Number(m[1]));
317
- }
318
- return `${prefix}_twin_${max + 1}`;
319
- }
320
240
  // Real Stripe embeds the resource's OWN id inside its client_secret (format
321
241
  // `<id>_secret_<random>`) — Stripe.js's confirmPayment/confirmSetup parse the id back
322
242
  // out of the client_secret (splitting on `_secret`) to build the same-origin confirm
@@ -324,25 +244,14 @@ function nextId(type: string, root?: string): string {
324
244
  // A secret that doesn't carry the real id breaks that round trip: a browser Stripe.js
325
245
  // call would try to confirm a resource whose id it invented from the string
326
246
  // (`'pi_twin_secret'` → `'pi_twin'`, which was never actually created). Every PI/SI a
327
- // caller might confirm CLIENT-SIDE (real Stripe.js — see the QA proxy's browserRouting
328
- // in packages/twin/stripe/src/index.ts) must mint a secret this way.
329
- export function mintClientSecret(id: string): string {
330
- return `${id}_secret_twin`;
331
- }
332
- // Stripe resource view: inject `object` + `id`, drop kernel meta.
333
- //
334
- // The kernel reserves the field name `type` as its resource-type discriminator, so a
335
- // stored vendor field literally named `type` is dropped on projection (see actions.ts
336
- // META). Several Stripe objects (payout.type, balance_transaction.type, event.type,
337
- // dispute uses `reason` not `type`) DO have a vendor `type`, so the create path stashes
338
- // it under the reserved key `_stripe_type` (a `_`-prefixed twin-internal field that the
339
- // conformance gate exempts) and we restore it to `type` here. This keeps the vendor
340
- // field faithful without touching the kernel discriminator. (price.type stays a declared
341
- // deviation — its create path predates this and one_time/recurring is derivable.)
342
- // A few Stripe objects have a DOTTED `object` value that differs from the twin's
343
- // (identifier-safe) resource type — e.g. type 'checkout_session' emits object
344
- // 'checkout.session'. Map them on emit so the `object` field is vendor-faithful.
345
- // (stripe-conformance.ts emitted() mirrors this map.)
247
+ // caller might confirm CLIENT-SIDE (real Stripe.js) must mint a secret this way.
248
+ /** An intent's client secret: its id, `_secret_`, and a secret the World holds for it (ctx.secret, passed in), so no one
249
+ * derives it from the intent's id; Stripe.js confirms an intent with it and the publishable key. */
250
+ export function mintClientSecret(id: string, secret: string): string {
251
+ return `${id}_secret_${secret.replace(/[^A-Za-z0-9]/g, '').slice(0, 24)}`;
252
+ }
253
+ // A few Stripe objects have a DOTTED `object` value that differs from the twin's (identifier-safe) resource type: type
254
+ // 'checkout_session' is object 'checkout.session'.
346
255
  export const OBJECT_NAME: Record<string, string> = {
347
256
  checkout_session: 'checkout.session',
348
257
  billing_portal_session: 'billing_portal.session',
@@ -403,17 +312,11 @@ export const OBJECT_NAME: Record<string, string> = {
403
312
  // Forwarding + Crypto onramp.
404
313
  forwarding_request: 'forwarding.request', onramp_session: 'crypto.onramp_session',
405
314
  };
406
- // Exported for the pack's own modules that must render the SAME vendor view of a stored
407
- // resource (stripe-emit.ts synthesizes `data.object` for emitted events from it) — one
408
- // projection, no drift. Not a public API for consumers.
409
- export function view(type: string, r: Record<string, unknown>): Record<string, unknown> {
410
- // `_subscription_data` is twin-internal (a Checkout Session's create-only
411
- // subscription_data, held for the completion transition to copy onto the created
412
- // subscription) — real Stripe never returns it on the Session, so strip it here.
413
- const { type: _t, updatedAt: _u, _stripe_type, _subscription_data, ...rest } = r;
414
- const out: Record<string, unknown> = { object: OBJECT_NAME[type] ?? type, ...rest, id: r.id };
415
- if (_stripe_type !== undefined) out.type = _stripe_type;
416
- return out;
315
+ /** A stored row as Stripe answers it: its `object`, its own fields (the vendor's `type` among them, which the tree's
316
+ * shadows: world-core ownFields) without the twin's `_` bookkeeping, and its id. */
317
+ export function view(type: string, r: TwinResource): Record<string, unknown> {
318
+ const own = Object.fromEntries(Object.entries(ownFields(r)).filter(([k]) => !k.startsWith('_') && k !== 'updatedAt'));
319
+ return { object: OBJECT_NAME[type] ?? type, ...own, id: r.id };
417
320
  }
418
321
  // Real Stripe list pagination. Honors limit (default 10, max 100, min 1),
419
322
  // starting_after (cursor: exclude up to & including that id), ending_before
@@ -448,101 +351,6 @@ export function paginate(items: Array<Record<string, unknown>>, params: Record<s
448
351
  const page = items.slice(from, from + limit);
449
352
  return { page, hasMore: from + limit < items.length };
450
353
  }
451
-
452
- async function writeResource(
453
- type: string,
454
- id: string,
455
- fields: Record<string, unknown>,
456
- op: string,
457
- root?: string,
458
- occurredAt?: string,
459
- apiVersion?: string,
460
- ): Promise<Record<string, unknown>> {
461
- const { resource } = await applyTwinWrite(SERVICE, { operation: op, subjectType: type, subjectId: id, fields, ...(occurredAt ? { occurredAt } : {}), actor: { kind: 'agent' } }, root);
462
- const out = view(type, resource);
463
- await afterStripeWrite(type, op, out, root, occurredAt, apiVersion);
464
- return out;
465
- }
466
-
467
- /** What follows every stored Stripe write: the webhook for the state change and the stored Event
468
- * the Events API lists. The derived pack's write hook (manifest.ts) is this same function. */
469
- export async function afterStripeWrite(type: string, op: string, out: Record<string, unknown>, root?: string, occurredAt?: string, apiVersion?: string, stripeAccount?: string): Promise<void> {
470
- // R17: fire the Stripe event/webhook for this state change (no-op if none registered). An event is a connected
471
- // account's when its resource lives in one (a request made as it, the Stripe-Account header) or is a connected
472
- // account itself (its account.updated): docs.stripe.com/connect/webhooks, "Connected accounts" scope.
473
- // A write with no header is still a connected account's when the row it wrote is kept on that account's books (a
474
- // payout or ledger entry's `_account`: an automatic payout time makes for it, semantics/balance.ts).
475
- const account = stripeAccount ?? (type === 'account' && typeof out.id === 'string' && out.id !== PLATFORM_ACCOUNT_ID ? out.id : undefined) ?? ownerOf(type, out.id, root);
476
- // a plan is stored as the recurring price it is; its own events carry the plan object (semantics/plans.ts)
477
- const object = type === 'price' && op.startsWith('plan.') ? planOf(out) : out;
478
- // events.full_types: the Stripe `event` envelope for this state change is also stored, so it appears in GET
479
- // /v1/events (independent of webhook registration), exactly like real Stripe's stored Events API. Skip when the op
480
- // has no mapped event type, and never for event/_idempotency writes themselves (no recursion / no meta-events). The
481
- // event's id is minted once and is the delivered webhook's id and the stored event's alike: one event, one id, which
482
- // a consumer deduplicates by and retrieves by.
483
- const eventType = type !== 'event' && type !== IDEMPOTENCY_TYPE ? eventTypeFor(op) : null;
484
- const id = eventType ? nextStripeEventId(root) : undefined;
485
- // stored before it is delivered: a consumer that looks its webhook's event up finds it
486
- if (eventType) await persistStripeEvent(eventType, object, root, occurredAt, apiVersion, account, id);
487
- // a connected account whose OAuth connection was revoked "can't be accessed by your platform" (docs.stripe.com/connect/
488
- // oauth-reference): its events (a payout time makes, a renewal) are its own and no longer reach the platform's Connect
489
- // endpoints, except the account.application.deauthorized that says so (screens/connect-oauth.tsx)
490
- if (account && eventType !== 'account.application.deauthorized' && rows(OAUTH_CONNECTIONS, root).some((c) => (c as Record<string, unknown>).id === account && (c as Record<string, unknown>).revoked === true)) return;
491
- await emitStripeEvent(op, object, { occurredAt: occurredAt ?? '1970-01-01T00:00:00.000Z', endpoints: webhookTargets(root), ...(account ? { account } : {}), ...(id ? { id } : {}) });
492
- }
493
-
494
- /** Event numbers taken in this process, per root, before their events are stored: two writes whose events overlap
495
- * (a webhook handler calling back in, concurrent requests) never take the same number. */
496
- const takenEventNumbers = new Map<string, number>();
497
- /** The id the World's next event takes: its place in the World's events, so it is deterministic and never repeats
498
- * within a World (a Balance has no id of its own, so nothing about the object can tell two events apart). The number
499
- * is taken synchronously — the count of stored events, or the last number taken, whichever is higher. */
500
- export function nextStripeEventId(root?: string): string {
501
- const key = root ?? '';
502
- const n = Math.max(rows('event', root).length, takenEventNumbers.get(key) ?? 0) + 1;
503
- takenEventNumbers.set(key, n);
504
- return `evt_twin_${n}`;
505
- }
506
-
507
- /** The connected account whose books a stored row is kept on (its `_account`), if any. */
508
- function ownerOf(type: string, id: unknown, root?: string): string | undefined {
509
- if (typeof id !== 'string') return undefined;
510
- const owner = (rows(type, root).find((r) => r.id === id) as Record<string, unknown> | undefined)?._account;
511
- return typeof owner === 'string' ? owner : undefined;
512
- }
513
-
514
- // Persist a Stripe `event` resource (object 'event') for a state change into the action
515
- // log so the Events API (GET /v1/events) lists/retrieves it. Deterministic id derived
516
- // from the per-root event count; data.object carries the resource snapshot. Written via
517
- // applyTwinWrite directly (NOT writeResource) to avoid re-emitting an event for the event.
518
- export async function persistStripeEvent(eventType: string, resource: Record<string, unknown>, root?: string, occurredAt?: string, apiVersion?: string, account?: string, id?: string): Promise<void> {
519
- const eventId = id ?? nextStripeEventId(root);
520
- const fields = {
521
- object: 'event', _stripe_type: eventType, created: nowUnix(occurredAt), livemode: false,
522
- pending_webhooks: 0, api_version: apiVersion && isValidApiVersion(apiVersion) ? apiVersion : TWIN_API_VERSION,
523
- request: { id: null, idempotency_key: null },
524
- data: { object: resource },
525
- // a connected account's event names it, and is listed to requests made as it (semantics/webhook-endpoints.ts)
526
- ...(account ? { account } : {}),
527
- };
528
- await applyTwinWrite(SERVICE, { operation: 'event.record', subjectType: 'event', subjectId: eventId, fields, ...(occurredAt ? { occurredAt } : {}), actor: { kind: 'system' } }, root);
529
- }
530
- function getOne(type: string, id: string, root?: string): Record<string, unknown> | undefined {
531
- const r = rows(type, root).find((x) => x.id === id);
532
- return r ? view(type, r) : undefined;
533
- }
534
-
535
- // Stripe list order: newest first by `created` (or `date` for invoiceitem), ties
536
- // broken by id descending so the order is stable for cursor pagination.
537
- /** The World's live webhook endpoints, from its tree: delivery survives a restart and belongs to
538
- * this World alone. A disabled or deleted endpoint receives nothing, like the vendor. */
539
- function webhookTargets(root: string | undefined): StripeWebhookTarget[] {
540
- // `connect` is a create parameter the endpoint object does not answer, so it is read off the stored row
541
- return rows('webhook_endpoint', root)
542
- .map((r) => ({ w: view('webhook_endpoint', r), connect: asBool((r as Record<string, unknown>).connect) }))
543
- .filter(({ w }) => !w.deleted && w.status !== 'disabled' && typeof w.url === 'string')
544
- .map(({ w, connect }) => ({ url: String(w.url), ...(typeof w.secret === 'string' ? { secret: w.secret } : {}), ...(Array.isArray(w.enabled_events) ? { enabledEvents: w.enabled_events.map(String) } : {}), connect }));
545
- }
546
354
  // Stripe's `active=true|false` filters arrive as strings/booleans; normalize.
547
355
  export function asBool(v: unknown): boolean {
548
356
  return v === true || v === 'true' || v === 1 || v === '1';
@@ -804,36 +612,15 @@ export function resolveTrial(params: Record<string, unknown>, at: number): { sta
804
612
  return undefined;
805
613
  }
806
614
 
807
- // Create a resource from form params, stamping object + id + created + the given
808
- // defaults. Only real Stripe field names are emitted (conformance-checked).
809
- // A vendor `type` field (a price's one_time or recurring, a payout's bank_account) always collides with the kernel's
810
- // row type, so it is stashed under `_stripe_type` and restored by view().
811
- export function stashVendorType(_type: string, fields: Record<string, unknown>): Record<string, unknown> {
812
- if (!('type' in fields)) return fields;
813
- const { type: vt, ...rest } = fields;
814
- return { ...rest, _stripe_type: vt };
815
- }
816
-
817
- async function create(type: string, params: Record<string, unknown>, defaults: Record<string, unknown>, req: StripeRequest, opts: { timeField?: string } = {}): Promise<StripeResponse> {
818
- // honor a caller-provided id (seeding uses the catalog's real prod_*/price_* ids);
819
- // otherwise assign one. The id is identity, not a stored field.
820
- const { id: providedId, ...rest } = params as { id?: unknown } & Record<string, unknown>;
821
- const id = typeof providedId === 'string' && providedId ? providedId : nextId(type, req.root);
822
- // Most Stripe objects stamp `created`; a few (invoiceitem) use a differently-named
823
- // timestamp instead (`date`) and have NO `created` field — honor that, don't fabricate.
824
- const fields = stashVendorType(type, { object: OBJECT_NAME[type] ?? type, [opts.timeField ?? 'created']: nowUnix(req.occurredAt), ...defaults, ...rest });
825
- return { status: 200, body: await writeResource(type, id, fields, `${type}.create`, req.root, req.occurredAt, req.apiVersion) };
826
- }
827
-
828
615
  // ── ISSUING helpers: spending controls, real-time-auth shapes ─────────────────────────
829
616
  // Authorization.card is the FULL Card object in every vendor egress (API responses and
830
617
  // webhook payloads) — it is not expandable (stripe@22.3.0 Issuing.Authorization.card:
831
618
  // Stripe.Issuing.Card). The twin stores the id internally and embeds at the boundary;
832
619
  // cardholder stays an id string (expandable, unexpanded default). Caught live: the
833
620
  // issuing-bridge reads event.data.object.card.id and refused every twin presentment.
834
- export function embedIssuingAuthorizationCard(body: Record<string, unknown>, root?: string): Record<string, unknown> {
621
+ export function embedIssuingAuthorizationCard(body: Record<string, unknown>, find: FindStored): Record<string, unknown> {
835
622
  if (typeof body.card === 'string') {
836
- const cardRow = getOne('issuing_card', body.card, root);
623
+ const cardRow = find('issuing_card', body.card);
837
624
  if (cardRow !== undefined) body.card = cardRow;
838
625
  }
839
626
  return body;
@@ -1202,19 +989,6 @@ export function lineItemEntries(params: Record<string, unknown>): Array<Record<s
1202
989
  return Array.isArray(li) ? (li.filter((x) => x && typeof x === 'object') as Array<Record<string, unknown>>) : [];
1203
990
  }
1204
991
 
1205
- // ---- IDEMPOTENCY KEYS (vendor-faithful) ----
1206
- // Real Stripe honors the `Idempotency-Key` header on POST: the first request with a
1207
- // key executes and the (status + body) response is stored against the key; a replay
1208
- // with the SAME key returns the SAME stored response WITHOUT re-applying the write.
1209
- // We persist the stored response as an `_idempotency` resource in the action log
1210
- // (per-root, so a fork has its own keyspace). `_idempotency` is a twin-internal type
1211
- // (never served as a Stripe object), so it does not affect spec conformance.
1212
- //
1213
- // Note: real Stripe only persists idempotency for responses it considers "completed"
1214
- // (2xx and most 4xx, including card 402s) and scopes the key to the account; here we
1215
- // store every executed POST response (success and error alike), keyed per-root.
1216
- const IDEMPOTENCY_TYPE = '_idempotency';
1217
-
1218
992
  // ── THE MONEY MODEL: a charge and the refunds taken out of it ──────────────────────────
1219
993
  //
1220
994
  // The rule this section exists to hold: A FACT RECORDED ON ONE MONEY OBJECT IS VISIBLE FROM
@@ -1237,75 +1011,6 @@ export function chargeDefaults(chargeId: string, amount: number, captured: boole
1237
1011
  };
1238
1012
  }
1239
1013
 
1240
- /**
1241
- * Public entry: honors the Idempotency-Key (replay → stored response, no re-write)
1242
- * then delegates to the router. Only POSTs are idempotent (matches Stripe; GET/DELETE
1243
- * pass straight through). A read-only twin never stores (it cannot write).
1244
- */
1245
- /** Stripe's API as one call: the request goes through the pack's own dispatch (the derived dispatch over
1246
- * its semantics, its derived core and the hand-written routes below), so a caller that holds no
1247
- * HTTP server reaches exactly what an SDK does. `occurredAt` pins the World instant. */
1248
- export async function handleStripeTwinRequest(req: StripeRequest): Promise<StripeResponse> {
1249
- const twin = createStripeTwinFetch({ ...(req.root !== undefined ? { root: req.root } : {}), readOnly: req.readOnly ?? false, ...(req.occurredAt ? { clock: () => req.occurredAt! } : {}) });
1250
- const method = req.method.toUpperCase();
1251
- const headers: Record<string, string> = { 'content-type': 'application/x-www-form-urlencoded' };
1252
- if (req.idempotencyKey) headers['idempotency-key'] = req.idempotencyKey;
1253
- if (req.apiVersion !== undefined) headers['stripe-version'] = req.apiVersion;
1254
- if (req.stripeAccount) headers['stripe-account'] = req.stripeAccount;
1255
- // a GET carries its parameters in the query; a caller that handed them as a body keeps them
1256
- let path = req.path.startsWith('/') ? req.path : `/${req.path}`;
1257
- if ((method === 'GET' || method === 'HEAD') && req.body) path += (path.includes('?') ? '&' : '?') + req.body;
1258
- const response = await twin(new Request(`http://stripe.test${path}`, { method, headers, ...(method !== 'GET' && method !== 'HEAD' && req.body ? { body: req.body } : {}) }));
1259
- const text = await response.text();
1260
- return { status: response.status, body: text ? JSON.parse(text) : null };
1261
- }
1262
-
1263
- /**
1264
- * The twin's doors: what stands in for an act Stripe's API does not have, each under `/_twin/`. The
1265
- * platform's own account settings (its payout schedule) change on Stripe's Dashboard, which has no API:
1266
- * POST /_twin/account stands in for that page. Answers nothing for any other path.
1267
- */
1268
- export async function handleStripeDoor(req: StripeRequest, params: Record<string, unknown>): Promise<StripeResponse | undefined> {
1269
- const method = req.method.toUpperCase();
1270
- const path = (req.path.split('?')[0] ?? '/').replace(/\/+$/, '') || '/';
1271
- const seg = path.replace(/^\/+/, '').split('/');
1272
- if (seg[0] !== '_twin') return undefined;
1273
- if (req.readOnly) return err('twin is read-only; omit readOnly to accept writes', 405);
1274
- if (path === '/_twin/account' && method === 'POST') {
1275
- const ex = getOne('account', PLATFORM_ACCOUNT_ID, req.root);
1276
- const { type: _t, settings: rawSettings, business_profile: rawProfile, ...rest } = params as Record<string, unknown>;
1277
- // the platform's account is Stripe's default until the page first changes it (semantics/connect.ts, the same
1278
- // default GET /v1/account answers and the Public details page stores)
1279
- const fields = {
1280
- ...(ex ? {} : (({ id: _id, ...base }) => base)(platformAccountDefault())),
1281
- ...rest,
1282
- settings: accountSettings(rawSettings, ex?.settings as Record<string, unknown> | undefined),
1283
- // a hash is merged into what the account holds, as an update merges it (the name the Public details page saved stays)
1284
- ...(rawProfile && typeof rawProfile === 'object' ? { business_profile: { ...((ex?.business_profile as Record<string, unknown> | undefined) ?? {}), ...(rawProfile as Record<string, unknown>) } } : {}),
1285
- };
1286
- return { status: 200, body: await writeResource('account', PLATFORM_ACCOUNT_ID, stashVendorType('account', fields), 'account.update', req.root, req.occurredAt) };
1287
- }
1288
- // Issuing network tokens are minted by the card network when a cardholder adds the card to a
1289
- // phone's wallet (docs.stripe.com/issuing/cards/digital-wallets): there is no API create, and the
1290
- // act happens in the phone's wallet app, not on a Stripe page. POST /_twin/issuing/cards/:card/wallets
1291
- // stands in for that act ({wallet_provider, network}); the API reads the token and moves its status.
1292
- // Where the documentation stops and the twin decides: the network approves at once (the token is active).
1293
- if (seg[0] === '_twin' && seg[1] === 'issuing' && seg[2] === 'cards' && seg[3] && seg[4] === 'wallets' && seg.length === 5 && method === 'POST') {
1294
- const card = decodeURIComponent(seg[3]);
1295
- const c = getOne('issuing_card', card, req.root);
1296
- if (!c) return err(`No such card: '${card}'`, 400, 'resource_missing');
1297
- const wallet = typeof params.wallet_provider === 'string' && ['apple_pay', 'google_pay', 'samsung_pay'].includes(params.wallet_provider)
1298
- ? params.wallet_provider : 'apple_pay';
1299
- const network = typeof params.network === 'string' && ['visa', 'mastercard'].includes(params.network) ? params.network : 'visa';
1300
- const last4 = typeof c.last4 === 'string' ? c.last4 : '0000';
1301
- return create('issuing_token', { card, cardholder: typeof c.cardholder === 'string' ? c.cardholder : ((c.cardholder as Record<string, unknown> | undefined)?.id ?? null) }, {
1302
- status: 'active', wallet_provider: wallet, network, last4, livemode: false,
1303
- device_fingerprint: null, network_data: null, network_updated_at: nowUnix(req.occurredAt),
1304
- }, req);
1305
- }
1306
- return undefined;
1307
- }
1308
-
1309
1014
  // collection path segment → resource type, for the generic list of a collection Stripe does not
1310
1015
  // list at that path (the twin's test clocks, which Stripe lists under /v1/test_helpers).
1311
1016
 
@@ -0,0 +1,10 @@
1
+ // Subscription schedule semantics: a schedule drives a subscription through phases (items for a
2
+ // duration). One made for a customer starts its subscription at once on the first phase's items. Cancel and
3
+ // release end it, the machine's moves in ../manifest.ts. List and update are the derived core's.
4
+ //
5
+ // Where the documentation stops and the twin decides: the subscription a schedule starts raises no first invoice.
6
+ import { addBillingInterval } from './stripe.ts';
7
+
8
+ export const SS = 'subscription_schedule';
9
+
10
+ export type Interval = Parameters<typeof addBillingInterval>[1];
@@ -0,0 +1,40 @@
1
+ // Subscription and SubscriptionItem semantics. A subscription is created with its items, its
2
+ // billing period and, under payment_behavior=default_incomplete, its first invoice and that
3
+ // invoice's PaymentIntent; canceling it is the machine's move in ../manifest.ts. Retrieve of a
4
+ // subscription and of an item are the derived core's.
5
+ import type { Row } from './common.ts';
6
+
7
+ export const SUB = 'subscription';
8
+
9
+ // pause_collection pauses billing (the subscription stays active; the paused event fires) and
10
+ // clearing it resumes; cancel_at_period_end schedules or withdraws a cancel; a coupon replaces the
11
+ // discount and an empty one clears it
12
+ /** pause_collection pauses billing (the paused event fires) and clearing it resumes
13
+ * (docs.stripe.com/billing/subscriptions/pause-payment); answers the event, or nothing for a value it does not take. */
14
+ export function pauseCollection(pc: unknown, fields: Row): string | undefined {
15
+ const isClear = pc === '' || pc === null || (typeof pc === 'object' && pc !== null && Object.keys(pc as object).length === 0);
16
+ if (isClear) {
17
+ fields.pause_collection = null;
18
+ return 'customer.subscription.resumed';
19
+ }
20
+ if (!pc || typeof pc !== 'object') return undefined;
21
+ const p = pc as Row;
22
+ fields.pause_collection = { behavior: typeof p.behavior === 'string' ? p.behavior : 'void', resumes_at: p.resumes_at !== undefined ? Number(p.resumes_at) : null };
23
+ return 'customer.subscription.paused';
24
+ }
25
+
26
+ /** The longest trial Stripe takes: `trial_end` "Can be at most two years from `billing_cycle_anchor`"
27
+ * (docs.stripe.com/api/subscriptions/update#update_subscription-trial_end); "The trial period must be 730 days (2 years)
28
+ * or less" (docs.stripe.com/billing/subscriptions/trials/free-trials). */
29
+ export const MAX_TRIAL = 730 * 86400;
30
+
31
+ /** A trial moved to end at `end`, or a new one to `end` on a subscription out of its trial (applyTrialEnd). */
32
+ export function movedTrial(sub: Row, fields: Row, end: number, now: number): undefined {
33
+ Object.assign(fields, {
34
+ status: 'trialing', trial_end: end, trial_start: sub.trial_start ?? now, billing_cycle_anchor: end,
35
+ current_period_end: end, ...(sub.status !== 'trialing' ? { current_period_start: now } : {}),
36
+ });
37
+ return undefined;
38
+ }
39
+
40
+ export const ITEM_ATTRIBUTES = new Set(['billing_thresholds', 'discounts', 'metadata', 'price', 'quantity', 'tax_rates']);
@@ -0,0 +1,39 @@
1
+ // Stripe Tax semantics: tax rates, the account's tax settings (a singleton), calculations,
2
+ // registrations, and the transactions that commit a calculation or reverse one. A calculation's
3
+ // tax comes from one flat default rate so its amounts are stable (Stripe derives it from the
4
+ // customer's jurisdiction and the account's registrations). Rate, calculation, registration and
5
+ // transaction retrieves and the registration list are the derived core's.
6
+ import type { Row } from './common.ts';
7
+
8
+ export const TWIN_TAX_RATE_PCT = 10;
9
+
10
+ // ── settings: active once a head office is set; the answer has no id ──
11
+
12
+ // the defaults' provider: "The tax calculation provider this account uses. Defaults to `stripe` when not using a
13
+ // third-party provider" (the served spec's tax settings defaults); the head office's address answers each line, the
14
+ // lines not given null (the served spec's address: each "(string, nullable)"; the settings page's example answers
15
+ // line2 null)
16
+ export const ADDRESS_LINES = ['city', 'country', 'line1', 'line2', 'postal_code', 'state'];
17
+ export function settingsBody(stored: Row | undefined): Row {
18
+ const given = (stored?.head_office ?? null) as Row | null;
19
+ const address = given && typeof given.address === 'object' && given.address ? (given.address as Row) : undefined;
20
+ const headOffice = given ? { ...given, ...(address ? { address: Object.fromEntries(ADDRESS_LINES.map((k) => [k, address[k] ?? null])) } : {}) } : null;
21
+ const active = !!headOffice;
22
+ return {
23
+ object: 'tax.settings', livemode: false,
24
+ defaults: { provider: 'stripe', ...((stored?.defaults as Row) ?? { tax_behavior: null, tax_code: null }) }, head_office: headOffice,
25
+ status: active ? 'active' : 'pending',
26
+ status_details: active ? { active: {} } : { pending: { missing_fields: ['head_office'] } },
27
+ };
28
+ }
29
+
30
+ // ── transactions: committing a calculation, or reversing a transaction with negated amounts ──
31
+
32
+ export const TX = 'tax.transaction';
33
+ export const txLine = (id: string, i: number, l: Row, sign: 1 | -1, reversal: Row | null, type: string): Row => ({
34
+ object: 'tax.transaction_line_item', id: `tax_li_${id}_${i + 1}`,
35
+ amount: sign === 1 ? l.amount : -(Number(l.amount) || 0), amount_tax: sign === 1 ? l.amount_tax : -(Number(l.amount_tax) || 0),
36
+ reference: l.reference ?? null, tax_behavior: l.tax_behavior ?? 'exclusive', tax_code: l.tax_code ?? 'txcd_99999999',
37
+ quantity: l.quantity ?? 1, reversal, type, livemode: false, metadata: {},
38
+ });
39
+ export const linesOf = (holder: Row): Row[] => (holder.line_items as { data?: Row[] } | undefined)?.data ?? [];
@@ -0,0 +1,23 @@
1
+ // Terminal and top-up semantics: in-person locations, readers (handed a PaymentIntent to process)
2
+ // and their configurations, the reader SDK's connection tokens, and top-ups that fund the balance
3
+ // (a test top-up succeeds at once; only a pending one cancels, the machine in ../manifest.ts). In test mode a
4
+ // simulated reader is presented a card by a test helper: the PaymentIntent the reader is processing is paid with a
5
+ // card_present payment method (succeeded, or requires_capture under manual capture) and the reader's action succeeds
6
+ // (docs.stripe.com/terminal/references/testing#simulated-test-cards,
7
+ // docs.stripe.com/api/terminal/readers/present_payment_method). Where the documentation stops and the twin decides:
8
+ // the presented card is the simulated reader's default Visa, and the reader answers at once.
9
+ // Lists and retrieves are the derived core's.
10
+
11
+ export const LOC = 'terminal.location';
12
+ export const READER = 'terminal.reader';
13
+ export const CONF = 'terminal.configuration';
14
+
15
+ // ── top-ups ──
16
+
17
+ // a top-up adds money to the balance it names, through the ledger, once its funds arrive: "USA (USD) ACH Debit Transfer
18
+ // 5 days" (docs.stripe.com/connect/top-ups), and to the Issuing balance alike: "Top-ups debit your bank account. Your
19
+ // top-ups can take up to 5 business days to become available. While they're pending, they won't be added to your
20
+ // Issuing balance" (docs.stripe.com/issuing/funding/balance). It is pending until its expected_availability_date, then
21
+ // settled by settleTopups. Where the documentation stops and the twin decides: every top-up takes exactly five days,
22
+ // whatever its currency and balance, and succeeds.
23
+ export const TOPUP_DAYS = 5;
@@ -0,0 +1,11 @@
1
+ // Test clock semantics. A test clock is Stripe's own door for a transition no API verb makes: the
2
+ // passage of time. Advancing it moves the subscriptions of the clock's customers as a real clock tick does:
3
+ // trials that ended end, and periods that ended renew (./renewals.ts advanceBilling). List, retrieve and delete are
4
+ // the derived core's.
5
+
6
+ export const CLOCK = 'test_helpers.test_clock';
7
+
8
+ /** How long an advance takes: "it takes a few seconds to advance to the specified time"
9
+ * (docs.stripe.com/billing/testing/test-clocks/api-advanced-usage). Where the documentation stops and the twin decides:
10
+ * five seconds of World time from the advance. */
11
+ export const ADVANCE_SECONDS = 5;
@@ -0,0 +1,22 @@
1
+ // Token semantics: the older integrations' single-use tokens for a card, a bank account or PII. A
2
+ // token carries only the safe fields of its instrument, never the card or account number. Retrieve
3
+ // is the derived core's.
4
+ import { paymentMethodSubObject } from './stripe.ts';
5
+ import type { Row } from './common.ts';
6
+
7
+ /** The Card object a card token carries, as the served spec's `card` describes it: its brand as a name ("Card brand.
8
+ * Can be `American Express`, ... `MasterCard`, `UnionPay`, `Visa`, or `Unknown`"), the holder's name and address as
9
+ * given ("Cardholder name"), and the CVC's check when one was given ("If a CVC was provided, results of the check:
10
+ * pass, fail, unavailable, or unchecked"). Where the documentation stops and the twin decides: a test card's CVC passes. */
11
+ export const BRAND_NAMES: Record<string, string> = { amex: 'American Express', cartes_bancaires: 'Cartes Bancaires', diners: 'Diners Club', discover: 'Discover', eftpos_au: 'Eftpos Australia', girocard: 'Girocard', jcb: 'JCB', mastercard: 'MasterCard', unionpay: 'UnionPay', visa: 'Visa' };
12
+ export function legacyCard(id: string, card: Row): Row {
13
+ const pm = paymentMethodSubObject('card', { card }).card as Row;
14
+ const given = (k: string): unknown => (typeof card[k] === 'string' && card[k] !== '' ? card[k] : null);
15
+ return {
16
+ id, object: 'card', brand: BRAND_NAMES[String(pm.brand)] ?? 'Unknown', last4: pm.last4, exp_month: pm.exp_month, exp_year: pm.exp_year,
17
+ funding: pm.funding ?? 'credit', country: pm.country ?? null, fingerprint: pm.fingerprint ?? null, name: given('name'),
18
+ address_line1: given('address_line1'), address_line2: given('address_line2'), address_city: given('address_city'), address_state: given('address_state'),
19
+ address_zip: given('address_zip'), address_country: given('address_country'), address_line1_check: null, address_zip_check: null,
20
+ cvc_check: card.cvc !== undefined && card.cvc !== '' ? 'pass' : null, dynamic_last4: null, tokenization_method: null, metadata: {}, customer: null,
21
+ };
22
+ }
@@ -0,0 +1,23 @@
1
+ // Transfer and application-fee semantics: money the platform moves to a connected account and
2
+ // claws back (reversals), and the platform's fee on a connected charge and its refunds. A
3
+ // reversal or fee refund never exceeds what is left, and lands on its parent's totals and list.
4
+ // A transfer goes only to an account whose transfers capability is active, comes out of the
5
+ // platform's available balance, and lands in the destination's (docs.stripe.com/connect/separate-
6
+ // charges-and-transfers); a reversal moves it back.
7
+ // A transfer tied to a charge (`source_transaction`, "Transfer availability" in the same guide) "returns success
8
+ // regardless of your available balance if the related charge hasn't settled yet", but "the funds don't become
9
+ // available in the destination account until the funds from the associated charge are available"; a charge whose funds
10
+ // are already available by the World's clock is no exception, and the transfer is held to the available balance as any
11
+ // other. "The amount of the transfer must not exceed the amount of the source charge", several transfers may share one
12
+ // charge while "the sum of the transfers doesn't exceed the source charge", and the charge's balance currency must
13
+ // match. "If the source charge has a `transfer_group` value, Stripe assigns the same value to the transfer's
14
+ // `transfer_group`. If it doesn't, then Stripe generates a string in the format `group_` plus the associated
15
+ // PaymentIntent ID ... It assigns that string as the `transfer_group` for both the charge and the transfer."
16
+ // Where the documentation stops and the twin decides: the sum from one charge counts each transfer less what was
17
+ // reversed of it; a transfer_group the request names is kept only when the charge has none and no PaymentIntent to
18
+ // name one after; an uncaptured charge (an authorization, docs silent) is refused as a source_transaction until it is
19
+ // captured; the refusals' wording is the twin's.
20
+ // Transfer list, retrieve and update and application-fee list and retrieve are the derived core's.
21
+ import type { Row } from './common.ts';
22
+
23
+ export const emptyList = (url: string): Row => ({ object: 'list', data: [], has_more: false, total_count: 0, url });