@volter/twin-stripe 2.0.38 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (402) hide show
  1. package/README.md +112 -207
  2. package/dist/generated/pack-facts.json +94 -0
  3. package/dist/journeys/coverage.json +596 -0
  4. package/dist/journeys/customer-life.json +6108 -0
  5. package/dist/journeys/customer-life.outline.md +371 -0
  6. package/dist/journeys/decisions.json +677 -0
  7. package/dist/journeys/demand.json +706 -0
  8. package/dist/journeys/score.json +853 -0
  9. package/dist/journeys/unreachable.json +102 -0
  10. package/dist/journeys/vendor-examples.json +8010 -0
  11. package/dist/spec/SOURCE.md +18 -0
  12. package/dist/spec/doc-examples.json +445 -0
  13. package/dist/spec/fixtures3.json.gz +0 -0
  14. package/dist/spec/openapi.json.gz +0 -0
  15. package/dist/spec/patches.json +34 -0
  16. package/dist/spec/sources.json +306 -0
  17. package/dist/src/cli.d.ts +0 -1
  18. package/dist/src/cli.js +11 -31
  19. package/dist/src/engine/after-payment.d.ts +8 -0
  20. package/dist/src/engine/after-payment.js +27 -0
  21. package/dist/src/engine/apps-secrets.d.ts +1 -0
  22. package/dist/src/engine/apps-secrets.js +3 -0
  23. package/dist/src/engine/balance.d.ts +5 -0
  24. package/dist/src/engine/balance.js +15 -0
  25. package/dist/src/engine/checkout.d.ts +24 -0
  26. package/dist/src/engine/checkout.js +30 -0
  27. package/dist/src/engine/common.d.ts +19 -0
  28. package/dist/src/engine/common.js +34 -0
  29. package/dist/src/engine/connect.d.ts +45 -0
  30. package/dist/src/engine/connect.js +108 -0
  31. package/dist/src/engine/customers.d.ts +4 -0
  32. package/dist/src/engine/customers.js +8 -0
  33. package/dist/src/engine/display.d.ts +11 -0
  34. package/dist/src/engine/display.js +13 -0
  35. package/dist/src/engine/files.d.ts +11 -0
  36. package/dist/src/engine/files.js +23 -0
  37. package/dist/src/engine/invoices.d.ts +21 -0
  38. package/dist/src/engine/invoices.js +84 -0
  39. package/dist/src/engine/issuing.d.ts +33 -0
  40. package/dist/src/engine/issuing.js +54 -0
  41. package/dist/src/engine/ledger.d.ts +8 -0
  42. package/dist/src/engine/ledger.js +8 -0
  43. package/dist/src/engine/oauth.d.ts +4 -0
  44. package/dist/src/engine/oauth.js +24 -0
  45. package/dist/src/engine/onboarding.d.ts +13 -0
  46. package/dist/src/engine/onboarding.js +42 -0
  47. package/dist/src/{stripe-params.d.ts → engine/params.d.ts} +20 -3
  48. package/dist/src/{stripe-params.js → engine/params.js} +7 -60
  49. package/dist/src/engine/payment-intents.d.ts +10 -0
  50. package/dist/src/engine/payment-intents.js +27 -0
  51. package/dist/src/engine/payment-methods.d.ts +16 -0
  52. package/dist/src/engine/payment-methods.js +22 -0
  53. package/dist/src/engine/radar.d.ts +2 -0
  54. package/dist/src/engine/radar.js +5 -0
  55. package/dist/src/engine/refunds.d.ts +1 -0
  56. package/dist/src/engine/refunds.js +3 -0
  57. package/dist/src/engine/renewals.d.ts +36 -0
  58. package/dist/src/engine/renewals.js +65 -0
  59. package/dist/src/{stripe-twin.d.ts → engine/stripe.d.ts} +12 -45
  60. package/dist/src/{stripe-twin.js → engine/stripe.js} +53 -387
  61. package/dist/src/engine/subscriptions.d.ts +11 -0
  62. package/dist/src/engine/subscriptions.js +30 -0
  63. package/dist/src/engine/transfers.d.ts +2 -0
  64. package/dist/src/engine/transfers.js +1 -0
  65. package/dist/src/{stripe-version.d.ts → engine/version.d.ts} +0 -2
  66. package/dist/src/{stripe-version.js → engine/version.js} +21 -9
  67. package/dist/src/engine/webhook-endpoints.d.ts +1 -0
  68. package/dist/src/engine/webhook-endpoints.js +12 -0
  69. package/dist/src/engine/webhooks.d.ts +31 -0
  70. package/dist/src/engine/webhooks.js +68 -0
  71. package/dist/src/fetch.d.ts +2 -0
  72. package/dist/src/fetch.js +26 -0
  73. package/dist/src/generated/surface.gen.json +1 -1
  74. package/dist/src/generated/ui.gen.json +1 -1
  75. package/dist/src/index.d.ts +5 -14
  76. package/dist/src/index.js +10 -75
  77. package/dist/src/manifest.js +478 -876
  78. package/dist/src/screens/billing-portal.d.ts +3 -0
  79. package/dist/src/screens/{portal.js → billing-portal.js} +32 -58
  80. package/dist/src/screens/checkout-js.d.ts +2 -0
  81. package/dist/src/screens/checkout-js.js +84 -0
  82. package/dist/src/screens/checkout.d.ts +2 -31
  83. package/dist/src/screens/checkout.js +32 -121
  84. package/dist/src/screens/connect-onboarding.d.ts +3 -0
  85. package/dist/src/screens/{onboarding.js → connect-onboarding.js} +38 -104
  86. package/dist/src/screens/dashboard.d.ts +3 -0
  87. package/dist/src/screens/dashboard.js +116 -0
  88. package/dist/src/screens/shared.d.ts +27 -0
  89. package/dist/src/screens/shared.js +87 -0
  90. package/dist/src/screens/stripe-js.d.ts +3 -0
  91. package/dist/src/screens/stripe-js.js +95 -0
  92. package/dist/src/semantics/account.d.ts +2 -0
  93. package/dist/src/semantics/account.js +8 -0
  94. package/dist/src/semantics/account_links.d.ts +2 -0
  95. package/dist/src/semantics/account_links.js +22 -0
  96. package/dist/src/semantics/accounts.d.ts +4 -0
  97. package/dist/src/semantics/accounts.js +40 -0
  98. package/dist/src/semantics/apps.d.ts +4 -0
  99. package/dist/src/semantics/{apps-secrets.js → apps.js} +14 -26
  100. package/dist/src/semantics/around.d.ts +2 -0
  101. package/dist/src/semantics/around.js +13 -0
  102. package/dist/src/semantics/balance.d.ts +2 -11
  103. package/dist/src/semantics/balance.js +3 -194
  104. package/dist/src/semantics/balance_transactions.d.ts +2 -0
  105. package/dist/src/semantics/balance_transactions.js +15 -0
  106. package/dist/src/semantics/billing_portal.d.ts +4 -0
  107. package/dist/src/semantics/billing_portal.js +36 -0
  108. package/dist/src/semantics/charges.d.ts +3 -28
  109. package/dist/src/semantics/charges.js +5 -202
  110. package/dist/src/semantics/checkout.d.ts +3 -20
  111. package/dist/src/semantics/checkout.js +21 -271
  112. package/dist/src/semantics/clock.d.ts +2 -0
  113. package/dist/src/semantics/clock.js +15 -0
  114. package/dist/src/semantics/coupons.d.ts +2 -6
  115. package/dist/src/semantics/coupons.js +2 -60
  116. package/dist/src/semantics/customers.d.ts +5 -6
  117. package/dist/src/semantics/customers.js +47 -413
  118. package/dist/src/semantics/doors.d.ts +23 -0
  119. package/dist/src/semantics/doors.js +73 -0
  120. package/dist/src/semantics/entitlements.d.ts +0 -2
  121. package/dist/src/semantics/entitlements.js +4 -95
  122. package/dist/src/semantics/events.d.ts +11 -0
  123. package/dist/src/semantics/events.js +31 -0
  124. package/dist/src/semantics/index.d.ts +2 -0
  125. package/dist/src/semantics/index.js +85 -0
  126. package/dist/src/semantics/invoice_payments.d.ts +2 -0
  127. package/dist/src/semantics/invoice_payments.js +12 -0
  128. package/dist/src/semantics/invoices.d.ts +11 -18
  129. package/dist/src/semantics/invoices.js +121 -440
  130. package/dist/src/semantics/issuing.d.ts +6 -13
  131. package/dist/src/semantics/issuing.js +58 -556
  132. package/dist/src/semantics/payment_intents.d.ts +3 -0
  133. package/dist/src/semantics/payment_intents.js +71 -0
  134. package/dist/src/semantics/payment_methods.d.ts +3 -0
  135. package/dist/src/semantics/payment_methods.js +15 -0
  136. package/dist/src/semantics/payouts.d.ts +3 -0
  137. package/dist/src/semantics/payouts.js +28 -0
  138. package/dist/src/semantics/prices.d.ts +4 -0
  139. package/dist/src/semantics/prices.js +37 -0
  140. package/dist/src/semantics/products.d.ts +4 -2
  141. package/dist/src/semantics/products.js +12 -138
  142. package/dist/src/semantics/promotion_codes.d.ts +3 -0
  143. package/dist/src/semantics/promotion_codes.js +35 -0
  144. package/dist/src/semantics/radar.d.ts +2 -2
  145. package/dist/src/semantics/radar.js +5 -74
  146. package/dist/src/semantics/refunds.d.ts +2 -9
  147. package/dist/src/semantics/refunds.js +3 -193
  148. package/dist/src/semantics/shared.d.ts +558 -55
  149. package/dist/src/semantics/shared.js +2070 -114
  150. package/dist/src/semantics/states.d.ts +462 -0
  151. package/dist/src/semantics/states.js +634 -0
  152. package/dist/src/semantics/subscriptions.d.ts +6 -11
  153. package/dist/src/semantics/subscriptions.js +37 -530
  154. package/dist/src/semantics/test_helpers.d.ts +3 -0
  155. package/dist/src/semantics/test_helpers.js +125 -0
  156. package/dist/src/semantics/transfers.d.ts +2 -2
  157. package/dist/src/semantics/transfers.js +6 -101
  158. package/dist/src/semantics/webhook_endpoints.d.ts +2 -0
  159. package/dist/src/semantics/webhook_endpoints.js +26 -0
  160. package/dist/src/server.d.ts +7 -0
  161. package/dist/src/server.js +7 -0
  162. package/generated/pack-facts.json +94 -0
  163. package/journeys/coverage.json +596 -0
  164. package/journeys/customer-life.json +6108 -0
  165. package/journeys/customer-life.outline.md +371 -0
  166. package/journeys/decisions.json +677 -0
  167. package/journeys/demand.json +706 -0
  168. package/journeys/score.json +853 -0
  169. package/journeys/unreachable.json +102 -0
  170. package/journeys/vendor-examples.json +8010 -0
  171. package/package.json +11 -20
  172. package/spec/SOURCE.md +18 -0
  173. package/spec/doc-examples.json +445 -0
  174. package/spec/fixtures3.json.gz +0 -0
  175. package/spec/openapi.json.gz +0 -0
  176. package/spec/patches.json +34 -0
  177. package/spec/sources.json +306 -0
  178. package/src/cli.ts +11 -28
  179. package/src/engine/after-payment.ts +29 -0
  180. package/src/engine/apps-secrets.ts +4 -0
  181. package/src/engine/balance.ts +32 -0
  182. package/src/engine/checkout.ts +39 -0
  183. package/src/engine/common.ts +49 -0
  184. package/src/engine/connect.ts +106 -0
  185. package/src/engine/customers.ts +10 -0
  186. package/src/engine/display.ts +18 -0
  187. package/src/engine/files.ts +28 -0
  188. package/src/engine/invoices.ts +102 -0
  189. package/src/engine/issuing.ts +66 -0
  190. package/src/engine/ledger.ts +48 -0
  191. package/src/engine/oauth.ts +18 -0
  192. package/src/engine/onboarding.ts +53 -0
  193. package/src/{stripe-params.ts → engine/params.ts} +7 -56
  194. package/src/engine/payment-intents.ts +32 -0
  195. package/src/engine/payment-methods.ts +24 -0
  196. package/src/engine/radar.ts +6 -0
  197. package/src/engine/refunds.ts +3 -0
  198. package/src/engine/renewals.ts +72 -0
  199. package/src/{stripe-twin.ts → engine/stripe.ts} +57 -400
  200. package/src/engine/subscriptions.ts +37 -0
  201. package/src/engine/transfers.ts +22 -0
  202. package/src/{stripe-version.ts → engine/version.ts} +19 -10
  203. package/src/engine/webhook-endpoints.ts +14 -0
  204. package/src/engine/webhooks.ts +70 -0
  205. package/src/fetch.ts +27 -0
  206. package/src/generated/surface.gen.json +1 -1
  207. package/src/generated/ui.gen.json +1 -1
  208. package/src/index.ts +10 -116
  209. package/src/manifest.ts +480 -904
  210. package/src/screens/{portal.tsx → billing-portal.tsx} +35 -42
  211. package/src/screens/checkout-js.ts +80 -0
  212. package/src/screens/checkout.tsx +32 -96
  213. package/src/screens/{onboarding.tsx → connect-onboarding.tsx} +39 -85
  214. package/src/screens/dashboard.tsx +178 -0
  215. package/src/screens/shared.tsx +84 -0
  216. package/src/screens/stripe-js.ts +102 -0
  217. package/src/semantics/account.ts +10 -0
  218. package/src/semantics/account_links.ts +20 -0
  219. package/src/semantics/accounts.ts +44 -0
  220. package/src/semantics/{apps-secrets.ts → apps.ts} +17 -33
  221. package/src/semantics/around.ts +17 -0
  222. package/src/semantics/balance.ts +6 -208
  223. package/src/semantics/balance_transactions.ts +18 -0
  224. package/src/semantics/billing_portal.ts +45 -0
  225. package/src/semantics/charges.ts +8 -212
  226. package/src/semantics/checkout.ts +25 -276
  227. package/src/semantics/clock.ts +19 -0
  228. package/src/semantics/coupons.ts +5 -68
  229. package/src/semantics/customers.ts +48 -414
  230. package/src/semantics/doors.ts +79 -0
  231. package/src/semantics/entitlements.ts +3 -94
  232. package/src/semantics/events.ts +37 -0
  233. package/src/semantics/index.ts +89 -0
  234. package/src/semantics/invoice_payments.ts +16 -0
  235. package/src/semantics/invoices.ts +112 -441
  236. package/src/semantics/issuing.ts +57 -573
  237. package/src/semantics/payment_intents.ts +76 -0
  238. package/src/semantics/payment_methods.ts +20 -0
  239. package/src/semantics/payouts.ts +29 -0
  240. package/src/semantics/prices.ts +41 -0
  241. package/src/semantics/products.ts +12 -146
  242. package/src/semantics/promotion_codes.ts +38 -0
  243. package/src/semantics/radar.ts +8 -79
  244. package/src/semantics/refunds.ts +4 -216
  245. package/src/semantics/shared.ts +2089 -135
  246. package/src/semantics/states.ts +662 -0
  247. package/src/semantics/subscriptions.ts +39 -542
  248. package/src/semantics/test_helpers.ts +119 -0
  249. package/src/semantics/transfers.ts +10 -132
  250. package/src/semantics/webhook_endpoints.ts +27 -0
  251. package/src/server.ts +7 -0
  252. package/client/dashboard-api.ts +0 -286
  253. package/client/stripe-mirror.css +0 -277
  254. package/client/stripe-mirror.tsx +0 -1559
  255. package/dist/client/dashboard-api.d.ts +0 -107
  256. package/dist/client/dashboard-api.js +0 -238
  257. package/dist/client/dashboard-api.ts +0 -286
  258. package/dist/client/stripe-mirror.bundle.js +0 -236
  259. package/dist/client/stripe-mirror.css +0 -277
  260. package/dist/client/stripe-mirror.d.ts +0 -134
  261. package/dist/client/stripe-mirror.js +0 -859
  262. package/dist/client/stripe-mirror.tsx +0 -1559
  263. package/dist/src/screens/connect-oauth.d.ts +0 -27
  264. package/dist/src/screens/connect-oauth.js +0 -414
  265. package/dist/src/screens/connect-settings.d.ts +0 -22
  266. package/dist/src/screens/connect-settings.js +0 -103
  267. package/dist/src/screens/consent-skin.d.ts +0 -4
  268. package/dist/src/screens/consent-skin.js +0 -18
  269. package/dist/src/screens/financial-connections.d.ts +0 -5
  270. package/dist/src/screens/financial-connections.js +0 -90
  271. package/dist/src/screens/identity.d.ts +0 -5
  272. package/dist/src/screens/identity.js +0 -86
  273. package/dist/src/screens/onboarding.d.ts +0 -13
  274. package/dist/src/screens/portal.d.ts +0 -5
  275. package/dist/src/screens/public-details.d.ts +0 -5
  276. package/dist/src/screens/public-details.js +0 -90
  277. package/dist/src/semantics/after-payment.d.ts +0 -22
  278. package/dist/src/semantics/after-payment.js +0 -99
  279. package/dist/src/semantics/apps-secrets.d.ts +0 -2
  280. package/dist/src/semantics/billing.d.ts +0 -2
  281. package/dist/src/semantics/billing.js +0 -220
  282. package/dist/src/semantics/connect.d.ts +0 -5
  283. package/dist/src/semantics/connect.js +0 -493
  284. package/dist/src/semantics/credit-notes.d.ts +0 -2
  285. package/dist/src/semantics/credit-notes.js +0 -172
  286. package/dist/src/semantics/disputes.d.ts +0 -2
  287. package/dist/src/semantics/disputes.js +0 -51
  288. package/dist/src/semantics/ephemeral-keys.d.ts +0 -2
  289. package/dist/src/semantics/ephemeral-keys.js +0 -34
  290. package/dist/src/semantics/files.d.ts +0 -2
  291. package/dist/src/semantics/files.js +0 -125
  292. package/dist/src/semantics/ledger.d.ts +0 -59
  293. package/dist/src/semantics/ledger.js +0 -200
  294. package/dist/src/semantics/payment-intents.d.ts +0 -18
  295. package/dist/src/semantics/payment-intents.js +0 -452
  296. package/dist/src/semantics/payment-links.d.ts +0 -2
  297. package/dist/src/semantics/payment-links.js +0 -133
  298. package/dist/src/semantics/payment-methods.d.ts +0 -20
  299. package/dist/src/semantics/payment-methods.js +0 -140
  300. package/dist/src/semantics/plans.d.ts +0 -5
  301. package/dist/src/semantics/plans.js +0 -121
  302. package/dist/src/semantics/platform.d.ts +0 -9
  303. package/dist/src/semantics/platform.js +0 -206
  304. package/dist/src/semantics/renewals.d.ts +0 -47
  305. package/dist/src/semantics/renewals.js +0 -281
  306. package/dist/src/semantics/setup-intents.d.ts +0 -2
  307. package/dist/src/semantics/setup-intents.js +0 -84
  308. package/dist/src/semantics/subscription-schedules.d.ts +0 -2
  309. package/dist/src/semantics/subscription-schedules.js +0 -119
  310. package/dist/src/semantics/tax.d.ts +0 -2
  311. package/dist/src/semantics/tax.js +0 -197
  312. package/dist/src/semantics/terminal.d.ts +0 -5
  313. package/dist/src/semantics/terminal.js +0 -182
  314. package/dist/src/semantics/test-clocks.d.ts +0 -6
  315. package/dist/src/semantics/test-clocks.js +0 -73
  316. package/dist/src/semantics/tokens.d.ts +0 -4
  317. package/dist/src/semantics/tokens.js +0 -44
  318. package/dist/src/semantics/treasury.d.ts +0 -2
  319. package/dist/src/semantics/treasury.js +0 -377
  320. package/dist/src/semantics/webhook-endpoints.d.ts +0 -3
  321. package/dist/src/semantics/webhook-endpoints.js +0 -85
  322. package/dist/src/stripe-budget.d.ts +0 -55
  323. package/dist/src/stripe-budget.js +0 -155
  324. package/dist/src/stripe-capabilities.d.ts +0 -3
  325. package/dist/src/stripe-capabilities.js +0 -5836
  326. package/dist/src/stripe-conformance.d.ts +0 -43
  327. package/dist/src/stripe-conformance.js +0 -105
  328. package/dist/src/stripe-connector.d.ts +0 -161
  329. package/dist/src/stripe-connector.js +0 -414
  330. package/dist/src/stripe-emit.d.ts +0 -2
  331. package/dist/src/stripe-emit.js +0 -145
  332. package/dist/src/stripe-events.d.ts +0 -93
  333. package/dist/src/stripe-events.js +0 -392
  334. package/dist/src/stripe-js.d.ts +0 -4
  335. package/dist/src/stripe-js.js +0 -70
  336. package/dist/src/stripe-mirror-ui.d.ts +0 -15
  337. package/dist/src/stripe-mirror-ui.js +0 -87
  338. package/dist/src/stripe-perform-harness.d.ts +0 -9
  339. package/dist/src/stripe-perform-harness.js +0 -26
  340. package/dist/src/stripe-server.d.ts +0 -33
  341. package/dist/src/stripe-server.js +0 -429
  342. package/dist/src/stripe-shared.d.ts +0 -109
  343. package/dist/src/stripe-shared.js +0 -276
  344. package/dist/src/stripe-ui-conformance.d.ts +0 -5
  345. package/dist/src/stripe-ui-conformance.js +0 -79
  346. package/dist/src/stripe-ui-structure.d.ts +0 -3
  347. package/dist/src/stripe-ui-structure.js +0 -168
  348. package/dist/test-fixtures/stripe-known-deviations.json +0 -110
  349. package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +0 -14
  350. package/dist/test-fixtures/stripe-openapi-operations.json +0 -4717
  351. package/dist/test-fixtures/stripe-schemas.SOURCE.md +0 -35
  352. package/dist/test-fixtures/stripe-schemas.json +0 -3813
  353. package/src/screens/connect-oauth.tsx +0 -400
  354. package/src/screens/connect-settings.tsx +0 -121
  355. package/src/screens/consent-skin.ts +0 -20
  356. package/src/screens/financial-connections.tsx +0 -101
  357. package/src/screens/identity.tsx +0 -96
  358. package/src/screens/public-details.tsx +0 -105
  359. package/src/semantics/after-payment.ts +0 -118
  360. package/src/semantics/billing.ts +0 -216
  361. package/src/semantics/connect.ts +0 -487
  362. package/src/semantics/credit-notes.ts +0 -168
  363. package/src/semantics/disputes.ts +0 -62
  364. package/src/semantics/ephemeral-keys.ts +0 -34
  365. package/src/semantics/files.ts +0 -143
  366. package/src/semantics/ledger.ts +0 -253
  367. package/src/semantics/payment-intents.ts +0 -463
  368. package/src/semantics/payment-links.ts +0 -148
  369. package/src/semantics/payment-methods.ts +0 -145
  370. package/src/semantics/plans.ts +0 -131
  371. package/src/semantics/platform.ts +0 -220
  372. package/src/semantics/renewals.ts +0 -279
  373. package/src/semantics/setup-intents.ts +0 -87
  374. package/src/semantics/subscription-schedules.ts +0 -129
  375. package/src/semantics/tax.ts +0 -220
  376. package/src/semantics/terminal.ts +0 -195
  377. package/src/semantics/test-clocks.ts +0 -77
  378. package/src/semantics/tokens.ts +0 -52
  379. package/src/semantics/treasury.ts +0 -383
  380. package/src/semantics/webhook-endpoints.ts +0 -87
  381. package/src/stripe-budget.ts +0 -181
  382. package/src/stripe-capabilities.ts +0 -5651
  383. package/src/stripe-conformance.ts +0 -124
  384. package/src/stripe-connector.ts +0 -462
  385. package/src/stripe-emit.ts +0 -157
  386. package/src/stripe-events.ts +0 -434
  387. package/src/stripe-js.ts +0 -70
  388. package/src/stripe-mirror-ui.ts +0 -90
  389. package/src/stripe-perform-harness.ts +0 -29
  390. package/src/stripe-server.ts +0 -393
  391. package/src/stripe-shared.ts +0 -297
  392. package/src/stripe-ui-conformance.ts +0 -88
  393. package/src/stripe-ui-structure.ts +0 -182
  394. package/test-fixtures/stripe-known-deviations.json +0 -110
  395. package/test-fixtures/stripe-openapi-operations.json +0 -4717
  396. package/test-fixtures/stripe-schemas.json +0 -3813
  397. /package/dist/src/{screens → engine}/industries.d.ts +0 -0
  398. /package/dist/src/{screens → engine}/industries.js +0 -0
  399. /package/dist/src/{semantics → engine}/test-cards.d.ts +0 -0
  400. /package/dist/src/{semantics → engine}/test-cards.js +0 -0
  401. /package/src/{screens → engine}/industries.ts +0 -0
  402. /package/src/{semantics → engine}/test-cards.ts +0 -0
@@ -0,0 +1,76 @@
1
+ // Stripe's payment_intents operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { PI, TYPES_GIVEN } from '../engine/payment-intents.ts';
5
+ import { asBool, mintClientSecret, nowUnix, validateMoney } from '../engine/stripe.ts';
6
+ import { confirmIntent, intentFields, confirmOnly, methodFromData, paymentIntentsSend } from './shared.ts';
7
+ import { cancelAuthorization, paymentIntentsLoad } from './shared.ts';
8
+ export async function PostPaymentIntents(ctx: HandlerContext): Promise<Response> {
9
+ const params = ctx.params;
10
+ const bad = validateMoney(params);
11
+ if (bad) return paymentIntentsSend(ctx, bad);
12
+ // what describes a confirmation needs one: error_on_requires_action, mandate, mandate_data, off_session and return_url
13
+ // are each, in the served spec, a parameter that "can only be used with `confirm=true`" (shared.ts confirmOnly)
14
+ const unconfirmed = confirmOnly(ctx, ['error_on_requires_action', 'mandate', 'mandate_data', 'off_session', 'return_url'], asBool(params.confirm));
15
+ if (unconfirmed) return unconfirmed;
16
+ // automatic_payment_methods: when enabled, Stripe selects eligible methods and answers the
17
+ // normalized { enabled, allow_redirects } object
18
+ const apmIn = params.automatic_payment_methods;
19
+ const apmEnabled = apmIn && typeof apmIn === 'object' ? asBool((apmIn as Record<string, unknown>).enabled) : false;
20
+ const automatic_payment_methods = apmEnabled ? { enabled: true, allow_redirects: ((apmIn as Record<string, unknown>).allow_redirects as string) ?? 'always' } : null;
21
+ // the methods it may be paid with: allowed_payment_method_types in the served version, payment_method_types for a
22
+ // caller pinned to an earlier one (docs.stripe.com/api/payment_intents/create)
23
+ const given = Array.isArray(params.allowed_payment_method_types) ? params.allowed_payment_method_types : params.payment_method_types;
24
+ const payment_method_types = Array.isArray(given) ? given.map(String) : ['card'];
25
+ // `confirm` is an instruction, not a field: `confirm=true` attempts to confirm the intent at once
26
+ // (https://docs.stripe.com/api/payment_intents/create#create_payment_intent-confirm)
27
+ const { automatic_payment_methods: _a, payment_method_types: _p, allowed_payment_method_types: _ap, id: provided, expand: _e, confirm: confirmNow, payment_method_data: data, mandate_data: _mandate, ...rest } = params;
28
+ // a create's payment_method_data makes its method, as a confirm's does (payment-methods.ts methodFromData)
29
+ const made = await methodFromData(ctx, data);
30
+ if (made) rest.payment_method = made;
31
+ // the id is minted first so the client secret can carry it: Stripe.js parses the id back out
32
+ const id = typeof provided === 'string' && provided ? provided : ctx.mint(PI);
33
+ // it waits for a payment method until it has one, then for its confirmation (manifest.ts)
34
+ const hasMethod = typeof rest.payment_method === 'string' && rest.payment_method !== '';
35
+ if (hasMethod) ctx.legal(PI, 'status', 'PostPaymentIntents', 'requires_payment_method', 'requires_confirmation', id);
36
+ const body = await ctx.write(
37
+ PI,
38
+ id,
39
+ {
40
+ object: 'payment_intent',
41
+ created: nowUnix(ctx.occurredAt),
42
+ status: hasMethod ? 'requires_confirmation' : 'requires_payment_method',
43
+ client_secret: mintClientSecret(id, await ctx.secret(`client-secret:${id}`)),
44
+ livemode: false,
45
+ capture_method: 'automatic',
46
+ amount_capturable: 0,
47
+ amount_received: 0,
48
+ next_action: null,
49
+ automatic_payment_methods,
50
+ payment_method_types,
51
+ ...(Array.isArray(params.allowed_payment_method_types) ? { allowed_payment_method_types: payment_method_types } : {}),
52
+ payment_method_options: (params.payment_method_options as object) ?? {},
53
+ ...intentFields(rest),
54
+ },
55
+ 'payment_intent.create',
56
+ );
57
+ if (Array.isArray(given)) await ctx.record(TYPES_GIVEN, { payment_intent: id }, id);
58
+ if (asBool(confirmNow)) return confirmIntent(ctx, body, { ...params, payment_method: rest.payment_method });
59
+ return ctx.reply(ctx.expand(PI, body));
60
+ }
61
+
62
+
63
+ // source: spec:GetPaymentIntentsSearch "Search for PaymentIntents"
64
+
65
+
66
+
67
+ export async function PostPaymentIntentsIntentCancel(ctx: HandlerContext): Promise<Response> {
68
+ const loaded = paymentIntentsLoad(ctx, 'PostPaymentIntentsIntentCancel');
69
+ if ('answer' in loaded) return loaded.answer;
70
+ const cancellation_reason = typeof ctx.params.cancellation_reason === 'string' ? ctx.params.cancellation_reason : 'requested_by_customer';
71
+ // "For PaymentIntents with a `status` of `requires_capture`, the remaining `amount_capturable` is automatically
72
+ // refunded" (docs.stripe.com/api/payment_intents/cancel): the authorization is released (charges.ts)
73
+ const held = loaded.pi.status === 'requires_capture' && typeof loaded.pi.latest_charge === 'string' ? ctx.get('charge', loaded.pi.latest_charge) : undefined;
74
+ if (held && held.captured === false && held.refunded !== true) await cancelAuthorization(ctx, held);
75
+ return ctx.reply(ctx.expand(PI, await ctx.write(PI, String(loaded.pi.id), { status: 'canceled', cancellation_reason, amount_capturable: 0 }, 'payment_intent.canceled')));
76
+ }
@@ -0,0 +1,20 @@
1
+ // Stripe's payment_methods operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { PM } from '../engine/payment-methods.ts';
5
+ import { at, pmMissing } from './shared.ts';
6
+ export async function GetPaymentMethodsPaymentMethod(ctx: HandlerContext): Promise<Response> {
7
+ const m = ctx.get(PM, at(ctx, 'payment_method'));
8
+ return m ? ctx.reply(m) : pmMissing(ctx, at(ctx, 'payment_method'));
9
+ }
10
+
11
+ // the raw card number, cvc and bank account number are never echoed: the modeled sub-object is
12
+ // what the PaymentMethod carries, with the decline outcome its card implies, so a later charge
13
+ // naming it only by id declines the same way
14
+
15
+
16
+ export async function PostPaymentMethodsPaymentMethodDetach(ctx: HandlerContext): Promise<Response> {
17
+ const id = at(ctx, 'payment_method');
18
+ if (!ctx.get(PM, id)) return pmMissing(ctx, id);
19
+ return ctx.reply(await ctx.write(PM, id, { customer: null }, 'payment_method.detach'));
20
+ }
@@ -0,0 +1,29 @@
1
+ // Stripe's payouts operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { validateMoney } from '../engine/stripe.ts';
5
+ import { account, asOf, created, kept, list, newest, fail, noExternalAccount, payoutBank, payoutDefaults, refusePayout, send, settlePayout } from './shared.ts';
6
+ export async function PostPayouts(ctx: HandlerContext): Promise<Response> {
7
+ const bad = validateMoney(ctx.params);
8
+ if (bad) return send(ctx, bad);
9
+ const acct = account(ctx);
10
+ if (acct && !ctx.get('account', acct)) return fail(ctx, `No such account: '${acct}'`, 400, 'account_invalid');
11
+ const amount = Math.trunc(Number(ctx.params.amount) || 0);
12
+ const currency = String(ctx.params.currency ?? 'usd');
13
+ // a connected account is paid out to its own bank account
14
+ if (acct && !ctx.rows('external_account').some((e) => e.account === acct && (e.currency ?? currency) === currency)) return noExternalAccount(ctx, currency);
15
+ const refused = refusePayout(ctx, amount, currency);
16
+ if (refused) return refused;
17
+ const id = ctx.mint('payout');
18
+ const bt = await settlePayout(ctx, id, -amount, currency);
19
+ return ctx.reply(await created(ctx, 'payout', { ...ctx.params, id }, { status: 'pending', ...payoutDefaults(ctx), balance_transaction: bt, destination: acct ? payoutBank(ctx, acct, currency) : null, ...(acct ? { _account: acct } : {}) }));
20
+ }
21
+
22
+
23
+ // source: https://docs.stripe.com/connect/authentication "Stripe-Account header"
24
+ // source: https://docs.stripe.com/payouts "paid"
25
+ export async function GetPayouts(ctx: HandlerContext): Promise<Response> {
26
+ const acct = account(ctx);
27
+ const payouts = newest(ctx, 'payout').filter((p) => (kept(ctx, 'payout', p, '_account') ?? null) === (acct ?? null));
28
+ return list(ctx, 'payout', payouts.map((p) => asOf(ctx, p)));
29
+ }
@@ -0,0 +1,41 @@
1
+ // Stripe's prices operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import type { Row } from '../engine/common.ts';
5
+ import { asBool } from '../engine/stripe.ts';
6
+ import { at, created, fail, list, newest, tieredPrice, where } from './shared.ts';
7
+ // `type` is not stored (it collides with the tree's discriminator), so `recurring` stands for it
8
+ export async function GetPrices(ctx: HandlerContext): Promise<Response> {
9
+ return list(ctx, 'price', where(ctx, newest(ctx, 'price'), {
10
+ active: (p, v) => asBool(p.active) === asBool(v),
11
+ product: (p, v) => p.product === v,
12
+ currency: (p, v) => p.currency === v,
13
+ type: (p, v) => (v === 'recurring' ? !!p.recurring : !p.recurring),
14
+ lookup_keys: (p, v) => (Array.isArray(v) ? v.map(String) : [String(v)]).includes(String(p.lookup_key)),
15
+ }));
16
+ }
17
+
18
+ export async function GetPricesPrice(ctx: HandlerContext): Promise<Response> {
19
+ const p = ctx.get('price', at(ctx, 'price'));
20
+ return p ? ctx.reply(p) : fail(ctx, `No such price: '${at(ctx, 'price')}'`, 404, 'resource_missing');
21
+ }
22
+
23
+ export async function PostPrices(ctx: HandlerContext): Promise<Response> {
24
+ const params = ctx.params;
25
+ // the product must exist
26
+ const product = typeof params.product === 'string' ? params.product : '';
27
+ if (!product || !ctx.get('product', product)) return fail(ctx, `No such product: '${product}'`, 400, 'resource_missing');
28
+ // a tiered price needs tiers_mode and tiers, each tier with up_to and a unit or flat amount; it
29
+ // has no single unit_amount, and its last tier's up_to is null (∞)
30
+ const scheme = typeof params.billing_scheme === 'string' ? params.billing_scheme : 'per_unit';
31
+ if (scheme === 'tiered') return tieredPrice(ctx, params);
32
+ // a price that recurs is billed by subscriptions; any other is paid once. Its recurring block answers what the create
33
+ // left out as Stripe does: `usage_type` "Defaults to `licensed`", and the create example's answer
34
+ // (docs.stripe.com/api/prices/create) carries `"interval_count": 1, "trial_period_days": null`; a meter only a metered
35
+ // price names
36
+ if (params.recurring && typeof params.recurring === 'object') {
37
+ const r = params.recurring as Row;
38
+ params.recurring = { ...r, interval_count: r.interval_count !== undefined ? Math.trunc(Number(r.interval_count)) : 1, usage_type: r.usage_type ?? 'licensed', trial_period_days: r.trial_period_days !== undefined ? Math.trunc(Number(r.trial_period_days)) : null, meter: r.meter ?? null };
39
+ }
40
+ return ctx.reply(await created(ctx, 'price', params, { active: true, livemode: false, billing_scheme: 'per_unit', type: params.recurring ? 'recurring' : 'one_time', metadata: {} }));
41
+ }
@@ -1,154 +1,20 @@
1
- // Product and Price semantics, with the entitlement features granted to a product. Retrieve of a
2
- // product and the product and price updates (archiving and restoring by `active`, the machines in
3
- // ../manifest.ts) are the derived core's.
4
- import type { Semantics, SemanticsContext } from '@volter/world-core';
5
- import { asBool } from '../stripe-twin.ts';
6
- import { at, created, fail, kept, list, newest, where, type Row } from './shared.ts';
7
-
8
- const productMissing = (ctx: SemanticsContext, id: string): Response => fail(ctx, `No such product: '${id}'`, 404, 'resource_missing');
9
-
10
- const createProduct: Semantics = async (ctx) =>
11
- ctx.reply(await created(ctx, 'product', ctx.params, { active: true, livemode: false, images: [], marketing_features: [], metadata: {}, updated: ctx.now() }));
12
-
13
- const listProducts: Semantics = async (ctx) =>
14
- list(ctx, 'product', where(ctx, newest(ctx, 'product'), {
1
+ // Stripe's products operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { asBool, nowUnix } from '../engine/stripe.ts';
5
+ import { created, list, newest, where } from './shared.ts';
6
+ export async function GetProducts(ctx: HandlerContext): Promise<Response> {
7
+ return list(ctx, 'product', where(ctx, newest(ctx, 'product'), {
15
8
  active: (p, v) => asBool(p.active) === asBool(v),
16
9
  ids: (p, v) => (Array.isArray(v) ? v.map(String).includes(String(p.id)) : String(p.id) === String(v)),
17
10
  }));
18
-
19
- // a product with prices cannot be deleted; Stripe says to deactivate it instead
20
- /** A product deleted while it has prices: "Deleting a product is only possible if it has no prices associated with it"
21
- * (docs.stripe.com/api/products/delete). */
22
- function pricedProductRefused(ctx: SemanticsContext): Response {
23
- return fail(ctx, 'You cannot delete the product because it has one or more prices. Deactivate the product instead.', 400, 'resource_already_exists');
24
11
  }
25
12
 
26
- const deleteProduct: Semantics = async (ctx) => {
27
- const id = at(ctx, 'id');
28
- if (!ctx.get('product', id)) return productMissing(ctx, id);
29
- if (ctx.rows('price').some((p) => p.product === id)) return pricedProductRefused(ctx);
30
- await ctx.write('product', id, { deleted: true }, 'product.delete');
31
- return ctx.reply({ id, object: 'product', deleted: true });
32
- };
33
-
34
- // ── features: an entitlements feature granted to a product, at most once ──
35
-
36
- /** A feature attached to a product that already has it. */
37
- function alreadyAttached(ctx: SemanticsContext): Response {
38
- return fail(ctx, 'This feature is already attached to the product.', 400, 'resource_already_exists');
39
- }
40
-
41
- const attachFeature: Semantics = async (ctx) => {
42
- const product = at(ctx, 'product');
43
- if (!ctx.get('product', product)) return productMissing(ctx, product);
44
- const feature = typeof ctx.params.entitlement_feature === 'string' ? ctx.params.entitlement_feature : '';
45
- if (!feature) return fail(ctx, 'Missing required param: entitlement_feature.', 400, 'parameter_missing');
46
- const feat = ctx.get('entitlements_feature', feature);
47
- if (!feat) return fail(ctx, `No such feature: '${feature}'`, 400, 'resource_missing');
48
- if (ctx.rowsRaw('product_feature').some((pf) => pf._product === product && pf._feature === feature)) return alreadyAttached(ctx);
49
- // Stripe answers the feature itself as the product feature's entitlement_feature (docs.stripe.com/api/product-feature/object)
50
- return ctx.reply(
51
- await created(ctx, 'product_feature', { _product: product, _feature: feature }, {
52
- livemode: false,
53
- entitlement_feature: { id: feature, object: 'entitlements.feature', name: feat.name, lookup_key: feat.lookup_key, active: feat.active, metadata: feat.metadata ?? {}, livemode: false },
54
- }),
55
- );
56
- };
57
-
58
- const features: Semantics = async (ctx) => {
59
- const product = at(ctx, 'product');
60
- if (!ctx.get('product', product)) return productMissing(ctx, product);
61
- return list(ctx, 'product_feature', newest(ctx, 'product_feature').filter((pf) => kept(ctx, 'product_feature', pf, '_product') === product));
62
- };
63
-
64
- const productFeature = (ctx: SemanticsContext): Row | undefined => {
65
- const pf = ctx.get('product_feature', at(ctx, 'id'));
66
- // the product a feature is attached to is its address, not a field Stripe answers
67
- return pf && kept(ctx, 'product_feature', pf, '_product') === at(ctx, 'product') ? pf : undefined;
68
- };
69
- const featureMissing = (ctx: SemanticsContext): Response => fail(ctx, `No such product feature: '${at(ctx, 'id')}'`, 404, 'resource_missing');
70
-
71
- const feature: Semantics = async (ctx) => {
72
- const pf = productFeature(ctx);
73
- return pf ? ctx.reply(pf) : featureMissing(ctx);
74
- };
75
-
76
- const detachFeature: Semantics = async (ctx) => {
77
- if (!productFeature(ctx)) return featureMissing(ctx);
78
- const id = at(ctx, 'id');
79
- // when it came off the product: a subscription keeps it until its next period (semantics/entitlements.ts)
80
- await ctx.write('product_feature', id, { deleted: true, _removed_at: Number(ctx.now()) }, 'product_feature.delete');
81
- return ctx.reply({ id, object: 'product_feature', deleted: true });
82
- };
83
-
84
- // ── prices ──
85
-
86
- /** A tiered price: tiers_mode and tiers, each tier with up_to and a unit or flat amount; no single unit_amount, and
87
- * the last tier's up_to null (∞) (docs.stripe.com/products-prices/pricing-models#tiered-pricing). */
88
- async function tieredPrice(ctx: SemanticsContext, params: Row): Promise<Response> {
89
- const mode = typeof params.tiers_mode === 'string' ? params.tiers_mode : '';
90
- if (mode !== 'graduated' && mode !== 'volume') return fail(ctx, 'Missing required param: tiers_mode (graduated or volume).', 400, 'parameter_missing');
91
- const rawTiers = Array.isArray(params.tiers) ? (params.tiers as Row[]) : [];
92
- if (rawTiers.length === 0) return fail(ctx, 'Missing required param: tiers.', 400, 'parameter_missing');
93
- const tiers = rawTiers.map((t) => {
94
- const upToRaw = t.up_to;
95
- return {
96
- up_to: upToRaw === 'inf' || upToRaw === undefined || upToRaw === null ? null : Math.trunc(Number(upToRaw)),
97
- unit_amount: t.unit_amount !== undefined ? Math.trunc(Number(t.unit_amount)) : null,
98
- unit_amount_decimal: t.unit_amount !== undefined ? String(Math.trunc(Number(t.unit_amount))) : null,
99
- flat_amount: t.flat_amount !== undefined ? Math.trunc(Number(t.flat_amount)) : null,
100
- flat_amount_decimal: t.flat_amount !== undefined ? String(Math.trunc(Number(t.flat_amount))) : null,
101
- };
102
- });
103
- if (tiers.some((t) => t.unit_amount === null && t.flat_amount === null)) return fail(ctx, 'Each tier must specify a unit_amount or flat_amount.', 400, 'parameter_invalid_empty');
104
- const { tiers: _t, ...rest } = params;
105
- return ctx.reply(await created(ctx, 'price', { ...rest, billing_scheme: 'tiered', tiers_mode: mode, tiers, unit_amount: null }, { active: true, livemode: false, type: rest.recurring ? 'recurring' : 'one_time', metadata: {} }));
13
+ export async function PostProducts(ctx: HandlerContext): Promise<Response> {
14
+ return ctx.reply(await created(ctx, 'product', ctx.params, { active: true, livemode: false, images: [], marketing_features: [], metadata: {}, updated: nowUnix(ctx.occurredAt) }));
106
15
  }
107
16
 
108
- const createPrice: Semantics = async (ctx) => {
109
- const params = ctx.params;
110
- // the product must exist
111
- const product = typeof params.product === 'string' ? params.product : '';
112
- if (!product || !ctx.get('product', product)) return fail(ctx, `No such product: '${product}'`, 400, 'resource_missing');
113
- // a tiered price needs tiers_mode and tiers, each tier with up_to and a unit or flat amount; it
114
- // has no single unit_amount, and its last tier's up_to is null (∞)
115
- const scheme = typeof params.billing_scheme === 'string' ? params.billing_scheme : 'per_unit';
116
- if (scheme === 'tiered') return tieredPrice(ctx, params);
117
- // a price that recurs is billed by subscriptions; any other is paid once. Its recurring block answers what the create
118
- // left out as Stripe does: `usage_type` "Defaults to `licensed`", and the create example's answer
119
- // (docs.stripe.com/api/prices/create) carries `"interval_count": 1, "trial_period_days": null`; a meter only a metered
120
- // price names
121
- if (params.recurring && typeof params.recurring === 'object') {
122
- const r = params.recurring as Row;
123
- params.recurring = { ...r, interval_count: r.interval_count !== undefined ? Math.trunc(Number(r.interval_count)) : 1, usage_type: r.usage_type ?? 'licensed', trial_period_days: r.trial_period_days !== undefined ? Math.trunc(Number(r.trial_period_days)) : null, meter: r.meter ?? null };
124
- }
125
- return ctx.reply(await created(ctx, 'price', params, { active: true, livemode: false, billing_scheme: 'per_unit', type: params.recurring ? 'recurring' : 'one_time', metadata: {} }));
126
- };
127
-
128
- // `type` is not stored (it collides with the tree's discriminator), so `recurring` stands for it
129
- const listPrices: Semantics = async (ctx) =>
130
- list(ctx, 'price', where(ctx, newest(ctx, 'price'), {
131
- active: (p, v) => asBool(p.active) === asBool(v),
132
- product: (p, v) => p.product === v,
133
- currency: (p, v) => p.currency === v,
134
- type: (p, v) => (v === 'recurring' ? !!p.recurring : !p.recurring),
135
- lookup_keys: (p, v) => (Array.isArray(v) ? v.map(String) : [String(v)]).includes(String(p.lookup_key)),
136
- }));
137
-
138
- const retrievePrice: Semantics = async (ctx) => {
139
- const p = ctx.get('price', at(ctx, 'price'));
140
- return p ? ctx.reply(p) : fail(ctx, `No such price: '${at(ctx, 'price')}'`, 404, 'resource_missing');
141
- };
17
+ /** `GET /v1/products/search?query=`: the products Stripe's search language selects. */
18
+ // source: spec:GetProductsSearch "Search for products you’ve previously created using Stripe’s"
142
19
 
143
- export const products: Record<string, Semantics> = {
144
- PostProducts: createProduct,
145
- GetProducts: listProducts,
146
- DeleteProductsId: deleteProduct,
147
- PostProductsProductFeatures: attachFeature,
148
- GetProductsProductFeatures: features,
149
- GetProductsProductFeaturesId: feature,
150
- DeleteProductsProductFeaturesId: detachFeature,
151
- PostPrices: createPrice,
152
- GetPrices: listPrices,
153
- GetPricesPrice: retrievePrice,
154
- };
20
+ // source: spec:PostProductsProductFeatures "Creates a product_feature"
@@ -0,0 +1,38 @@
1
+ // Stripe's promotion_codes operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { asBool } from '../engine/stripe.ts';
5
+ import { created, fail, list, newest, where } from './shared.ts';
6
+ export async function GetPromotionCodes(ctx: HandlerContext): Promise<Response> {
7
+ return list(ctx, 'promotion_code', where(ctx, newest(ctx, 'promotion_code'), {
8
+ code: (p, v) => p.code === v,
9
+ active: (p, v) => asBool(p.active) === asBool(v),
10
+ coupon: (p, v) => p.coupon === v,
11
+ customer: (p, v) => p.customer === v,
12
+ }));
13
+ }
14
+
15
+ // a code the caller does not give is derived from the promotion code's id
16
+ export async function PostPromotionCodes(ctx: HandlerContext): Promise<Response> {
17
+ // what it promotes: promotion[type]=coupon and promotion[coupon] (2025-09-30.clover,
18
+ // docs.stripe.com/changelog/clover/2025-09-30/polymorphic-coupon), or the top-level coupon a caller pinned to an
19
+ // earlier version sends; the twin keeps the coupon's id on the code for its rules
20
+ const given = ctx.params;
21
+ const { promotion, coupon: legacy, ...params } = given;
22
+ const promo = promotion && typeof promotion === 'object' ? (promotion as Record<string, unknown>) : undefined;
23
+ if (promo && promo.type !== 'coupon') return fail(ctx, 'Invalid promotion[type]: must be coupon.', 400, 'parameter_invalid_string_enum');
24
+ const coupon = typeof promo?.coupon === 'string' ? promo.coupon : typeof legacy === 'string' ? legacy : '';
25
+ if (!coupon) return fail(ctx, promo ? 'Missing required param: promotion[coupon].' : 'Missing required param: promotion.', 400, 'parameter_missing');
26
+ if (!ctx.get('coupon', coupon)) return fail(ctx, `No such coupon: '${coupon}'`, 400, 'resource_missing');
27
+ const id = ctx.mint('promotion_code');
28
+ const code = typeof params.code === 'string' && params.code ? params.code : `TWIN${id.toUpperCase().replace(/[^A-Z0-9]/g, '')}`;
29
+ return ctx.reply(
30
+ await created(ctx, 'promotion_code', { ...params, coupon, promotion: { type: 'coupon', coupon }, id, code }, {
31
+ active: params.active !== undefined ? asBool(params.active) : true,
32
+ customer: typeof params.customer === 'string' ? params.customer : null,
33
+ expires_at: params.expires_at !== undefined ? Number(params.expires_at) : null,
34
+ max_redemptions: params.max_redemptions !== undefined ? Number(params.max_redemptions) : null,
35
+ times_redeemed: 0, livemode: false, metadata: {}, restrictions: { first_time_transaction: false, minimum_amount: null, minimum_amount_currency: null },
36
+ }),
37
+ );
38
+ }
@@ -1,85 +1,14 @@
1
- // Radar semantics: reviews of payments Radar held (approving closes one, the machine in
2
- // ../manifest.ts) and the value lists custom rules reference, with their items. Review list and
3
- // retrieve, value-list list and retrieve, and value-list-item retrieve are the derived core's.
4
- import type { Semantics, SemanticsContext } from '@volter/world-core';
5
- import { at, created, fail, list, newest } from './shared.ts';
6
-
7
- const approve: Semantics = async (ctx) => {
8
- const id = at(ctx, 'review');
9
- const r = ctx.get('review', id);
10
- if (!r) return fail(ctx, `No such review: '${id}'`, 404, 'resource_missing');
11
- const refused = ctx.legal('review', 'open', 'PostReviewsReviewApprove', r.open === true, undefined, id);
12
- if (refused) return ctx.refuse(refused);
13
- return ctx.reply(await ctx.write('review', id, { open: false, closed_reason: 'approved', reason: 'approved' }, 'review.closed'));
14
- };
15
-
16
- const VL = 'radar.value_list';
17
- const VLI = 'radar.value_list_item';
18
- const listMissing = (ctx: SemanticsContext, id: string, status = 404): Response => fail(ctx, `No such radar value list: '${id}'`, status, 'resource_missing');
19
-
20
- const createList: Semantics = async (ctx) => {
21
- const params = ctx.params;
22
- if (params.alias === undefined || params.alias === '') return fail(ctx, 'Missing required param: alias.', 400, 'parameter_missing');
23
- if (params.name === undefined || params.name === '') return fail(ctx, 'Missing required param: name.', 400, 'parameter_missing');
24
- const made = await created(ctx, VL, params, {
25
- item_type: typeof params.item_type === 'string' ? params.item_type : 'string', livemode: false, metadata: {},
26
- created_by: 'twin', list_items: { object: 'list', data: [], has_more: false, url: '' },
27
- });
28
- await syncItems(ctx, String(made.id));
29
- return ctx.reply(ctx.get(VL, String(made.id))!);
30
- };
31
-
32
- /** A value list's list_items, "List of items contained within this value list" (the served spec), kept in step with
33
- * its items, at the address the fixture names (/v1/radar/value_list_items?value_list=…). */
34
- async function syncItems(ctx: SemanticsContext, listId: string): Promise<void> {
35
- const data = newest(ctx, VLI).filter((i) => i.value_list === listId);
36
- await ctx.write(VL, listId, { list_items: { object: 'list', data, has_more: false, url: `/v1/radar/value_list_items?value_list=${listId}` } }, 'radar.value_list.items_synced');
37
- }
38
-
39
- const updateList: Semantics = async (ctx) => {
40
- const id = at(ctx, 'value_list');
41
- if (!ctx.row(VL, id, { withDeleted: true })) return listMissing(ctx, id);
42
- return ctx.reply(await ctx.write(VL, id, ctx.params, 'radar.value_list.updated'));
43
- };
44
-
45
- const deleteList: Semantics = async (ctx) => {
46
- const id = at(ctx, 'value_list');
47
- if (!ctx.row(VL, id, { withDeleted: true })) return listMissing(ctx, id);
48
- await ctx.write(VL, id, { deleted: true }, 'radar.value_list.deleted');
49
- return ctx.reply({ id, object: 'radar.value_list', deleted: true });
50
- };
51
-
52
- const addItem: Semantics = async (ctx) => {
1
+ // Stripe's radar operations (docs/contributing/architecture.md, "What an author writes"): each handler over the
2
+ // handler contract's context, computing with the engine (../engine/).
3
+ import type { HandlerContext } from '@volter/world-core';
4
+ import { VL, VLI } from '../engine/radar.ts';
5
+ import { created, fail, listMissing, radarSyncItems } from './shared.ts';
6
+ export async function PostRadarValueListItems(ctx: HandlerContext): Promise<Response> {
53
7
  const listId = typeof ctx.params.value_list === 'string' ? ctx.params.value_list : '';
54
8
  if (!listId) return fail(ctx, 'Missing required param: value_list.', 400, 'parameter_missing');
55
9
  if (!ctx.row(VL, listId, { withDeleted: true })) return listMissing(ctx, listId, 400);
56
10
  if (ctx.params.value === undefined || ctx.params.value === '') return fail(ctx, 'Missing required param: value.', 400, 'parameter_missing');
57
11
  const item = await created(ctx, VLI, { value_list: listId, value: ctx.params.value }, { livemode: false, created_by: 'twin' });
58
- await syncItems(ctx, listId);
12
+ await radarSyncItems(ctx, listId);
59
13
  return ctx.reply(item);
60
- };
61
-
62
- const items: Semantics = async (ctx) => {
63
- const listId = typeof ctx.params.value_list === 'string' ? ctx.params.value_list : '';
64
- if (!listId) return fail(ctx, 'Missing required param: value_list.', 400, 'parameter_missing');
65
- return list(ctx, VLI, newest(ctx, VLI).filter((i) => i.value_list === listId));
66
- };
67
-
68
- const removeItem: Semantics = async (ctx) => {
69
- const id = at(ctx, 'item');
70
- const was = ctx.row(VLI, id, { withDeleted: true });
71
- if (!was) return fail(ctx, `No such radar value list item: '${id}'`, 404, 'resource_missing');
72
- await ctx.write(VLI, id, { deleted: true }, 'radar.value_list_item.deleted');
73
- if (typeof was.value_list === 'string' && ctx.get(VL, was.value_list)) await syncItems(ctx, was.value_list);
74
- return ctx.reply({ id, object: 'radar.value_list_item', deleted: true });
75
- };
76
-
77
- export const radar: Record<string, Semantics> = {
78
- PostReviewsReviewApprove: approve,
79
- PostRadarValueLists: createList,
80
- PostRadarValueListsValueList: updateList,
81
- DeleteRadarValueListsValueList: deleteList,
82
- PostRadarValueListItems: addItem,
83
- GetRadarValueListItems: items,
84
- DeleteRadarValueListItemsItem: removeItem,
85
- };
14
+ }