payment-kit 1.29.1 → 1.29.3

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 (343) hide show
  1. package/api/dev.ts +41 -2
  2. package/api/hono.d.ts +42 -0
  3. package/api/node-sqlite.d.ts +12 -0
  4. package/api/src/bootstrap.ts +47 -0
  5. package/api/src/crons/base.ts +3 -3
  6. package/api/src/crons/currency.ts +1 -1
  7. package/api/src/crons/index.ts +41 -37
  8. package/api/src/crons/metering-subscription-detection.ts +1 -1
  9. package/api/src/crons/overdue-detection.ts +2 -2
  10. package/api/src/crons/retry-pending-events.ts +6 -0
  11. package/api/src/crons/tenant-fanout.ts +82 -0
  12. package/api/src/host-node/did-connect-runtime-node.ts +33 -0
  13. package/api/src/host-node/serve-static-arc.ts +68 -0
  14. package/api/src/host-node/serve-static.ts +41 -0
  15. package/api/src/index.ts +22 -161
  16. package/api/src/integrations/app-store/client.ts +3 -4
  17. package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
  18. package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
  19. package/api/src/integrations/arcblock/token.ts +21 -7
  20. package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
  21. package/api/src/integrations/google-play/handlers/voided.ts +2 -2
  22. package/api/src/integrations/google-play/verify.ts +3 -2
  23. package/api/src/integrations/iap-reconcile.ts +3 -5
  24. package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
  25. package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
  26. package/api/src/libs/archive/query.ts +19 -0
  27. package/api/src/libs/audit.ts +61 -4
  28. package/api/src/libs/auth.ts +247 -47
  29. package/api/src/libs/context.ts +89 -1
  30. package/api/src/libs/currency.ts +2 -2
  31. package/api/src/libs/dayjs.ts +8 -2
  32. package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
  33. package/api/src/libs/did-connect/tenant-identity.ts +221 -0
  34. package/api/src/libs/drivers/auth-storage.ts +118 -0
  35. package/api/src/libs/drivers/cron.ts +264 -0
  36. package/api/src/libs/drivers/db.ts +170 -0
  37. package/api/src/libs/drivers/identity.ts +142 -0
  38. package/api/src/libs/drivers/index.ts +40 -0
  39. package/api/src/libs/drivers/locks.ts +226 -0
  40. package/api/src/libs/drivers/migrate-runner.ts +70 -0
  41. package/api/src/libs/drivers/queue.ts +104 -0
  42. package/api/src/libs/drivers/secrets.ts +194 -0
  43. package/api/src/libs/env.ts +170 -54
  44. package/api/src/libs/exchange-rate/service.ts +7 -6
  45. package/api/src/libs/http-fetch-adapter.ts +60 -0
  46. package/api/src/libs/invoice.ts +1 -1
  47. package/api/src/libs/lock.ts +51 -47
  48. package/api/src/libs/logger.ts +48 -8
  49. package/api/src/libs/notification/index.ts +1 -1
  50. package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
  51. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
  52. package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
  53. package/api/src/libs/overdraft-protection.ts +1 -1
  54. package/api/src/libs/payout.ts +1 -1
  55. package/api/src/libs/queue/index.ts +271 -52
  56. package/api/src/libs/queue/runtime.ts +175 -0
  57. package/api/src/libs/resource.ts +3 -3
  58. package/api/src/libs/secrets.ts +38 -0
  59. package/api/src/libs/session.ts +3 -2
  60. package/api/src/libs/subscription.ts +5 -5
  61. package/api/src/libs/tenant.ts +92 -0
  62. package/api/src/libs/url.ts +3 -3
  63. package/api/src/libs/util.ts +21 -13
  64. package/api/src/middlewares/hono/cdn.ts +63 -0
  65. package/api/src/middlewares/hono/context.ts +80 -0
  66. package/api/src/middlewares/hono/csrf.ts +83 -0
  67. package/api/src/middlewares/hono/fallback.ts +194 -0
  68. package/api/src/middlewares/hono/pipeline.ts +73 -0
  69. package/api/src/middlewares/hono/resource-mount.ts +42 -0
  70. package/api/src/middlewares/hono/resource.ts +63 -0
  71. package/api/src/middlewares/hono/security.ts +209 -0
  72. package/api/src/middlewares/hono/session.ts +114 -0
  73. package/api/src/middlewares/hono/xss.ts +61 -0
  74. package/api/src/queues/auto-recharge.ts +12 -10
  75. package/api/src/queues/checkout-session.ts +38 -21
  76. package/api/src/queues/credit-consume.ts +40 -36
  77. package/api/src/queues/credit-grant.ts +25 -18
  78. package/api/src/queues/credit-reconciliation.ts +7 -5
  79. package/api/src/queues/discount-status.ts +9 -6
  80. package/api/src/queues/event.ts +41 -11
  81. package/api/src/queues/exchange-rate-health.ts +49 -30
  82. package/api/src/queues/invoice.ts +18 -15
  83. package/api/src/queues/notification.ts +14 -7
  84. package/api/src/queues/payment.ts +64 -37
  85. package/api/src/queues/payout.ts +37 -21
  86. package/api/src/queues/refund.ts +36 -18
  87. package/api/src/queues/subscription.ts +83 -53
  88. package/api/src/queues/token-transfer.ts +15 -10
  89. package/api/src/queues/usage-record.ts +8 -5
  90. package/api/src/queues/vendors/commission.ts +7 -5
  91. package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
  92. package/api/src/queues/vendors/fulfillment.ts +4 -2
  93. package/api/src/queues/vendors/return-processor.ts +5 -3
  94. package/api/src/queues/vendors/return-scanner.ts +5 -4
  95. package/api/src/queues/vendors/status-check.ts +10 -7
  96. package/api/src/queues/webhook.ts +60 -32
  97. package/api/src/routes/connect/shared.ts +1 -2
  98. package/api/src/routes/connect/subscribe.ts +3 -3
  99. package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
  100. package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
  101. package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
  102. package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
  103. package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
  104. package/api/src/routes/hono/credit-tokens.ts +43 -0
  105. package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
  106. package/api/src/routes/{customers.ts → hono/customers.ts} +199 -224
  107. package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
  108. package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
  109. package/api/src/routes/{events.ts → hono/events.ts} +107 -71
  110. package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
  111. package/api/src/routes/hono/exchange-rates.ts +77 -0
  112. package/api/src/routes/hono/index.ts +115 -0
  113. package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
  114. package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
  115. package/api/src/routes/hono/integrations/stripe.ts +74 -0
  116. package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
  117. package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
  118. package/api/src/routes/hono/meters.ts +288 -0
  119. package/api/src/routes/hono/passports.ts +73 -0
  120. package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
  121. package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
  122. package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
  123. package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
  124. package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
  125. package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
  126. package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
  127. package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
  128. package/api/src/routes/{products.ts → hono/products.ts} +172 -159
  129. package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
  130. package/api/src/routes/hono/redirect.ts +24 -0
  131. package/api/src/routes/{refunds.ts → hono/refunds.ts} +98 -83
  132. package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
  133. package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
  134. package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
  135. package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
  136. package/api/src/routes/hono/tool.ts +69 -0
  137. package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
  138. package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
  139. package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
  140. package/api/src/routes/hono/webhook-endpoints.ts +126 -0
  141. package/api/src/service.ts +814 -0
  142. package/api/src/store/migrations/20230911-seeding.ts +2 -1
  143. package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
  144. package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
  145. package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
  146. package/api/src/store/models/auto-recharge-config.ts +22 -10
  147. package/api/src/store/models/checkout-session.ts +15 -14
  148. package/api/src/store/models/coupon.ts +29 -20
  149. package/api/src/store/models/credit-grant.ts +38 -29
  150. package/api/src/store/models/credit-transaction.ts +32 -21
  151. package/api/src/store/models/customer.ts +19 -17
  152. package/api/src/store/models/discount.ts +11 -2
  153. package/api/src/store/models/entitlement-grant.ts +21 -9
  154. package/api/src/store/models/entitlement-product.ts +21 -9
  155. package/api/src/store/models/entitlement.ts +19 -10
  156. package/api/src/store/models/event.ts +18 -9
  157. package/api/src/store/models/exchange-rate-provider.ts +17 -4
  158. package/api/src/store/models/invoice-item.ts +18 -9
  159. package/api/src/store/models/invoice.ts +16 -8
  160. package/api/src/store/models/meter-event.ts +27 -9
  161. package/api/src/store/models/meter.ts +31 -22
  162. package/api/src/store/models/payment-currency.ts +25 -8
  163. package/api/src/store/models/payment-intent.ts +15 -6
  164. package/api/src/store/models/payment-link.ts +15 -6
  165. package/api/src/store/models/payment-method.ts +38 -22
  166. package/api/src/store/models/payment-stat.ts +18 -9
  167. package/api/src/store/models/payout.ts +15 -6
  168. package/api/src/store/models/price-quote.ts +17 -8
  169. package/api/src/store/models/price.ts +24 -12
  170. package/api/src/store/models/pricing-table.ts +29 -20
  171. package/api/src/store/models/product-vendor.ts +20 -10
  172. package/api/src/store/models/product.ts +15 -6
  173. package/api/src/store/models/promotion-code.ts +14 -6
  174. package/api/src/store/models/refund.ts +15 -6
  175. package/api/src/store/models/revenue-snapshot.ts +21 -9
  176. package/api/src/store/models/setting.ts +18 -9
  177. package/api/src/store/models/setup-intent.ts +36 -27
  178. package/api/src/store/models/subscription-item.ts +21 -9
  179. package/api/src/store/models/subscription-schedule.ts +21 -9
  180. package/api/src/store/models/subscription.ts +21 -10
  181. package/api/src/store/models/tax-rate.ts +29 -21
  182. package/api/src/store/models/usage-record.ts +11 -2
  183. package/api/src/store/models/webhook-attempt.ts +18 -9
  184. package/api/src/store/models/webhook-endpoint.ts +18 -9
  185. package/api/src/store/scoped-core.ts +55 -0
  186. package/api/src/store/scoped.ts +247 -0
  187. package/api/src/store/sequelize.ts +82 -23
  188. package/api/src/store/sql-migrations.ts +20 -0
  189. package/api/src/store/tenant-backfill.ts +260 -0
  190. package/api/src/store/tenant-model.ts +124 -0
  191. package/api/src/store/tenant-tables.ts +50 -0
  192. package/api/tests/bootstrap/bootstrap.spec.ts +162 -0
  193. package/api/tests/crons/tenant-fanout.spec.ts +158 -0
  194. package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
  195. package/api/tests/fixtures/bare-query-violation.ts +13 -0
  196. package/api/tests/fixtures/core-env-violation.ts +10 -0
  197. package/api/tests/fixtures/host-read-violation.ts +19 -0
  198. package/api/tests/fixtures/tenants.ts +4 -0
  199. package/api/tests/integrations/iap-tenant.spec.ts +284 -0
  200. package/api/tests/libs/archive-query.spec.ts +26 -0
  201. package/api/tests/libs/audit-tenant.spec.ts +153 -0
  202. package/api/tests/libs/context.spec.ts +204 -0
  203. package/api/tests/libs/core-config.spec.ts +115 -0
  204. package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
  205. package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
  206. package/api/tests/libs/did-connect-runtime-js.spec.ts +98 -0
  207. package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -0
  208. package/api/tests/libs/lock-tenant.spec.ts +66 -0
  209. package/api/tests/libs/scoped.spec.ts +222 -0
  210. package/api/tests/libs/secrets-facade.spec.ts +52 -0
  211. package/api/tests/libs/service-host.spec.ts +37 -0
  212. package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
  213. package/api/tests/libs/tenant-middleware.spec.ts +42 -0
  214. package/api/tests/libs/tenant-scanner.spec.ts +120 -0
  215. package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
  216. package/api/tests/middlewares/hono/context.spec.ts +113 -0
  217. package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
  218. package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
  219. package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
  220. package/api/tests/middlewares/hono/security.spec.ts +181 -0
  221. package/api/tests/middlewares/hono/session.spec.ts +42 -0
  222. package/api/tests/middlewares/hono/xss.spec.ts +81 -0
  223. package/api/tests/models/tenant-backfill.spec.ts +287 -0
  224. package/api/tests/models/tenant-columns-model.spec.ts +46 -0
  225. package/api/tests/models/tenant-columns.spec.ts +161 -0
  226. package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
  227. package/api/tests/queues/credit-consume.spec.ts +8 -1
  228. package/api/tests/queues/event-tenant.spec.ts +292 -0
  229. package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
  230. package/api/tests/queues/queue-parity.spec.ts +249 -0
  231. package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
  232. package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
  233. package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
  234. package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
  235. package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
  236. package/api/tests/service/collapse.spec.ts +96 -0
  237. package/api/tests/service/didconnect-storage-slot.spec.ts +60 -0
  238. package/api/tests/service/fail-closed-http.spec.ts +79 -0
  239. package/api/tests/service/static-arc-handler.spec.ts +101 -0
  240. package/api/tests/service/static-externalized.spec.ts +48 -0
  241. package/api/tests/store/tenant-crosscut.spec.ts +202 -0
  242. package/api/tests/store/tenant-model-spike.spec.ts +177 -0
  243. package/api/tests/store/tenant-model.spec.ts +162 -0
  244. package/api/tests/store/tenant-residual.spec.ts +196 -0
  245. package/api/third.d.ts +4 -0
  246. package/blocklet.yml +1 -1
  247. package/cloudflare/MIGRATION-RUNBOOK.md +3 -8
  248. package/cloudflare/README.md +34 -27
  249. package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
  250. package/cloudflare/build.ts +33 -13
  251. package/cloudflare/cf-adapter.ts +419 -0
  252. package/cloudflare/did-connect-runtime.ts +96 -0
  253. package/cloudflare/did-connect-token-storage.ts +151 -0
  254. package/cloudflare/esbuild-cf-config.cjs +407 -0
  255. package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
  256. package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
  257. package/cloudflare/migrations/0008_schema_parity.sql +16 -0
  258. package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
  259. package/cloudflare/queue-runtime-mode.ts +13 -0
  260. package/cloudflare/run-build.js +33 -403
  261. package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
  262. package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
  263. package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
  264. package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
  265. package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
  266. package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
  267. package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
  268. package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
  269. package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +16 -1
  270. package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
  271. package/cloudflare/shims/cron.ts +38 -158
  272. package/cloudflare/shims/events.ts +124 -0
  273. package/cloudflare/shims/fastq.ts +15 -1
  274. package/cloudflare/shims/nedb-storage.ts +16 -8
  275. package/cloudflare/shims/xss.ts +8 -0
  276. package/cloudflare/tenant-middleware.ts +36 -0
  277. package/cloudflare/tests/cf-adapter.spec.ts +244 -0
  278. package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
  279. package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
  280. package/cloudflare/tests/worker-handler-gate.spec.ts +69 -0
  281. package/cloudflare/vite.config.ts +53 -45
  282. package/cloudflare/worker.ts +261 -448
  283. package/cloudflare/wrangler.json +0 -6
  284. package/cloudflare/wrangler.jsonc +0 -6
  285. package/cloudflare/wrangler.local-e2e.jsonc +25 -0
  286. package/cloudflare/wrangler.staging.json +0 -6
  287. package/jest.config.js +3 -1
  288. package/package.json +33 -38
  289. package/scripts/bootstrap-inject.ts +166 -0
  290. package/scripts/core-env-whitelist.json +1 -0
  291. package/scripts/e2e-12b-runtime.ts +149 -0
  292. package/scripts/e2e-core-config.ts +125 -0
  293. package/scripts/e2e-d1-tenancy.ts +116 -0
  294. package/scripts/e2e-d2-cron-queue.ts +139 -0
  295. package/scripts/e2e-d3-embedded-multi.ts +171 -0
  296. package/scripts/e2e-hono-s2.ts +125 -0
  297. package/scripts/e2e-hono-s3e.ts +135 -0
  298. package/scripts/e2e-hono-s4.ts +114 -0
  299. package/scripts/e2e-migration-contract.ts +100 -0
  300. package/scripts/e2e-s0.ts +61 -0
  301. package/scripts/e2e-s1.ts +107 -0
  302. package/scripts/e2e-s2.ts +178 -0
  303. package/scripts/e2e-s3.ts +110 -0
  304. package/scripts/e2e-s4.ts +191 -0
  305. package/scripts/e2e-s5.ts +139 -0
  306. package/scripts/e2e-s6.ts +127 -0
  307. package/scripts/e2e-tenant-model.ts +119 -0
  308. package/scripts/e2e-tenant-worker.ts +199 -0
  309. package/scripts/gen-sql-migrations.js +46 -0
  310. package/scripts/phase8-codemod.js +219 -0
  311. package/scripts/phase9a-env-getters-codemod.js +82 -0
  312. package/scripts/scan-core-env.js +109 -0
  313. package/scripts/scan-tenant-queries.js +235 -0
  314. package/scripts/schema-drift-guard.ts +210 -0
  315. package/scripts/tenant-scan-whitelist.json +1 -0
  316. package/src/app.tsx +2 -1
  317. package/src/env.d.ts +13 -1
  318. package/src/libs/service-host.ts +13 -0
  319. package/tsconfig.json +1 -1
  320. package/vite.arc.config.ts +159 -0
  321. package/api/src/libs/did-space.ts +0 -235
  322. package/api/src/libs/middleware.ts +0 -50
  323. package/api/src/libs/security.ts +0 -192
  324. package/api/src/queues/space.ts +0 -662
  325. package/api/src/routes/credit-tokens.ts +0 -38
  326. package/api/src/routes/exchange-rates.ts +0 -87
  327. package/api/src/routes/index.ts +0 -142
  328. package/api/src/routes/integrations/stripe.ts +0 -61
  329. package/api/src/routes/meters.ts +0 -274
  330. package/api/src/routes/passports.ts +0 -68
  331. package/api/src/routes/redirect.ts +0 -20
  332. package/api/src/routes/tool.ts +0 -65
  333. package/api/src/routes/webhook-endpoints.ts +0 -126
  334. package/api/tests/routes/credit-grants.spec.ts +0 -1261
  335. package/cloudflare/did-connect-auth.ts +0 -527
  336. package/cloudflare/shims/did-space-js.ts +0 -17
  337. package/cloudflare/shims/did-space.ts +0 -11
  338. package/cloudflare/shims/express-compat/index.ts +0 -80
  339. package/cloudflare/shims/express-compat/types.ts +0 -41
  340. package/cloudflare/shims/lock.ts +0 -115
  341. package/cloudflare/shims/queue.ts +0 -611
  342. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
  343. package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
@@ -1,12 +1,17 @@
1
+ // Phase 3 (express→hono) — hono fork of routes/payment-intents.ts. Sub-app with
2
+ // routes relative to /api/payment-intents (mounted via mountResourceGroup). The
3
+ // business logic is unchanged; only the express plumbing becomes hono:
4
+ // req.body → c.get('sanitizedBody'); res.status(n).json(x) → c.json(x, n).
1
5
  import { isValid } from '@arcblock/did';
2
- import { Router } from 'express';
6
+ import { Hono } from 'hono';
3
7
  import Joi from 'joi';
4
8
  import pick from 'lodash/pick';
5
9
  import { Op } from 'sequelize';
6
10
 
7
11
  import { BN, fromTokenToUnit } from '@ocap/util';
8
- import { syncStripeInvoice } from '../integrations/stripe/handlers/invoice';
9
- import { syncStripePayment } from '../integrations/stripe/handlers/payment-intent';
12
+ import type { Context } from 'hono';
13
+ import { syncStripeInvoice } from '../../integrations/stripe/handlers/invoice';
14
+ import { syncStripePayment } from '../../integrations/stripe/handlers/payment-intent';
10
15
  import {
11
16
  BNPositiveValidator,
12
17
  createListParamSchema,
@@ -14,22 +19,23 @@ import {
14
19
  getWhereFromKvQuery,
15
20
  getWhereFromQuery,
16
21
  MetadataSchema,
17
- } from '../libs/api';
18
- import { authenticate } from '../libs/security';
19
- import { formatMetadata } from '../libs/util';
20
- import { paymentQueue } from '../queues/payment';
21
- import { CheckoutSession } from '../store/models/checkout-session';
22
- import { Customer } from '../store/models/customer';
23
- import { Invoice } from '../store/models/invoice';
24
- import { PaymentCurrency } from '../store/models/payment-currency';
25
- import { PaymentIntent } from '../store/models/payment-intent';
26
- import { PaymentMethod } from '../store/models/payment-method';
27
- import { Subscription } from '../store/models/subscription';
28
- import logger from '../libs/logger';
29
- import { Payout, Refund } from '../store/models';
30
- import { getRefundAmountSetup } from '../libs/refund';
31
-
32
- const router = Router();
22
+ } from '../../libs/api';
23
+ import { authenticate } from '../../middlewares/hono/security';
24
+ import { formatMetadata } from '../../libs/util';
25
+ import { paymentQueue } from '../../queues/payment';
26
+ import { CheckoutSession } from '../../store/models/checkout-session';
27
+ import { Customer } from '../../store/models/customer';
28
+ import { Invoice } from '../../store/models/invoice';
29
+ import { PaymentCurrency } from '../../store/models/payment-currency';
30
+ import { PaymentIntent } from '../../store/models/payment-intent';
31
+ import { PaymentMethod } from '../../store/models/payment-method';
32
+ import { Subscription } from '../../store/models/subscription';
33
+ import logger from '../../libs/logger';
34
+ import { Payout, Refund } from '../../store/models';
35
+ import { getRefundAmountSetup } from '../../libs/refund';
36
+
37
+ const app = new Hono();
38
+
33
39
  const authAdmin = authenticate<PaymentIntent>({ component: true, roles: ['owner', 'admin'] });
34
40
  const authMine = authenticate<PaymentIntent>({ component: true, roles: ['owner', 'admin'], mine: true });
35
41
  const authPortal = authenticate<PaymentIntent>({
@@ -42,8 +48,8 @@ const authPortal = authenticate<PaymentIntent>({
42
48
  },
43
49
  });
44
50
 
45
- async function syncStripePaymentAndInvoice(paymentIntent: PaymentIntent, invoice: Invoice | null, req: any) {
46
- const shouldSync = paymentIntent.status !== 'succeeded' || req.query.sync === '1';
51
+ async function syncStripePaymentAndInvoice(paymentIntent: PaymentIntent, invoice: Invoice | null, c: Context) {
52
+ const shouldSync = paymentIntent.status !== 'succeeded' || c.req.query('sync') === '1';
47
53
  if (shouldSync) {
48
54
  await syncStripePayment(paymentIntent);
49
55
  }
@@ -66,8 +72,9 @@ const paginationSchema = createListParamSchema<{
66
72
  customer_did: Joi.string().empty(''),
67
73
  currency_id: Joi.string().empty(''),
68
74
  });
69
- router.get('/', authMine, async (req, res) => {
70
- const { page, pageSize, status, livemode, ...query } = await paginationSchema.validateAsync(req.query, {
75
+
76
+ app.get('/', authMine, async (c) => {
77
+ const { page, pageSize, status, livemode, ...query } = await paginationSchema.validateAsync(c.req.query(), {
71
78
  stripUnknown: false,
72
79
  allowUnknown: true,
73
80
  });
@@ -79,16 +86,15 @@ router.get('/', authMine, async (req, res) => {
79
86
  .map((x) => x.trim())
80
87
  .filter(Boolean);
81
88
  }
82
- if (query.customer_id) {
83
- where.customer_id = query.customer_id;
89
+ if (c.get('customer_id') ?? query.customer_id) {
90
+ where.customer_id = c.get('customer_id') ?? query.customer_id;
84
91
  }
85
92
  if (query.customer_did && isValid(query.customer_did)) {
86
93
  const customer = await Customer.findOne({ where: { did: query.customer_did } });
87
94
  if (customer) {
88
95
  where.customer_id = customer.id;
89
96
  } else {
90
- res.json({ count: 0, list: [] });
91
- return;
97
+ return c.json({ count: 0, list: [] });
92
98
  }
93
99
  }
94
100
  if (query.invoice_id) {
@@ -113,7 +119,7 @@ router.get('/', authMine, async (req, res) => {
113
119
  try {
114
120
  const { rows: list, count } = await PaymentIntent.findAndCountAll({
115
121
  where,
116
- order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
122
+ order: getOrder(c.req.query(), [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
117
123
  offset: (page - 1) * pageSize,
118
124
  limit: pageSize,
119
125
  include: [
@@ -123,10 +129,10 @@ router.get('/', authMine, async (req, res) => {
123
129
  ],
124
130
  });
125
131
 
126
- res.json({ count, list, paging: { page, pageSize } });
132
+ return c.json({ count, list, paging: { page, pageSize } });
127
133
  } catch (err) {
128
134
  logger.error(err);
129
- res.json({ count: 0, list: [], paging: { page, pageSize } });
135
+ return c.json({ count: 0, list: [], paging: { page, pageSize } });
130
136
  }
131
137
  });
132
138
 
@@ -136,8 +142,9 @@ const searchSchema = createListParamSchema<{
136
142
  }>({
137
143
  query: Joi.string(),
138
144
  });
139
- router.get('/search', authMine, async (req, res) => {
140
- const { page, pageSize, query, livemode, q, o } = await searchSchema.validateAsync(req.query, {
145
+
146
+ app.get('/search', authMine, async (c) => {
147
+ const { page, pageSize, query, livemode, q, o } = await searchSchema.validateAsync(c.req.query(), {
141
148
  stripUnknown: false,
142
149
  allowUnknown: true,
143
150
  });
@@ -149,7 +156,7 @@ router.get('/search', authMine, async (req, res) => {
149
156
 
150
157
  const { rows: list, count } = await PaymentIntent.findAndCountAll({
151
158
  where,
152
- order: getOrder(req.query, [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
159
+ order: getOrder(c.req.query(), [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
153
160
  offset: (page - 1) * pageSize,
154
161
  limit: pageSize,
155
162
  include: [
@@ -159,13 +166,79 @@ router.get('/search', authMine, async (req, res) => {
159
166
  ],
160
167
  });
161
168
 
162
- res.json({ count, list, paging: { page, pageSize } });
169
+ return c.json({ count, list, paging: { page, pageSize } });
170
+ });
171
+
172
+ app.get('/:id/retry', authAdmin, async (c) => {
173
+ try {
174
+ const doc = await PaymentIntent.findByPk(c.req.param('id') as string);
175
+ if (!doc) {
176
+ return c.json({ error: 'PaymentIntent not found' }, 404);
177
+ }
178
+ if (doc.status === 'succeeded') {
179
+ return c.json({ error: 'PaymentIntent already done' }, 403);
180
+ }
181
+ if (doc.status === 'processing') {
182
+ return c.json({ error: 'PaymentIntent already processing' }, 403);
183
+ }
184
+
185
+ await doc.update({ status: 'requires_capture', last_payment_error: null });
186
+ await paymentQueue.pushAndWait({
187
+ id: `${doc.id}-retry-${Date.now()}`,
188
+ job: { paymentIntentId: doc.id, retryOnError: false },
189
+ });
190
+ return c.json(doc);
191
+ } catch (err) {
192
+ logger.error(err);
193
+ return c.json(null);
194
+ }
195
+ });
196
+
197
+ app.get('/:id/refundable-amount', authPortal, async (c) => {
198
+ try {
199
+ const doc = await PaymentIntent.findOne({
200
+ where: { id: c.req.param('id') },
201
+ });
202
+
203
+ if (doc) {
204
+ const invoice = await Invoice.findByPk(doc.invoice_id);
205
+ await syncStripePaymentAndInvoice(doc, invoice, c);
206
+ const result = await getRefundAmountSetup({
207
+ paymentIntentId: doc.id,
208
+ currencyId: doc.currency_id,
209
+ customerId: doc.customer_id,
210
+ subscriptionId: invoice?.subscription_id,
211
+ });
212
+ const payouts = await Payout.findAll({
213
+ where: {
214
+ payment_intent_id: doc.id,
215
+ status: {
216
+ [Op.notIn]: ['canceled', 'reverted'],
217
+ },
218
+ },
219
+ attributes: ['id', 'amount'],
220
+ });
221
+ if (payouts.length > 0) {
222
+ let totalPayoutAmount = new BN('0');
223
+ payouts.forEach((payout) => {
224
+ totalPayoutAmount = totalPayoutAmount.add(new BN(payout.amount || '0'));
225
+ });
226
+
227
+ result.amount = new BN(result.amount || '0').sub(totalPayoutAmount).toString();
228
+ }
229
+ return c.json(result);
230
+ }
231
+ return c.json(null, 404);
232
+ } catch (err) {
233
+ logger.error(err);
234
+ return c.json({ error: `Failed to get payment intent refundable amount: ${(err as any).message}` }, 500);
235
+ }
163
236
  });
164
237
 
165
- router.get('/:id', authPortal, async (req, res) => {
238
+ app.get('/:id', authPortal, async (c) => {
166
239
  try {
167
240
  const doc = await PaymentIntent.findOne({
168
- where: { id: req.params.id },
241
+ where: { id: c.req.param('id') },
169
242
  include: [
170
243
  { model: PaymentCurrency, as: 'paymentCurrency' },
171
244
  { model: PaymentMethod, as: 'paymentMethod' },
@@ -179,7 +252,7 @@ router.get('/:id', authPortal, async (req, res) => {
179
252
 
180
253
  if (doc) {
181
254
  invoice = await Invoice.findByPk(doc.invoice_id);
182
- await syncStripePaymentAndInvoice(doc, invoice, req);
255
+ await syncStripePaymentAndInvoice(doc, invoice, c);
183
256
 
184
257
  checkoutSession = await CheckoutSession.findOne({ where: { payment_intent_id: doc.id } });
185
258
  if (invoice && invoice.subscription_id) {
@@ -188,64 +261,37 @@ router.get('/:id', authPortal, async (req, res) => {
188
261
  }
189
262
 
190
263
  if (doc) {
191
- res.json({ ...doc.toJSON(), checkoutSession, invoice, subscription });
192
- } else {
193
- res.status(404).json(null);
264
+ return c.json({ ...doc.toJSON(), checkoutSession, invoice, subscription });
194
265
  }
266
+ return c.json(null, 404);
195
267
  } catch (err) {
196
268
  logger.error(err);
197
- res.status(500).json({ error: `Failed to get payment intent: ${err.message}` });
269
+ return c.json({ error: `Failed to get payment intent: ${(err as any).message}` }, 500);
198
270
  }
199
271
  });
200
272
 
201
- // eslint-disable-next-line consistent-return
202
- router.put('/:id', authAdmin, async (req, res) => {
273
+ app.put('/:id', authAdmin, async (c) => {
203
274
  try {
204
- const doc = await PaymentIntent.findByPk(req.params.id as string);
275
+ const doc = await PaymentIntent.findByPk(c.req.param('id') as string);
205
276
  if (!doc) {
206
- return res.status(404).json({ error: 'PaymentIntent not found' });
277
+ return c.json({ error: 'PaymentIntent not found' }, 404);
207
278
  }
208
279
 
209
- const raw = pick(req.body, ['metadata']);
280
+ const body = c.get('sanitizedBody') ?? {};
281
+ const raw = pick(body, ['metadata']);
210
282
  if (raw.metadata) {
211
283
  const { error: metadataError } = MetadataSchema.validate(raw.metadata);
212
284
  if (metadataError) {
213
- return res.status(400).json({ error: `metadata invalid: ${metadataError.message}` });
285
+ return c.json({ error: `metadata invalid: ${metadataError.message}` }, 400);
214
286
  }
215
287
  raw.metadata = formatMetadata(raw.metadata);
216
288
  }
217
289
 
218
290
  await doc.update(raw);
219
- res.json(doc);
220
- } catch (err) {
221
- logger.error(err);
222
- res.json(null);
223
- }
224
- });
225
-
226
- // eslint-disable-next-line consistent-return
227
- router.get('/:id/retry', authAdmin, async (req, res) => {
228
- try {
229
- const doc = await PaymentIntent.findByPk(req.params.id as string);
230
- if (!doc) {
231
- return res.status(404).json({ error: 'PaymentIntent not found' });
232
- }
233
- if (doc.status === 'succeeded') {
234
- return res.status(403).json({ error: 'PaymentIntent already done' });
235
- }
236
- if (doc.status === 'processing') {
237
- return res.status(403).json({ error: 'PaymentIntent already processing' });
238
- }
239
-
240
- await doc.update({ status: 'requires_capture', last_payment_error: null });
241
- await paymentQueue.pushAndWait({
242
- id: `${doc.id}-retry-${Date.now()}`,
243
- job: { paymentIntentId: doc.id, retryOnError: false },
244
- });
245
- res.json(doc);
291
+ return c.json(doc);
246
292
  } catch (err) {
247
293
  logger.error(err);
248
- res.json(null);
294
+ return c.json(null);
249
295
  }
250
296
  });
251
297
 
@@ -258,15 +304,15 @@ const refundRequestSchema = Joi.object({
258
304
  metadata: Joi.object().optional(),
259
305
  });
260
306
 
261
- // eslint-disable-next-line consistent-return
262
- router.put('/:id/refund', authAdmin, async (req, res) => {
307
+ app.put('/:id/refund', authAdmin, async (c) => {
263
308
  try {
264
- const { error } = refundRequestSchema.validate(req.body);
309
+ const body = c.get('sanitizedBody') ?? {};
310
+ const { error } = refundRequestSchema.validate(body);
265
311
  if (error) {
266
- return res.status(400).json({ error: `payment intent refund request invalid: ${error.message}` });
312
+ return c.json({ error: `payment intent refund request invalid: ${error.message}` }, 400);
267
313
  }
268
314
  const doc = await PaymentIntent.findOne({
269
- where: { id: req.params.id },
315
+ where: { id: c.req.param('id') },
270
316
  include: [
271
317
  { model: PaymentCurrency, as: 'paymentCurrency' },
272
318
  { model: PaymentMethod, as: 'paymentMethod' },
@@ -282,7 +328,7 @@ router.put('/:id/refund', authAdmin, async (req, res) => {
282
328
  }
283
329
 
284
330
  const invoice = await Invoice.findByPk(doc.invoice_id);
285
- await syncStripePaymentAndInvoice(doc, invoice, req);
331
+ await syncStripePaymentAndInvoice(doc, invoice, c);
286
332
  // @ts-ignore
287
333
  const result = await getRefundAmountSetup({
288
334
  paymentIntentId: doc.id,
@@ -294,7 +340,7 @@ router.put('/:id/refund', authAdmin, async (req, res) => {
294
340
  throw new Error('refund amount setup failed');
295
341
  }
296
342
  // @ts-ignore
297
- const amount = fromTokenToUnit(req.body.amount, doc.paymentCurrency?.decimal).toString();
343
+ const amount = fromTokenToUnit((body as any).amount, doc.paymentCurrency?.decimal).toString();
298
344
  const amountBN = new BN(amount);
299
345
 
300
346
  if (amountBN.gt(new BN(result.amount))) {
@@ -305,9 +351,9 @@ router.put('/:id/refund', authAdmin, async (req, res) => {
305
351
  type: 'refund',
306
352
  livemode: doc.livemode,
307
353
  amount,
308
- description: req.body.description || 'payment_intent_cancel',
354
+ description: (body as any).description || 'payment_intent_cancel',
309
355
  status: 'pending',
310
- reason: req.body.reason || 'requested_by_admin',
356
+ reason: (body as any).reason || 'requested_by_admin',
311
357
  currency_id: doc.currency_id,
312
358
  customer_id: doc.customer_id || '',
313
359
  payment_method_id: doc.payment_method_id,
@@ -323,62 +369,20 @@ router.put('/:id/refund', authAdmin, async (req, res) => {
323
369
  starting_token_balance: {},
324
370
  ending_token_balance: {},
325
371
  metadata: {
326
- requested_by: req.user?.did,
372
+ requested_by: c.get('user')?.did,
327
373
  },
328
374
  });
329
375
  logger.info('payment intent refund created', {
330
- ...req.params,
331
- ...req.body,
376
+ id: c.req.param('id'),
377
+ ...pick(body as any, ['amount', 'reason', 'description']),
332
378
  ...pick(result, ['amount', 'totalAmount']),
333
379
  item: item.toJSON(),
334
380
  });
335
- res.json(item.toJSON());
336
- } catch (err) {
337
- logger.error(err);
338
- res.status(500).json({ error: `Failed to payment intent refund: ${err.message}` });
339
- }
340
- });
341
-
342
- router.get('/:id/refundable-amount', authPortal, async (req, res) => {
343
- try {
344
- const doc = await PaymentIntent.findOne({
345
- where: { id: req.params.id },
346
- });
347
-
348
- if (doc) {
349
- const invoice = await Invoice.findByPk(doc.invoice_id);
350
- await syncStripePaymentAndInvoice(doc, invoice, req);
351
- const result = await getRefundAmountSetup({
352
- paymentIntentId: doc.id,
353
- currencyId: doc.currency_id,
354
- customerId: doc.customer_id,
355
- subscriptionId: invoice?.subscription_id,
356
- });
357
- const payouts = await Payout.findAll({
358
- where: {
359
- payment_intent_id: doc.id,
360
- status: {
361
- [Op.notIn]: ['canceled', 'reverted'],
362
- },
363
- },
364
- attributes: ['id', 'amount'],
365
- });
366
- if (payouts.length > 0) {
367
- let totalPayoutAmount = new BN('0');
368
- payouts.forEach((payout) => {
369
- totalPayoutAmount = totalPayoutAmount.add(new BN(payout.amount || '0'));
370
- });
371
-
372
- result.amount = new BN(result.amount || '0').sub(totalPayoutAmount).toString();
373
- }
374
- res.json(result);
375
- } else {
376
- res.status(404).json(null);
377
- }
381
+ return c.json(item.toJSON());
378
382
  } catch (err) {
379
383
  logger.error(err);
380
- res.status(500).json({ error: `Failed to get payment intent refundable amount: ${err.message}` });
384
+ return c.json({ error: `Failed to payment intent refund: ${(err as any).message}` }, 500);
381
385
  }
382
386
  });
383
387
 
384
- export default router;
388
+ export default app;