payment-kit 1.29.0 → 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 (312) 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/docs/2026-06-10-bundle-size-analysis.md +288 -0
  236. package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
  237. package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
  238. package/cloudflare/migrations/0008_schema_parity.sql +16 -0
  239. package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
  240. package/cloudflare/queue-runtime-mode.ts +13 -0
  241. package/cloudflare/run-build.js +31 -56
  242. package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
  243. package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
  244. package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
  245. package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
  246. package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
  247. package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
  248. package/cloudflare/shims/blocklet-sdk/util-csrf.ts +13 -0
  249. package/cloudflare/shims/blocklet-sdk/util-wallet.ts +8 -0
  250. package/cloudflare/shims/cron.ts +38 -158
  251. package/cloudflare/shims/events.ts +124 -0
  252. package/cloudflare/shims/fastq.ts +15 -1
  253. package/cloudflare/shims/nedb-storage.ts +16 -8
  254. package/cloudflare/shims/node-fetch.ts +35 -0
  255. package/cloudflare/shims/xss.ts +8 -0
  256. package/cloudflare/tenant-middleware.ts +36 -0
  257. package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
  258. package/cloudflare/tests/worker-handler-gate.spec.ts +44 -0
  259. package/cloudflare/worker.ts +204 -433
  260. package/cloudflare/wrangler.local-e2e.jsonc +26 -0
  261. package/jest.config.js +3 -1
  262. package/package.json +33 -38
  263. package/scripts/core-env-whitelist.json +1 -0
  264. package/scripts/e2e-12b-runtime.ts +149 -0
  265. package/scripts/e2e-core-config.ts +125 -0
  266. package/scripts/e2e-d1-tenancy.ts +116 -0
  267. package/scripts/e2e-d2-cron-queue.ts +139 -0
  268. package/scripts/e2e-d3-embedded-multi.ts +171 -0
  269. package/scripts/e2e-hono-s2.ts +125 -0
  270. package/scripts/e2e-hono-s3e.ts +135 -0
  271. package/scripts/e2e-hono-s4.ts +114 -0
  272. package/scripts/e2e-migration-contract.ts +100 -0
  273. package/scripts/e2e-s0.ts +61 -0
  274. package/scripts/e2e-s1.ts +107 -0
  275. package/scripts/e2e-s2.ts +178 -0
  276. package/scripts/e2e-s3.ts +110 -0
  277. package/scripts/e2e-s4.ts +191 -0
  278. package/scripts/e2e-s5.ts +139 -0
  279. package/scripts/e2e-s6.ts +127 -0
  280. package/scripts/e2e-tenant-model.ts +119 -0
  281. package/scripts/e2e-tenant-worker.ts +199 -0
  282. package/scripts/gen-sql-migrations.js +46 -0
  283. package/scripts/phase8-codemod.js +219 -0
  284. package/scripts/phase9a-env-getters-codemod.js +82 -0
  285. package/scripts/scan-core-env.js +109 -0
  286. package/scripts/scan-tenant-queries.js +235 -0
  287. package/scripts/schema-drift-guard.ts +210 -0
  288. package/scripts/tenant-scan-whitelist.json +1 -0
  289. package/src/env.d.ts +13 -1
  290. package/tsconfig.json +1 -1
  291. package/api/src/libs/did-space.ts +0 -235
  292. package/api/src/libs/middleware.ts +0 -50
  293. package/api/src/libs/security.ts +0 -192
  294. package/api/src/queues/space.ts +0 -662
  295. package/api/src/routes/credit-tokens.ts +0 -38
  296. package/api/src/routes/exchange-rates.ts +0 -87
  297. package/api/src/routes/index.ts +0 -142
  298. package/api/src/routes/integrations/stripe.ts +0 -61
  299. package/api/src/routes/meters.ts +0 -274
  300. package/api/src/routes/passports.ts +0 -68
  301. package/api/src/routes/redirect.ts +0 -20
  302. package/api/src/routes/tool.ts +0 -65
  303. package/api/src/routes/webhook-endpoints.ts +0 -126
  304. package/api/tests/routes/credit-grants.spec.ts +0 -1261
  305. package/cloudflare/shims/did-space-js.ts +0 -17
  306. package/cloudflare/shims/did-space.ts +0 -11
  307. package/cloudflare/shims/express-compat/index.ts +0 -80
  308. package/cloudflare/shims/express-compat/types.ts +0 -41
  309. package/cloudflare/shims/lock.ts +0 -115
  310. package/cloudflare/shims/queue.ts +0 -611
  311. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
  312. package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
@@ -2,7 +2,9 @@ import type { LiteralUnion } from 'type-fest';
2
2
 
3
3
  import { BN } from '@ocap/util';
4
4
  import { Op } from 'sequelize';
5
- import { createEvent } from '../libs/audit';
5
+ import { paymentReloadSubscriptionJobs } from '../libs/env';
6
+ import { systemFindAll, systemFindByPk, systemFindOne } from '../store/scoped';
7
+ import { createEvent, reportAuditFailure } from '../libs/audit';
6
8
  import { ensurePassportRevoked } from '../integrations/blocklet/passport';
7
9
  // eslint-disable-next-line import/no-cycle
8
10
  import { batchHandleStripeSubscriptions } from '../integrations/stripe/resource';
@@ -13,7 +15,7 @@ import { events } from '../libs/event';
13
15
  import { getLock } from '../libs/lock';
14
16
  import logger from '../libs/logger';
15
17
  import { getGasPayerExtra, isDelegationSufficientForPayment } from '../libs/payment';
16
- import createQueue from '../libs/queue';
18
+ import createQueue, { assertJobObjectTenant } from '../libs/queue';
17
19
  import { getStatementDescriptor } from '../libs/session';
18
20
  import { NonRetryableError } from '../libs/error';
19
21
  import {
@@ -83,7 +85,7 @@ async function attachQuotesForInvoice(
83
85
  return { lineItems, quotes: [] };
84
86
  }
85
87
 
86
- const currency = (await PaymentCurrency.findByPk(currencyId, {
88
+ const currency = (await systemFindByPk(PaymentCurrency, currencyId, {
87
89
  include: [{ model: PaymentMethod, as: 'payment_method' }],
88
90
  })) as PaymentCurrency & { payment_method: PaymentMethod };
89
91
  if (!currency) {
@@ -178,22 +180,24 @@ const doHandleSubscriptionInvoice = async ({
178
180
  metadata?: Record<string, any>;
179
181
  }) => {
180
182
  // Do we still have the customer
181
- const customer = await Customer.findByPk(subscription.customer_id);
183
+ const customer = await systemFindByPk(Customer, subscription.customer_id);
182
184
  if (!customer) {
183
185
  logger.warn(`Customer ${subscription.customer_id} not found for subscription: ${subscription.id}`);
184
186
  return null;
185
187
  }
188
+ assertJobObjectTenant(customer);
186
189
 
187
190
  // Do we still have the currency
188
- const currency = await PaymentCurrency.findByPk(subscription.currency_id);
191
+ const currency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
189
192
  if (!currency) {
190
193
  logger.warn(`Currency ${subscription.currency_id} not found for subscription: ${subscription.id}`);
191
194
  return null;
192
195
  }
196
+ assertJobObjectTenant(currency);
193
197
 
194
198
  // Do not proceed if previous invoice is not immutable
195
199
  if (reason === 'cycle') {
196
- const previous = await Invoice.findOne({
200
+ const previous = await systemFindOne(Invoice, {
197
201
  where: {
198
202
  subscription_id: subscription.id,
199
203
  period_start: subscription.current_period_start,
@@ -203,7 +207,7 @@ const doHandleSubscriptionInvoice = async ({
203
207
  });
204
208
  let existOverdraftProtection;
205
209
  if (previous) {
206
- existOverdraftProtection = await Invoice.findOne({
210
+ existOverdraftProtection = await systemFindOne(Invoice, {
207
211
  where: {
208
212
  subscription_id: subscription.id,
209
213
  billing_reason: 'overdraft_protection',
@@ -220,7 +224,7 @@ const doHandleSubscriptionInvoice = async ({
220
224
 
221
225
  // check if invoice already created for this reason
222
226
  if (['cycle', 'cancel', 'recover'].includes(reason)) {
223
- const exist = await Invoice.findOne({
227
+ const exist = await systemFindOne(Invoice, {
224
228
  where: {
225
229
  subscription_id: subscription.id,
226
230
  period_start: start,
@@ -235,7 +239,7 @@ const doHandleSubscriptionInvoice = async ({
235
239
  }
236
240
 
237
241
  // expand subscription items
238
- const subscriptionItems = await SubscriptionItem.findAll({ where: { subscription_id: subscription.id } });
242
+ const subscriptionItems = await systemFindAll(SubscriptionItem, { where: { subscription_id: subscription.id } });
239
243
  let expandedItems = await Price.expand(
240
244
  subscriptionItems.map((x) => ({ id: x.id, price_id: x.price_id, quantity: x.quantity })),
241
245
  { product: true }
@@ -251,7 +255,7 @@ const doHandleSubscriptionInvoice = async ({
251
255
  createEvent('Subscription', 'usage.report.empty', subscription, {
252
256
  usageReportStart,
253
257
  usageReportEnd,
254
- }).catch(console.error);
258
+ }).catch(reportAuditFailure);
255
259
  logger.info('create usage report empty event', {
256
260
  subscriptionId: subscription.id,
257
261
  usageReportStart,
@@ -542,11 +546,12 @@ export async function handleSubscriptionInvoice(args: Parameters<typeof doHandle
542
546
  }
543
547
 
544
548
  const handleSubscriptionBeforeCancel = async (subscription: Subscription) => {
545
- const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
549
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
546
550
  if (!paymentCurrency) {
547
551
  logger.warn('Payment currency not found for subscription', { subscription: subscription.id });
548
552
  return;
549
553
  }
554
+ assertJobObjectTenant(paymentCurrency);
550
555
  if (paymentCurrency.isCredit()) {
551
556
  logger.info('Skip invoice creation for credit subscription', { subscription: subscription.id });
552
557
  return;
@@ -592,12 +597,12 @@ const handleSubscriptionWhenActive = async (subscription: Subscription) => {
592
597
 
593
598
  // Check if this is a credit subscription
594
599
  const isCredit = await subscription.isConsumesCredit();
595
- const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
600
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
596
601
 
597
602
  if (isCredit && paymentCurrency?.isCredit()) {
598
603
  // For credit subscriptions, check credit availability instead of creating invoices
599
- const customer = await Customer.findByPk(subscription.customer_id);
600
- const paymentMethod = await PaymentMethod.findByPk(subscription.default_payment_method_id);
604
+ const customer = await systemFindByPk(Customer, subscription.customer_id);
605
+ const paymentMethod = await systemFindByPk(PaymentMethod, subscription.default_payment_method_id);
601
606
 
602
607
  if (!customer || !paymentMethod || !paymentCurrency) {
603
608
  logger.warn('Credit subscription cycle skipped due to missing dependencies', {
@@ -757,7 +762,7 @@ const handleFinalInvoicePayment = async (
757
762
  paymentCurrency: PaymentCurrency
758
763
  ) => {
759
764
  // Check if there's any unpaid final metered invoice
760
- const lastInvoice = await Invoice.findOne({
765
+ const lastInvoice = await systemFindOne(Invoice, {
761
766
  where: {
762
767
  subscription_id: subscription.id,
763
768
  billing_reason: 'subscription_cancel',
@@ -775,7 +780,7 @@ const handleFinalInvoicePayment = async (
775
780
  }
776
781
 
777
782
  // Check payment status and handle accordingly
778
- const paymentIntent = await PaymentIntent.findByPk(lastInvoice.payment_intent_id);
783
+ const paymentIntent = await systemFindByPk(PaymentIntent, lastInvoice.payment_intent_id);
779
784
  if (!paymentIntent) {
780
785
  logger.warn('PaymentIntent not found for final invoice', {
781
786
  subscription: subscription.id,
@@ -783,6 +788,7 @@ const handleFinalInvoicePayment = async (
783
788
  });
784
789
  return;
785
790
  }
791
+ assertJobObjectTenant(paymentIntent);
786
792
 
787
793
  // If payment already succeeded, skip processing
788
794
  if (paymentIntent.status === 'succeeded') {
@@ -794,7 +800,7 @@ const handleFinalInvoicePayment = async (
794
800
  return;
795
801
  }
796
802
 
797
- const customer = await Customer.findByPk(subscription.customer_id);
803
+ const customer = await systemFindByPk(Customer, subscription.customer_id);
798
804
  if (!customer) {
799
805
  logger.warn('Final invoice settlement skipped because customer not found', {
800
806
  subscription: subscription.id,
@@ -802,6 +808,7 @@ const handleFinalInvoicePayment = async (
802
808
  });
803
809
  return;
804
810
  }
811
+ assertJobObjectTenant(customer);
805
812
 
806
813
  logger.info('Found unpaid final invoice, checking user delegation balance', {
807
814
  subscription: subscription.id,
@@ -834,7 +841,7 @@ const handleFinalInvoicePayment = async (
834
841
  };
835
842
 
836
843
  export const handleStakeSlashAfterCancel = async (subscription: Subscription, forceSlash: boolean = false) => {
837
- const invoice = await Invoice.findByPk(subscription.latest_invoice_id);
844
+ const invoice = await systemFindByPk(Invoice, subscription.latest_invoice_id);
838
845
  if (!invoice || (invoice.status !== 'uncollectible' && !forceSlash)) {
839
846
  logger.warn('Stake slashing aborted because invoice status', {
840
847
  subscription: subscription.id,
@@ -843,7 +850,7 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
843
850
  });
844
851
  return;
845
852
  }
846
- const currency = await PaymentCurrency.findByPk(invoice.currency_id || subscription.currency_id);
853
+ const currency = await systemFindByPk(PaymentCurrency, invoice.currency_id || subscription.currency_id);
847
854
  if (!currency) {
848
855
  logger.warn('Stake slashing aborted because currency not found', {
849
856
  subscription: subscription.id,
@@ -852,7 +859,8 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
852
859
  });
853
860
  return;
854
861
  }
855
- const method = await PaymentMethod.findByPk(currency.payment_method_id);
862
+ assertJobObjectTenant(currency);
863
+ const method = await systemFindByPk(PaymentMethod, currency.payment_method_id);
856
864
  if (!method || method.type !== 'arcblock') {
857
865
  logger.warn('Stake slashing aborted because payment method not arcblock', {
858
866
  subscription: subscription.id,
@@ -861,7 +869,7 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
861
869
  });
862
870
  return;
863
871
  }
864
- const customer = await Customer.findByPk(subscription.customer_id);
872
+ const customer = await systemFindByPk(Customer, subscription.customer_id);
865
873
  if (!customer) {
866
874
  logger.warn('Stake slashing aborted because customer not found', {
867
875
  subscription: subscription.id,
@@ -870,7 +878,8 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
870
878
  });
871
879
  return;
872
880
  }
873
- const paymentIntent = await PaymentIntent.findByPk(invoice.payment_intent_id);
881
+ assertJobObjectTenant(customer);
882
+ const paymentIntent = await systemFindByPk(PaymentIntent, invoice.payment_intent_id);
874
883
  if (!paymentIntent) {
875
884
  logger.warn('Stake slashing aborted because payment intent not found', {
876
885
  subscription: subscription.id,
@@ -878,6 +887,7 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
878
887
  });
879
888
  return;
880
889
  }
890
+ assertJobObjectTenant(paymentIntent);
881
891
 
882
892
  // Use lock to prevent race condition with payment queue
883
893
  const lock = getLock(`payment-${paymentIntent.id}`);
@@ -1023,7 +1033,7 @@ export const handleStakeSlashAfterCancel = async (subscription: Subscription, fo
1023
1033
  };
1024
1034
 
1025
1035
  const ensureReturnStake = async (subscription: Subscription, paymentCurrencyId?: string, stakingAddress?: string) => {
1026
- const paymentCurrency = await PaymentCurrency.findByPk(paymentCurrencyId || subscription.currency_id);
1036
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, paymentCurrencyId || subscription.currency_id);
1027
1037
  if (!paymentCurrency) {
1028
1038
  logger.warn('Stake return skipped because no payment currency', {
1029
1039
  subscription: subscription.id,
@@ -1031,7 +1041,9 @@ const ensureReturnStake = async (subscription: Subscription, paymentCurrencyId?:
1031
1041
  });
1032
1042
  return;
1033
1043
  }
1034
- const paymentMethod = await PaymentMethod.findByPk(
1044
+ assertJobObjectTenant(paymentCurrency);
1045
+ const paymentMethod = await systemFindByPk(
1046
+ PaymentMethod,
1035
1047
  paymentCurrency.payment_method_id || subscription.default_payment_method_id
1036
1048
  );
1037
1049
  if (paymentMethod?.type !== 'arcblock') {
@@ -1066,7 +1078,7 @@ const ensureReturnStake = async (subscription: Subscription, paymentCurrencyId?:
1066
1078
  return;
1067
1079
  }
1068
1080
  if (result.return_amount !== '0') {
1069
- const invoice = await Invoice.findOne({
1081
+ const invoice = await systemFindOne(Invoice, {
1070
1082
  where: {
1071
1083
  billing_reason: 'stake',
1072
1084
  subscription_id: subscription.id,
@@ -1122,7 +1134,7 @@ const ensureReturnStake = async (subscription: Subscription, paymentCurrencyId?:
1122
1134
  };
1123
1135
 
1124
1136
  const slashStakeOnCancel = async (subscription: Subscription) => {
1125
- const paymentMethod = await PaymentMethod.findByPk(subscription.default_payment_method_id);
1137
+ const paymentMethod = await systemFindByPk(PaymentMethod, subscription.default_payment_method_id);
1126
1138
  if (paymentMethod?.type !== 'arcblock') {
1127
1139
  logger.warn('Stake slashing skipped because payment method not arcblock', {
1128
1140
  subscription: subscription.id,
@@ -1130,7 +1142,7 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
1130
1142
  });
1131
1143
  return;
1132
1144
  }
1133
- const customer = await Customer.findByPk(subscription.customer_id);
1145
+ const customer = await systemFindByPk(Customer, subscription.customer_id);
1134
1146
  if (!customer) {
1135
1147
  logger.warn('Stake slashing skipped because customer not found', {
1136
1148
  subscription: subscription.id,
@@ -1138,7 +1150,8 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
1138
1150
  });
1139
1151
  return;
1140
1152
  }
1141
- const currency = await PaymentCurrency.findByPk(subscription.currency_id);
1153
+ assertJobObjectTenant(customer);
1154
+ const currency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
1142
1155
  if (!currency) {
1143
1156
  logger.warn('Stake slashing skipped because currency not found', {
1144
1157
  subscription: subscription.id,
@@ -1146,6 +1159,7 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
1146
1159
  });
1147
1160
  return;
1148
1161
  }
1162
+ assertJobObjectTenant(currency);
1149
1163
  const address = await getSubscriptionStakeAddress(subscription, customer.did, paymentMethod);
1150
1164
  const result = await getSubscriptionStakeSlashSetup(subscription, address, paymentMethod);
1151
1165
  const stakeEnough = await checkRemainingStake(paymentMethod, currency, address, result.return_amount);
@@ -1169,7 +1183,7 @@ const slashStakeOnCancel = async (subscription: Subscription) => {
1169
1183
  }
1170
1184
 
1171
1185
  // FIXME: handle exist one more invoices
1172
- const invoice = await Invoice.findOne({
1186
+ const invoice = await systemFindOne(Invoice, {
1173
1187
  where: {
1174
1188
  subscription_id: subscription.id,
1175
1189
  billing_reason: 'slash_stake',
@@ -1235,13 +1249,14 @@ const ensureRefundOnCancel = async (subscription: Subscription) => {
1235
1249
  });
1236
1250
  return;
1237
1251
  }
1238
- const lastInvoice = await Invoice.findByPk(subscription.latest_invoice_id);
1252
+ const lastInvoice = await systemFindByPk(Invoice, subscription.latest_invoice_id);
1239
1253
  if (!lastInvoice) {
1240
1254
  logger.warn('Refund skipped because no latest invoice', {
1241
1255
  subscription: subscription.id,
1242
1256
  });
1243
1257
  return;
1244
1258
  }
1259
+ assertJobObjectTenant(lastInvoice);
1245
1260
 
1246
1261
  const result = await getSubscriptionRefundSetup(subscription, subscription.cancel_at, lastInvoice.currency_id);
1247
1262
  if (result.remainingUnused === '0') {
@@ -1251,7 +1266,7 @@ const ensureRefundOnCancel = async (subscription: Subscription) => {
1251
1266
  });
1252
1267
  return;
1253
1268
  }
1254
- const currency = await PaymentCurrency.findByPk(lastInvoice?.currency_id);
1269
+ const currency = await systemFindByPk(PaymentCurrency, lastInvoice?.currency_id);
1255
1270
  const item = await Refund.create({
1256
1271
  type: 'refund',
1257
1272
  livemode: subscription.livemode,
@@ -1299,7 +1314,7 @@ const ensureReturnOverdraftProtectionStake = async (subscription: Subscription,
1299
1314
  });
1300
1315
  return;
1301
1316
  }
1302
- const paymentCurrency = await PaymentCurrency.findByPk(paymentCurrencyId || subscription.currency_id);
1317
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, paymentCurrencyId || subscription.currency_id);
1303
1318
  if (!paymentCurrency) {
1304
1319
  logger.warn('Return overdraft protection stake skipped because currency not found', {
1305
1320
  subscription: subscription.id,
@@ -1307,7 +1322,8 @@ const ensureReturnOverdraftProtectionStake = async (subscription: Subscription,
1307
1322
  });
1308
1323
  return;
1309
1324
  }
1310
- const paymentMethod = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
1325
+ assertJobObjectTenant(paymentCurrency);
1326
+ const paymentMethod = await systemFindByPk(PaymentMethod, paymentCurrency.payment_method_id);
1311
1327
  if (!paymentMethod) {
1312
1328
  logger.warn('Return overdraft protection stake skipped because payment method not found', {
1313
1329
  subscription: subscription.id,
@@ -1315,6 +1331,7 @@ const ensureReturnOverdraftProtectionStake = async (subscription: Subscription,
1315
1331
  });
1316
1332
  return;
1317
1333
  }
1334
+ assertJobObjectTenant(paymentMethod);
1318
1335
  if (paymentMethod?.type !== 'arcblock') {
1319
1336
  logger.info('Return overdraft protection stake skipped because payment method is not arcblock', {
1320
1337
  subscription: subscription.id,
@@ -1346,7 +1363,7 @@ const ensureSlashOverdraftProtectionStake = async (subscription: Subscription) =
1346
1363
  });
1347
1364
  return;
1348
1365
  }
1349
- const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
1366
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
1350
1367
  if (!paymentCurrency) {
1351
1368
  logger.warn('Slash overdraft protection stake skipped because currency not found', {
1352
1369
  subscription: subscription.id,
@@ -1354,7 +1371,8 @@ const ensureSlashOverdraftProtectionStake = async (subscription: Subscription) =
1354
1371
  });
1355
1372
  return;
1356
1373
  }
1357
- const paymentMethod = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
1374
+ assertJobObjectTenant(paymentCurrency);
1375
+ const paymentMethod = await systemFindByPk(PaymentMethod, paymentCurrency.payment_method_id);
1358
1376
  if (!paymentMethod) {
1359
1377
  logger.warn('Slash overdraft protection stake skipped because payment method not found', {
1360
1378
  subscription: subscription.id,
@@ -1362,6 +1380,7 @@ const ensureSlashOverdraftProtectionStake = async (subscription: Subscription) =
1362
1380
  });
1363
1381
  return;
1364
1382
  }
1383
+ assertJobObjectTenant(paymentMethod);
1365
1384
  if (paymentMethod?.type !== 'arcblock') {
1366
1385
  logger.info('Slash overdraft protection stake skipped because payment method is not arcblock', {
1367
1386
  subscription: subscription.id,
@@ -1386,11 +1405,12 @@ const ensureSlashOverdraftProtectionStake = async (subscription: Subscription) =
1386
1405
  export const handleSubscription = async (job: SubscriptionJob) => {
1387
1406
  logger.info('handle subscription', job);
1388
1407
 
1389
- const subscription = await Subscription.findByPk(job.subscriptionId);
1408
+ const subscription = await systemFindByPk(Subscription, job.subscriptionId);
1390
1409
  if (!subscription) {
1391
1410
  logger.warn('Subscription not found', { subscription: job.subscriptionId });
1392
1411
  return;
1393
1412
  }
1413
+ assertJobObjectTenant(subscription);
1394
1414
  if (EXPECTED_SUBSCRIPTION_STATUS.includes(subscription.status) === false) {
1395
1415
  logger.warn('Subscription status not expected', { subscription: subscription.id, status: subscription.status });
1396
1416
  return;
@@ -1468,7 +1488,7 @@ export const subscriptionQueue = createQueue<SubscriptionJob>({
1468
1488
  * Checks for subscriptions that may have missed billing periods during downtime
1469
1489
  */
1470
1490
  export const handleCreditSubscriptionRecovery = async () => {
1471
- const lock = getLock('creditSubscriptionRecovery');
1491
+ const lock = getLock('creditSubscriptionRecovery', { scope: 'global' });
1472
1492
  if (lock.locked) {
1473
1493
  return;
1474
1494
  }
@@ -1478,7 +1498,7 @@ export const handleCreditSubscriptionRecovery = async () => {
1478
1498
  await lock.acquire();
1479
1499
 
1480
1500
  // Find active credit subscriptions that might need recovery
1481
- const creditSubscriptions = await Subscription.findAll({
1501
+ const creditSubscriptions = await systemFindAll(Subscription, {
1482
1502
  where: {
1483
1503
  status: ['active', 'trialing'],
1484
1504
  },
@@ -1565,7 +1585,7 @@ export const handleCreditSubscriptionRecovery = async () => {
1565
1585
  };
1566
1586
 
1567
1587
  export const startSubscriptionQueue = async () => {
1568
- const lock = getLock('startSubscriptionQueue');
1588
+ const lock = getLock('startSubscriptionQueue', { scope: 'global' });
1569
1589
  if (lock.locked) {
1570
1590
  return;
1571
1591
  }
@@ -1576,7 +1596,7 @@ export const startSubscriptionQueue = async () => {
1576
1596
  // First handle credit subscription recovery
1577
1597
  await handleCreditSubscriptionRecovery();
1578
1598
 
1579
- const subscriptions = await Subscription.findAll({
1599
+ const subscriptions = await systemFindAll(Subscription, {
1580
1600
  where: {
1581
1601
  status: EXPECTED_SUBSCRIPTION_STATUS,
1582
1602
  },
@@ -1603,7 +1623,7 @@ export const startSubscriptionQueue = async () => {
1603
1623
  return;
1604
1624
  }
1605
1625
  logger.info('add subscription job', { subscription: x.id, action: 'cycle' });
1606
- await addSubscriptionJob(x, 'cycle', process.env.PAYMENT_RELOAD_SUBSCRIPTION_JOBS === '1');
1626
+ await addSubscriptionJob(x, 'cycle', paymentReloadSubscriptionJobs());
1607
1627
  })
1608
1628
  );
1609
1629
 
@@ -1624,10 +1644,11 @@ export const slashStakeQueue = createQueue({
1624
1644
  name: 'slashStake',
1625
1645
  onJob: async (job) => {
1626
1646
  const { subscriptionId } = job;
1627
- const subscription = await Subscription.findByPk(subscriptionId);
1647
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1628
1648
  if (!subscription) {
1629
1649
  return;
1630
1650
  }
1651
+ assertJobObjectTenant(subscription);
1631
1652
  await slashStakeOnCancel(subscription);
1632
1653
  },
1633
1654
  options: {
@@ -1643,10 +1664,11 @@ export const returnStakeQueue = createQueue({
1643
1664
  name: 'returnStake',
1644
1665
  onJob: async (job) => {
1645
1666
  const { subscriptionId, stakingAddress, paymentCurrencyId } = job;
1646
- const subscription = await Subscription.findByPk(subscriptionId);
1667
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1647
1668
  if (!subscription) {
1648
1669
  return;
1649
1670
  }
1671
+ assertJobObjectTenant(subscription);
1650
1672
  await ensureReturnStake(subscription, paymentCurrencyId, stakingAddress);
1651
1673
  },
1652
1674
  options: {
@@ -1662,10 +1684,11 @@ export const subscriptionCancelRefund = createQueue({
1662
1684
  name: 'subscription-cancel-refund',
1663
1685
  onJob: async (job) => {
1664
1686
  const { subscriptionId } = job;
1665
- const subscription = await Subscription.findByPk(subscriptionId);
1687
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1666
1688
  if (!subscription) {
1667
1689
  return;
1668
1690
  }
1691
+ assertJobObjectTenant(subscription);
1669
1692
  await ensureRefundOnCancel(subscription);
1670
1693
  },
1671
1694
  options: {
@@ -1681,10 +1704,11 @@ export const returnOverdraftProtectionQueue = createQueue({
1681
1704
  name: 'returnOverdraftProtection',
1682
1705
  onJob: async (job) => {
1683
1706
  const { subscriptionId, paymentCurrencyId } = job;
1684
- const subscription = await Subscription.findByPk(subscriptionId);
1707
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1685
1708
  if (!subscription) {
1686
1709
  return;
1687
1710
  }
1711
+ assertJobObjectTenant(subscription);
1688
1712
  await ensureReturnOverdraftProtectionStake(subscription, paymentCurrencyId);
1689
1713
  },
1690
1714
  options: {
@@ -1700,10 +1724,11 @@ export const slashOverdraftProtectionQueue = createQueue({
1700
1724
  name: 'slashOverdraftProtection',
1701
1725
  onJob: async (job) => {
1702
1726
  const { subscriptionId } = job;
1703
- const subscription = await Subscription.findByPk(subscriptionId);
1727
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1704
1728
  if (!subscription) {
1705
1729
  return;
1706
1730
  }
1731
+ assertJobObjectTenant(subscription);
1707
1732
  await ensureSlashOverdraftProtectionStake(subscription);
1708
1733
  },
1709
1734
  options: {
@@ -1791,7 +1816,7 @@ events.on('customer.subscription.recovered', async (subscription: Subscription)
1791
1816
  logger.info('subscription cancel job replaced after recover', { subscription: subscription.id });
1792
1817
  await subscriptionQueue.delete(`cancel-${subscription.id}`);
1793
1818
  await subscriptionQueue.delete(subscription.id);
1794
- const doc = await Subscription.findByPk(subscription.id);
1819
+ const doc = await systemFindByPk(Subscription, subscription.id);
1795
1820
  await handleSubscriptionAfterRecover(doc!);
1796
1821
  });
1797
1822
 
@@ -1837,10 +1862,11 @@ events.on('customer.subscription.upgraded', async (subscription: Subscription) =
1837
1862
  });
1838
1863
 
1839
1864
  events.on('customer.stake.revoked', async ({ subscriptionId, tx }: { subscriptionId: string; tx: any }) => {
1840
- const subscription = await Subscription.findByPk(subscriptionId);
1865
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1841
1866
  if (!subscription) {
1842
1867
  return;
1843
1868
  }
1869
+ assertJobObjectTenant(subscription);
1844
1870
 
1845
1871
  const { address } = tx.tx.itxJson;
1846
1872
  if (address === subscription.overdraft_protection?.payment_details?.arcblock?.staking?.address) {
@@ -1893,12 +1919,13 @@ events.on('customer.stake.revoked', async ({ subscriptionId, tx }: { subscriptio
1893
1919
  events.on('setup_intent.succeeded', async (setupIntent: SetupIntent) => {
1894
1920
  logger.info('setup intent succeeded', { setupIntent: setupIntent.id });
1895
1921
  if (setupIntent.metadata?.from_currency && setupIntent?.metadata?.subscription_id) {
1896
- const subscription = await Subscription.findByPk(setupIntent.metadata.subscription_id);
1922
+ const subscription = await systemFindByPk(Subscription, setupIntent.metadata.subscription_id);
1897
1923
  if (!subscription) {
1898
1924
  logger.info('skip return stake because no subscription found', { setupIntent: setupIntent.id });
1899
1925
  return;
1900
1926
  }
1901
- const stakingInvoice = await Invoice.findOne({
1927
+ assertJobObjectTenant(subscription);
1928
+ const stakingInvoice = await systemFindOne(Invoice, {
1902
1929
  where: {
1903
1930
  subscription_id: subscription.id,
1904
1931
  billing_reason: 'stake',
@@ -1984,11 +2011,12 @@ type SlippagePreCheckJob = {
1984
2011
  async function handleSlippagePreCheck(job: SlippagePreCheckJob): Promise<void> {
1985
2012
  const { subscriptionId, renewalTime } = job;
1986
2013
 
1987
- const subscription = await Subscription.findByPk(subscriptionId);
2014
+ const subscription = await systemFindByPk(Subscription, subscriptionId);
1988
2015
  if (!subscription) {
1989
2016
  logger.warn('Slippage pre-check: Subscription not found', { subscriptionId });
1990
2017
  return;
1991
2018
  }
2019
+ assertJobObjectTenant(subscription);
1992
2020
 
1993
2021
  // Skip if subscription is not in active status
1994
2022
  if (!['active', 'trialing'].includes(subscription.status)) {
@@ -2007,17 +2035,19 @@ async function handleSlippagePreCheck(job: SlippagePreCheckJob): Promise<void> {
2007
2035
  }
2008
2036
 
2009
2037
  // Get payment currency and payment method
2010
- const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
2038
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
2011
2039
  if (!paymentCurrency) {
2012
2040
  logger.info('Slippage pre-check: Payment currency not found', { subscriptionId });
2013
2041
  return;
2014
2042
  }
2043
+ assertJobObjectTenant(paymentCurrency);
2015
2044
 
2016
- const paymentMethod = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
2045
+ const paymentMethod = await systemFindByPk(PaymentMethod, paymentCurrency.payment_method_id);
2017
2046
  if (!paymentMethod) {
2018
2047
  logger.info('Slippage pre-check: Payment method not found', { subscriptionId });
2019
2048
  return;
2020
2049
  }
2050
+ assertJobObjectTenant(paymentMethod);
2021
2051
 
2022
2052
  // Get current exchange rate
2023
2053
  try {
@@ -1,8 +1,9 @@
1
1
  import { BN } from '@ocap/util';
2
2
  import logger from '../libs/logger';
3
- import createQueue from '../libs/queue';
3
+ import createQueue, { assertJobObjectTenant } from '../libs/queue';
4
4
  import { getAccountState, transferTokenFromCustomer, getCustomerTokenBalance } from '../integrations/arcblock/token';
5
5
  import { CreditTransaction, CreditGrant, Customer, MeterEvent, PaymentCurrency, Subscription } from '../store/models';
6
+ import { systemFindAll, systemFindByPk } from '../store/scoped';
6
7
 
7
8
  type TokenTransferJob = {
8
9
  creditTransactionId: string;
@@ -30,11 +31,12 @@ type ValidationResult =
30
31
  * Validate transfer job and fetch required data
31
32
  */
32
33
  async function validateAndFetchData(job: TokenTransferJob): Promise<ValidationResult> {
33
- const creditTransaction = await CreditTransaction.findByPk(job.creditTransactionId);
34
+ const creditTransaction = await systemFindByPk(CreditTransaction, job.creditTransactionId);
34
35
  if (!creditTransaction) {
35
36
  logger.warn('CreditTransaction not found', { creditTransactionId: job.creditTransactionId });
36
37
  return { valid: false };
37
38
  }
39
+ assertJobObjectTenant(creditTransaction);
38
40
 
39
41
  // Check if already transferred
40
42
  if (creditTransaction.transfer_status === 'completed') {
@@ -42,11 +44,12 @@ async function validateAndFetchData(job: TokenTransferJob): Promise<ValidationRe
42
44
  return { valid: false };
43
45
  }
44
46
 
45
- const creditGrant = await CreditGrant.findByPk(job.creditGrantId);
47
+ const creditGrant = await systemFindByPk(CreditGrant, job.creditGrantId);
46
48
  if (!creditGrant) {
47
49
  logger.warn('CreditGrant not found', { creditGrantId: job.creditGrantId });
48
50
  return { valid: false };
49
51
  }
52
+ assertJobObjectTenant(creditGrant);
50
53
 
51
54
  const customer = await Customer.findByPkOrDid(job.customerDid);
52
55
  if (!customer) {
@@ -54,21 +57,23 @@ async function validateAndFetchData(job: TokenTransferJob): Promise<ValidationRe
54
57
  return { valid: false };
55
58
  }
56
59
 
57
- const paymentCurrency = await PaymentCurrency.findByPk(job.paymentCurrencyId);
60
+ const paymentCurrency = await systemFindByPk(PaymentCurrency, job.paymentCurrencyId);
58
61
  if (!paymentCurrency) {
59
62
  logger.warn('PaymentCurrency not found', { paymentCurrencyId: job.paymentCurrencyId });
60
63
  return { valid: false };
61
64
  }
65
+ assertJobObjectTenant(paymentCurrency);
62
66
 
63
- const meterEvent = await MeterEvent.findByPk(job.meterEventId);
67
+ const meterEvent = await systemFindByPk(MeterEvent, job.meterEventId);
64
68
  if (!meterEvent) {
65
69
  logger.warn('MeterEvent not found', { meterEventId: job.meterEventId });
66
70
  return { valid: false };
67
71
  }
72
+ assertJobObjectTenant(meterEvent);
68
73
 
69
74
  let subscription: Subscription | undefined;
70
75
  if (job.subscriptionId) {
71
- subscription = (await Subscription.findByPk(job.subscriptionId)) || undefined;
76
+ subscription = (await systemFindByPk(Subscription, job.subscriptionId)) || undefined;
72
77
  }
73
78
 
74
79
  return {
@@ -239,7 +244,7 @@ tokenTransferQueue.on('finished', ({ id, job }) => {
239
244
  tokenTransferQueue.on('failed', async ({ id, job, error }) => {
240
245
  logger.error('Token transfer job failed after all retries', { id, job, error: error.message });
241
246
 
242
- const creditTransaction = await CreditTransaction.findByPk(job.creditTransactionId);
247
+ const creditTransaction = await systemFindByPk(CreditTransaction, job.creditTransactionId);
243
248
 
244
249
  if (creditTransaction && creditTransaction.transfer_status !== 'completed') {
245
250
  await creditTransaction.update({
@@ -295,7 +300,7 @@ export async function startTokenTransferQueue(): Promise<void> {
295
300
  logger.info('Token transfer queue started');
296
301
 
297
302
  // Process any pending transfers on startup
298
- const pendingTransactions = await CreditTransaction.findAll({
303
+ const pendingTransactions = await systemFindAll(CreditTransaction, {
299
304
  where: {
300
305
  transfer_status: 'pending',
301
306
  },
@@ -309,8 +314,8 @@ export async function startTokenTransferQueue(): Promise<void> {
309
314
  await Promise.all(
310
315
  pendingTransactions.map(async (transaction) => {
311
316
  try {
312
- const customer = (await Customer.findByPk(transaction.customer_id))!;
313
- const creditGrant = (await CreditGrant.findByPk(transaction.credit_grant_id))!;
317
+ const customer = (await systemFindByPk(Customer, transaction.customer_id))!;
318
+ const creditGrant = (await systemFindByPk(CreditGrant, transaction.credit_grant_id))!;
314
319
 
315
320
  await addTokenTransferJob({
316
321
  creditTransactionId: transaction.id,