payment-kit 1.29.1 → 1.29.2

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 (310) 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 +36 -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 +27 -24
  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/index.ts +22 -161
  12. package/api/src/integrations/app-store/client.ts +3 -4
  13. package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
  14. package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
  15. package/api/src/integrations/arcblock/token.ts +21 -7
  16. package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
  17. package/api/src/integrations/google-play/handlers/voided.ts +2 -2
  18. package/api/src/integrations/google-play/verify.ts +3 -2
  19. package/api/src/integrations/iap-reconcile.ts +3 -5
  20. package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
  21. package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
  22. package/api/src/libs/archive/query.ts +19 -0
  23. package/api/src/libs/audit.ts +61 -4
  24. package/api/src/libs/auth.ts +99 -38
  25. package/api/src/libs/context.ts +78 -1
  26. package/api/src/libs/currency.ts +2 -2
  27. package/api/src/libs/dayjs.ts +8 -2
  28. package/api/src/libs/drivers/auth-storage.ts +118 -0
  29. package/api/src/libs/drivers/cron.ts +264 -0
  30. package/api/src/libs/drivers/db.ts +170 -0
  31. package/api/src/libs/drivers/identity.ts +81 -0
  32. package/api/src/libs/drivers/index.ts +40 -0
  33. package/api/src/libs/drivers/locks.ts +226 -0
  34. package/api/src/libs/drivers/migrate-runner.ts +70 -0
  35. package/api/src/libs/drivers/queue.ts +104 -0
  36. package/api/src/libs/drivers/secrets.ts +194 -0
  37. package/api/src/libs/env.ts +170 -54
  38. package/api/src/libs/exchange-rate/service.ts +7 -6
  39. package/api/src/libs/http-fetch-adapter.ts +50 -0
  40. package/api/src/libs/invoice.ts +1 -1
  41. package/api/src/libs/lock.ts +51 -47
  42. package/api/src/libs/logger.ts +48 -8
  43. package/api/src/libs/notification/index.ts +1 -1
  44. package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
  45. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
  46. package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
  47. package/api/src/libs/overdraft-protection.ts +1 -1
  48. package/api/src/libs/payout.ts +1 -1
  49. package/api/src/libs/queue/index.ts +259 -52
  50. package/api/src/libs/queue/runtime.ts +175 -0
  51. package/api/src/libs/resource.ts +3 -3
  52. package/api/src/libs/secrets.ts +38 -0
  53. package/api/src/libs/session.ts +3 -2
  54. package/api/src/libs/subscription.ts +5 -5
  55. package/api/src/libs/tenant.ts +92 -0
  56. package/api/src/libs/url.ts +3 -3
  57. package/api/src/libs/util.ts +21 -13
  58. package/api/src/middlewares/hono/cdn.ts +63 -0
  59. package/api/src/middlewares/hono/context.ts +73 -0
  60. package/api/src/middlewares/hono/csrf.ts +72 -0
  61. package/api/src/middlewares/hono/fallback.ts +194 -0
  62. package/api/src/middlewares/hono/pipeline.ts +73 -0
  63. package/api/src/middlewares/hono/resource-mount.ts +42 -0
  64. package/api/src/middlewares/hono/resource.ts +63 -0
  65. package/api/src/middlewares/hono/security.ts +214 -0
  66. package/api/src/middlewares/hono/session.ts +114 -0
  67. package/api/src/middlewares/hono/xss.ts +61 -0
  68. package/api/src/queues/auto-recharge.ts +12 -10
  69. package/api/src/queues/checkout-session.ts +17 -12
  70. package/api/src/queues/credit-consume.ts +40 -36
  71. package/api/src/queues/credit-grant.ts +25 -18
  72. package/api/src/queues/credit-reconciliation.ts +7 -5
  73. package/api/src/queues/discount-status.ts +9 -6
  74. package/api/src/queues/event.ts +12 -4
  75. package/api/src/queues/exchange-rate-health.ts +49 -30
  76. package/api/src/queues/invoice.ts +18 -15
  77. package/api/src/queues/notification.ts +14 -7
  78. package/api/src/queues/payment.ts +41 -28
  79. package/api/src/queues/payout.ts +9 -5
  80. package/api/src/queues/refund.ts +18 -12
  81. package/api/src/queues/subscription.ts +83 -53
  82. package/api/src/queues/token-transfer.ts +15 -10
  83. package/api/src/queues/usage-record.ts +8 -5
  84. package/api/src/queues/vendors/commission.ts +7 -5
  85. package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
  86. package/api/src/queues/vendors/fulfillment.ts +4 -2
  87. package/api/src/queues/vendors/return-processor.ts +5 -3
  88. package/api/src/queues/vendors/return-scanner.ts +5 -4
  89. package/api/src/queues/vendors/status-check.ts +10 -7
  90. package/api/src/queues/webhook.ts +60 -32
  91. package/api/src/routes/connect/shared.ts +1 -2
  92. package/api/src/routes/connect/subscribe.ts +3 -3
  93. package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
  94. package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
  95. package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
  96. package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
  97. package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
  98. package/api/src/routes/hono/credit-tokens.ts +43 -0
  99. package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
  100. package/api/src/routes/{customers.ts → hono/customers.ts} +193 -223
  101. package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
  102. package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
  103. package/api/src/routes/{events.ts → hono/events.ts} +107 -71
  104. package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
  105. package/api/src/routes/hono/exchange-rates.ts +77 -0
  106. package/api/src/routes/hono/index.ts +115 -0
  107. package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
  108. package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
  109. package/api/src/routes/hono/integrations/stripe.ts +74 -0
  110. package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
  111. package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
  112. package/api/src/routes/hono/meters.ts +288 -0
  113. package/api/src/routes/hono/passports.ts +73 -0
  114. package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
  115. package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
  116. package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
  117. package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
  118. package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
  119. package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
  120. package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
  121. package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
  122. package/api/src/routes/{products.ts → hono/products.ts} +172 -159
  123. package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
  124. package/api/src/routes/hono/redirect.ts +24 -0
  125. package/api/src/routes/{refunds.ts → hono/refunds.ts} +96 -80
  126. package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
  127. package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
  128. package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
  129. package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
  130. package/api/src/routes/hono/tool.ts +69 -0
  131. package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
  132. package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
  133. package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
  134. package/api/src/routes/hono/webhook-endpoints.ts +126 -0
  135. package/api/src/service.ts +667 -0
  136. package/api/src/store/migrations/20230911-seeding.ts +2 -1
  137. package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
  138. package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
  139. package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
  140. package/api/src/store/models/auto-recharge-config.ts +22 -10
  141. package/api/src/store/models/checkout-session.ts +15 -14
  142. package/api/src/store/models/coupon.ts +29 -20
  143. package/api/src/store/models/credit-grant.ts +38 -29
  144. package/api/src/store/models/credit-transaction.ts +32 -21
  145. package/api/src/store/models/customer.ts +19 -17
  146. package/api/src/store/models/discount.ts +11 -2
  147. package/api/src/store/models/entitlement-grant.ts +21 -9
  148. package/api/src/store/models/entitlement-product.ts +21 -9
  149. package/api/src/store/models/entitlement.ts +19 -10
  150. package/api/src/store/models/event.ts +18 -9
  151. package/api/src/store/models/exchange-rate-provider.ts +17 -4
  152. package/api/src/store/models/invoice-item.ts +18 -9
  153. package/api/src/store/models/invoice.ts +16 -8
  154. package/api/src/store/models/meter-event.ts +27 -9
  155. package/api/src/store/models/meter.ts +31 -22
  156. package/api/src/store/models/payment-currency.ts +25 -8
  157. package/api/src/store/models/payment-intent.ts +15 -6
  158. package/api/src/store/models/payment-link.ts +15 -6
  159. package/api/src/store/models/payment-method.ts +38 -22
  160. package/api/src/store/models/payment-stat.ts +18 -9
  161. package/api/src/store/models/payout.ts +15 -6
  162. package/api/src/store/models/price-quote.ts +17 -8
  163. package/api/src/store/models/price.ts +24 -12
  164. package/api/src/store/models/pricing-table.ts +29 -20
  165. package/api/src/store/models/product-vendor.ts +20 -10
  166. package/api/src/store/models/product.ts +15 -6
  167. package/api/src/store/models/promotion-code.ts +14 -6
  168. package/api/src/store/models/refund.ts +15 -6
  169. package/api/src/store/models/revenue-snapshot.ts +21 -9
  170. package/api/src/store/models/setting.ts +18 -9
  171. package/api/src/store/models/setup-intent.ts +36 -27
  172. package/api/src/store/models/subscription-item.ts +21 -9
  173. package/api/src/store/models/subscription-schedule.ts +21 -9
  174. package/api/src/store/models/subscription.ts +21 -10
  175. package/api/src/store/models/tax-rate.ts +29 -21
  176. package/api/src/store/models/usage-record.ts +11 -2
  177. package/api/src/store/models/webhook-attempt.ts +18 -9
  178. package/api/src/store/models/webhook-endpoint.ts +18 -9
  179. package/api/src/store/scoped-core.ts +55 -0
  180. package/api/src/store/scoped.ts +247 -0
  181. package/api/src/store/sequelize.ts +66 -22
  182. package/api/src/store/sql-migrations.ts +20 -0
  183. package/api/src/store/tenant-backfill.ts +260 -0
  184. package/api/src/store/tenant-model.ts +124 -0
  185. package/api/src/store/tenant-tables.ts +50 -0
  186. package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
  187. package/api/tests/fixtures/bare-query-violation.ts +13 -0
  188. package/api/tests/fixtures/core-env-violation.ts +10 -0
  189. package/api/tests/fixtures/host-read-violation.ts +19 -0
  190. package/api/tests/fixtures/tenants.ts +4 -0
  191. package/api/tests/integrations/iap-tenant.spec.ts +284 -0
  192. package/api/tests/libs/archive-query.spec.ts +26 -0
  193. package/api/tests/libs/audit-tenant.spec.ts +153 -0
  194. package/api/tests/libs/context.spec.ts +204 -0
  195. package/api/tests/libs/core-config.spec.ts +115 -0
  196. package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
  197. package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
  198. package/api/tests/libs/lock-tenant.spec.ts +66 -0
  199. package/api/tests/libs/scoped.spec.ts +222 -0
  200. package/api/tests/libs/secrets-facade.spec.ts +52 -0
  201. package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
  202. package/api/tests/libs/tenant-middleware.spec.ts +42 -0
  203. package/api/tests/libs/tenant-scanner.spec.ts +120 -0
  204. package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
  205. package/api/tests/middlewares/hono/context.spec.ts +113 -0
  206. package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
  207. package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
  208. package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
  209. package/api/tests/middlewares/hono/security.spec.ts +181 -0
  210. package/api/tests/middlewares/hono/session.spec.ts +42 -0
  211. package/api/tests/middlewares/hono/xss.spec.ts +81 -0
  212. package/api/tests/models/tenant-backfill.spec.ts +287 -0
  213. package/api/tests/models/tenant-columns-model.spec.ts +46 -0
  214. package/api/tests/models/tenant-columns.spec.ts +161 -0
  215. package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
  216. package/api/tests/queues/credit-consume.spec.ts +8 -1
  217. package/api/tests/queues/event-tenant.spec.ts +236 -0
  218. package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
  219. package/api/tests/queues/queue-parity.spec.ts +249 -0
  220. package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
  221. package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
  222. package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
  223. package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
  224. package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
  225. package/api/tests/service/collapse.spec.ts +96 -0
  226. package/api/tests/store/tenant-crosscut.spec.ts +202 -0
  227. package/api/tests/store/tenant-model-spike.spec.ts +177 -0
  228. package/api/tests/store/tenant-model.spec.ts +162 -0
  229. package/api/tests/store/tenant-residual.spec.ts +196 -0
  230. package/api/third.d.ts +4 -0
  231. package/blocklet.yml +1 -1
  232. package/cloudflare/README.md +26 -6
  233. package/cloudflare/build.ts +28 -13
  234. package/cloudflare/did-connect-auth.ts +0 -217
  235. package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
  236. package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
  237. package/cloudflare/migrations/0008_schema_parity.sql +16 -0
  238. package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
  239. package/cloudflare/queue-runtime-mode.ts +13 -0
  240. package/cloudflare/run-build.js +10 -56
  241. package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
  242. package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
  243. package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
  244. package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
  245. package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
  246. package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
  247. package/cloudflare/shims/blocklet-sdk/util-csrf.ts +13 -0
  248. package/cloudflare/shims/blocklet-sdk/util-wallet.ts +8 -0
  249. package/cloudflare/shims/cron.ts +38 -158
  250. package/cloudflare/shims/events.ts +124 -0
  251. package/cloudflare/shims/fastq.ts +15 -1
  252. package/cloudflare/shims/nedb-storage.ts +16 -8
  253. package/cloudflare/shims/xss.ts +8 -0
  254. package/cloudflare/tenant-middleware.ts +36 -0
  255. package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
  256. package/cloudflare/tests/worker-handler-gate.spec.ts +44 -0
  257. package/cloudflare/worker.ts +204 -433
  258. package/cloudflare/wrangler.local-e2e.jsonc +26 -0
  259. package/jest.config.js +3 -1
  260. package/package.json +33 -38
  261. package/scripts/core-env-whitelist.json +1 -0
  262. package/scripts/e2e-12b-runtime.ts +149 -0
  263. package/scripts/e2e-core-config.ts +125 -0
  264. package/scripts/e2e-d1-tenancy.ts +116 -0
  265. package/scripts/e2e-d2-cron-queue.ts +139 -0
  266. package/scripts/e2e-d3-embedded-multi.ts +171 -0
  267. package/scripts/e2e-hono-s2.ts +125 -0
  268. package/scripts/e2e-hono-s3e.ts +135 -0
  269. package/scripts/e2e-hono-s4.ts +114 -0
  270. package/scripts/e2e-migration-contract.ts +100 -0
  271. package/scripts/e2e-s0.ts +61 -0
  272. package/scripts/e2e-s1.ts +107 -0
  273. package/scripts/e2e-s2.ts +178 -0
  274. package/scripts/e2e-s3.ts +110 -0
  275. package/scripts/e2e-s4.ts +191 -0
  276. package/scripts/e2e-s5.ts +139 -0
  277. package/scripts/e2e-s6.ts +127 -0
  278. package/scripts/e2e-tenant-model.ts +119 -0
  279. package/scripts/e2e-tenant-worker.ts +199 -0
  280. package/scripts/gen-sql-migrations.js +46 -0
  281. package/scripts/phase8-codemod.js +219 -0
  282. package/scripts/phase9a-env-getters-codemod.js +82 -0
  283. package/scripts/scan-core-env.js +109 -0
  284. package/scripts/scan-tenant-queries.js +235 -0
  285. package/scripts/schema-drift-guard.ts +210 -0
  286. package/scripts/tenant-scan-whitelist.json +1 -0
  287. package/src/env.d.ts +13 -1
  288. package/tsconfig.json +1 -1
  289. package/api/src/libs/did-space.ts +0 -235
  290. package/api/src/libs/middleware.ts +0 -50
  291. package/api/src/libs/security.ts +0 -192
  292. package/api/src/queues/space.ts +0 -662
  293. package/api/src/routes/credit-tokens.ts +0 -38
  294. package/api/src/routes/exchange-rates.ts +0 -87
  295. package/api/src/routes/index.ts +0 -142
  296. package/api/src/routes/integrations/stripe.ts +0 -61
  297. package/api/src/routes/meters.ts +0 -274
  298. package/api/src/routes/passports.ts +0 -68
  299. package/api/src/routes/redirect.ts +0 -20
  300. package/api/src/routes/tool.ts +0 -65
  301. package/api/src/routes/webhook-endpoints.ts +0 -126
  302. package/api/tests/routes/credit-grants.spec.ts +0 -1261
  303. package/cloudflare/shims/did-space-js.ts +0 -17
  304. package/cloudflare/shims/did-space.ts +0 -11
  305. package/cloudflare/shims/express-compat/index.ts +0 -80
  306. package/cloudflare/shims/express-compat/types.ts +0 -41
  307. package/cloudflare/shims/lock.ts +0 -115
  308. package/cloudflare/shims/queue.ts +0 -611
  309. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
  310. package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
@@ -1,19 +1,23 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
- import { Router } from 'express';
2
+ // Phase 3 (express→hono) hono fork of routes/coupons.ts. Sub-app with
3
+ // routes relative to /api/coupons (mounted via mountResourceGroup). The
4
+ // business logic is unchanged; only the express plumbing becomes hono:
5
+ // req.body → c.get('sanitizedBody') ?? {}; res.status(n).json(x) → c.json(x, n).
6
+ import { Hono } from 'hono';
3
7
  import Joi from 'joi';
4
8
  import pick from 'lodash/pick';
5
9
 
6
10
  import { CustomError, formatError } from '@blocklet/error';
7
11
  import { fromTokenToUnit } from '@ocap/util';
8
- import { authenticate } from '../libs/security';
9
- import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
10
- import { createIdGenerator, formatMetadata } from '../libs/util';
11
- import { trimDecimals } from '../libs/math-utils';
12
- import { Coupon, PaymentCurrency, PromotionCode } from '../store/models';
13
- import { getRedemptionData } from '../libs/discount/redemption';
14
- import logger from '../libs/logger';
15
-
16
- const router = Router();
12
+ import { authenticate } from '../../middlewares/hono/security';
13
+ import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../../libs/api';
14
+ import { createIdGenerator, formatMetadata } from '../../libs/util';
15
+ import { trimDecimals } from '../../libs/math-utils';
16
+ import { Coupon, PaymentCurrency, PromotionCode } from '../../store/models';
17
+ import { getRedemptionData } from '../../libs/discount/redemption';
18
+ import logger from '../../libs/logger';
19
+
20
+ const app = new Hono();
17
21
  const auth = authenticate({ component: true, roles: ['owner', 'admin'] });
18
22
 
19
23
  const PromotionCodeSchema = Joi.object({
@@ -253,35 +257,39 @@ export async function createCouponAndPromotionCodes(payload: any) {
253
257
  * POST /api/coupons
254
258
  * Create a new coupon with optional promotion codes
255
259
  */
256
- router.post('/', auth, async (req, res) => {
260
+ app.post('/', auth, async (c) => {
257
261
  try {
258
- logger.info('Creating coupon with body:', req.body);
259
- const { error, value } = createCouponSchema.validate(req.body);
262
+ const body = c.get('sanitizedBody') ?? {};
263
+ logger.info('Creating coupon with body:', body);
264
+ const { error, value } = createCouponSchema.validate(body);
260
265
  if (error) {
261
- return res.status(400).json({
262
- error: error.details?.[0]?.message || 'Validation error',
263
- });
266
+ return c.json(
267
+ {
268
+ error: error.details?.[0]?.message || 'Validation error',
269
+ },
270
+ 400
271
+ );
264
272
  }
265
273
 
266
274
  const result = await createCouponAndPromotionCodes({
267
275
  ...value,
268
- livemode: req.livemode,
269
- created_via: req.user?.via || 'api',
276
+ livemode: c.get('livemode'),
277
+ created_via: c.get('user')?.via || 'api',
270
278
  });
271
279
 
272
280
  logger.info('Coupon and promotion codes created', {
273
281
  couponId: result.coupon.id,
274
282
  promotionCodesCount: result.promotion_codes.length,
275
- requestedBy: req.user?.did,
283
+ requestedBy: c.get('user')?.did,
276
284
  });
277
285
 
278
- return res.json(result);
286
+ return c.json(result);
279
287
  } catch (error) {
280
288
  logger.error('Error creating coupon', {
281
289
  error,
282
- body: req.body,
290
+ body: c.get('sanitizedBody') ?? {},
283
291
  });
284
- return res.status(500).json(formatError(error));
292
+ return c.json(formatError(error), 500);
285
293
  }
286
294
  });
287
295
 
@@ -298,20 +306,21 @@ const paginationSchema = createListParamSchema<{
298
306
  * GET /api/coupons
299
307
  * List all coupons with pagination and filtering
300
308
  */
301
- router.get('/', auth, async (req, res) => {
302
- const { page, pageSize, valid, name, ...query } = await paginationSchema.validateAsync(req.query, {
309
+ app.get('/', auth, async (c) => {
310
+ const query = c.req.query();
311
+ const { page, pageSize, valid, name, ...rest } = await paginationSchema.validateAsync(query, {
303
312
  stripUnknown: false,
304
313
  allowUnknown: true,
305
314
  });
306
315
 
307
- const where = query.q ? getWhereFromKvQuery(query.q as any) : {};
316
+ const where = rest.q ? getWhereFromKvQuery(rest.q as any) : {};
308
317
 
309
318
  if (valid !== undefined) {
310
319
  where.valid = !!valid;
311
320
  }
312
321
 
313
- if (typeof req.livemode === 'boolean') {
314
- where.livemode = !!req.livemode;
322
+ if (typeof c.get('livemode') === 'boolean') {
323
+ where.livemode = !!c.get('livemode');
315
324
  }
316
325
 
317
326
  if (name) {
@@ -329,10 +338,10 @@ router.get('/', auth, async (req, res) => {
329
338
  ],
330
339
  limit: pageSize,
331
340
  offset: (page - 1) * pageSize,
332
- order: getOrder(req.query, [['created_at', 'DESC']]),
341
+ order: getOrder(query, [['created_at', 'DESC']]),
333
342
  });
334
343
 
335
- return res.json({
344
+ return c.json({
336
345
  count,
337
346
  list: rows,
338
347
  paging: { page, pageSize },
@@ -343,47 +352,51 @@ router.get('/', auth, async (req, res) => {
343
352
  * GET /api/coupons/:id
344
353
  * Retrieve a specific coupon
345
354
  */
346
- router.get('/:id', auth, async (req, res) => {
347
- const coupon = await getExpandedCoupon(req.params.id as string);
355
+ app.get('/:id', auth, async (c) => {
356
+ const coupon = await getExpandedCoupon(c.req.param('id') as string);
348
357
  if (!coupon) {
349
- return res.status(404).json({ error: 'Coupon not found' });
358
+ return c.json({ error: 'Coupon not found' }, 404);
350
359
  }
351
- return res.json(coupon);
360
+ return c.json(coupon);
352
361
  });
353
362
 
354
363
  /**
355
364
  * PUT /api/coupons/:id
356
365
  * Update a coupon (limited fields can be updated)
357
366
  */
358
- router.put('/:id', auth, async (req, res) => {
359
- const { error, value } = updateCouponSchema.validate(req.body);
367
+ app.put('/:id', auth, async (c) => {
368
+ const body = c.get('sanitizedBody') ?? {};
369
+ const { error, value } = updateCouponSchema.validate(body);
360
370
  if (error) {
361
- return res.status(400).json({
362
- error: error.details?.[0]?.message || 'Validation error',
363
- });
371
+ return c.json(
372
+ {
373
+ error: error.details?.[0]?.message || 'Validation error',
374
+ },
375
+ 400
376
+ );
364
377
  }
365
378
 
366
- if (!req.params.id) {
367
- return res.status(400).json({ error: 'Coupon ID is required' });
379
+ if (!c.req.param('id')) {
380
+ return c.json({ error: 'Coupon ID is required' }, 400);
368
381
  }
369
382
 
370
- const coupon = await Coupon.findByPk(req.params.id);
383
+ const coupon = await Coupon.findByPk(c.req.param('id'));
371
384
 
372
385
  if (!coupon) {
373
- return res.status(404).json({ error: 'Coupon not found' });
386
+ return c.json({ error: 'Coupon not found' }, 404);
374
387
  }
375
388
 
376
- if (req.body.metadata) {
377
- const { error: metadataError } = MetadataSchema.validate(req.body.metadata);
389
+ if ((body as any).metadata) {
390
+ const { error: metadataError } = MetadataSchema.validate((body as any).metadata);
378
391
  if (metadataError) {
379
- return res.status(400).json({ error: `metadata invalid: ${metadataError.message}` });
392
+ return c.json({ error: `metadata invalid: ${metadataError.message}` }, 400);
380
393
  }
381
394
  }
382
395
 
383
396
  if (coupon.locked) {
384
397
  const allowedUpdates = pick(value, ['name', 'metadata', 'description']);
385
398
  if (Object.keys(allowedUpdates).length === 0) {
386
- return res.status(403).json({ error: 'Coupon is locked and cannot be modified' });
399
+ return c.json({ error: 'Coupon is locked and cannot be modified' }, 403);
387
400
  }
388
401
  await coupon.update(Coupon.formatBeforeSave(allowedUpdates));
389
402
  }
@@ -402,9 +415,12 @@ router.put('/:id', auth, async (req, res) => {
402
415
  await coupon.update({ locked: true });
403
416
  const allowedUpdates = pick(value, ['name', 'metadata', 'description']);
404
417
  if (Object.keys(allowedUpdates).length === 0) {
405
- return res.status(403).json({
406
- error: 'Coupon is being used. Only name and metadata can be updated.',
407
- });
418
+ return c.json(
419
+ {
420
+ error: 'Coupon is being used. Only name and metadata can be updated.',
421
+ },
422
+ 403
423
+ );
408
424
  }
409
425
  await coupon.update(Coupon.formatBeforeSave(allowedUpdates));
410
426
  } else if (!coupon.locked && !isUsed) {
@@ -413,35 +429,35 @@ router.put('/:id', auth, async (req, res) => {
413
429
  }
414
430
 
415
431
  logger.info('Coupon updated', {
416
- couponId: req.params.id,
432
+ couponId: c.req.param('id'),
417
433
  updatedFields: Object.keys(value),
418
- requestedBy: req.user?.did,
434
+ requestedBy: c.get('user')?.did,
419
435
  });
420
436
 
421
- const doc = await getExpandedCoupon(req.params.id as string);
437
+ const doc = await getExpandedCoupon(c.req.param('id') as string);
422
438
 
423
- return res.json(doc);
439
+ return c.json(doc);
424
440
  });
425
441
 
426
442
  /**
427
443
  * DELETE /api/coupons/:id
428
444
  * Delete a coupon (mark as invalid if used, otherwise hard delete)
429
445
  */
430
- router.delete('/:id', auth, async (req, res) => {
446
+ app.delete('/:id', auth, async (c) => {
431
447
  try {
432
448
  const coupon = await Coupon.findOne({
433
449
  where: {
434
- id: req.params.id,
435
- livemode: req.livemode,
450
+ id: c.req.param('id'),
451
+ livemode: c.get('livemode'),
436
452
  },
437
453
  });
438
454
 
439
455
  if (!coupon) {
440
- return res.status(404).json({ error: 'Coupon not found' });
456
+ return c.json({ error: 'Coupon not found' }, 404);
441
457
  }
442
458
 
443
459
  if (coupon.locked) {
444
- return res.status(403).json({ error: 'Coupon is locked and cannot be deleted' });
460
+ return c.json({ error: 'Coupon is locked and cannot be deleted' }, 403);
445
461
  }
446
462
 
447
463
  const isUsed = await coupon.isUsed();
@@ -450,36 +466,36 @@ router.delete('/:id', auth, async (req, res) => {
450
466
  if (isUsed) {
451
467
  // Mark as invalid instead of deleting
452
468
  await coupon.update({ locked: true });
453
- return res.status(403).json({ error: 'Coupon is being used and cannot be deleted' });
469
+ return c.json({ error: 'Coupon is being used and cannot be deleted' }, 403);
454
470
  }
455
471
 
456
472
  // Hard delete if not used
457
473
  await coupon.destroy();
458
474
 
459
475
  logger.info('Coupon deleted', {
460
- couponId: req.params.id,
476
+ couponId: c.req.param('id'),
461
477
  });
462
478
 
463
- return res.json(coupon);
479
+ return c.json(coupon);
464
480
  } catch (error) {
465
481
  logger.error('Error deleting coupon', {
466
- error: error.message,
467
- couponId: req.params.id,
482
+ error: (error as any).message,
483
+ couponId: c.req.param('id'),
468
484
  });
469
- return res.status(400).json(formatError(error));
485
+ return c.json(formatError(error), 400);
470
486
  }
471
487
  });
472
488
 
473
- router.get('/:id/used', auth, async (req, res) => {
474
- const coupon = await Coupon.findByPk(req.params.id);
489
+ app.get('/:id/used', auth, async (c) => {
490
+ const coupon = await Coupon.findByPk(c.req.param('id'));
475
491
  if (!coupon) {
476
- return res.status(404).json({ error: 'Coupon not found' });
492
+ return c.json({ error: 'Coupon not found' }, 404);
477
493
  }
478
494
  const used = await coupon.isUsed();
479
495
  if (used && !coupon.locked) {
480
496
  await coupon.update({ locked: true });
481
497
  }
482
- return res.json({ used });
498
+ return c.json({ used });
483
499
  });
484
500
 
485
501
  // Create redemptions pagination schema
@@ -490,18 +506,19 @@ const redemptionsSchema = createListParamSchema<{
490
506
  });
491
507
 
492
508
  // Get active redemptions for a coupon with detailed admin analytics
493
- router.get('/:id/redemptions', auth, async (req, res) => {
509
+ app.get('/:id/redemptions', auth, async (c) => {
494
510
  try {
495
- const couponId = req.params.id as string;
511
+ const couponId = c.req.param('id') as string;
512
+ const query = c.req.query();
496
513
 
497
- const { page, pageSize, type } = await redemptionsSchema.validateAsync(req.query, {
514
+ const { page, pageSize, type } = await redemptionsSchema.validateAsync(query, {
498
515
  stripUnknown: false,
499
516
  allowUnknown: true,
500
517
  });
501
518
 
502
519
  const coupon = await Coupon.findByPk(couponId);
503
520
  if (!coupon) {
504
- return res.status(404).json({ error: 'Coupon not found' });
521
+ return c.json({ error: 'Coupon not found' }, 404);
505
522
  }
506
523
 
507
524
  const result = await getRedemptionData(
@@ -511,15 +528,15 @@ router.get('/:id/redemptions', auth, async (req, res) => {
511
528
  'coupon'
512
529
  );
513
530
 
514
- return res.json(result);
531
+ return c.json(result);
515
532
  } catch (error: any) {
516
533
  logger.error('Error getting coupon redemptions', {
517
534
  error: error.message,
518
535
  stack: error.stack,
519
- couponId: req.params.id,
536
+ couponId: c.req.param('id'),
520
537
  });
521
- return res.status(500).json(formatError(error));
538
+ return c.json(formatError(error), 500);
522
539
  }
523
540
  });
524
541
 
525
- export default router;
542
+ export default app;