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
@@ -1,7 +1,8 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
3
-
2
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
4
3
  import { BN } from '@ocap/util';
4
+ import { TenantModel } from '../tenant-model';
5
+ import { getInstanceDid } from '../../libs/context';
5
6
 
6
7
  import { createIdGenerator } from '../../libs/util';
7
8
  import logger from '../../libs/logger';
@@ -9,9 +10,10 @@ import logger from '../../libs/logger';
9
10
  const nextTaxRateId = createIdGenerator('txr', 16);
10
11
 
11
12
  // eslint-disable-next-line prettier/prettier
12
- export class TaxRate extends Model<InferAttributes<TaxRate>, InferCreationAttributes<TaxRate>> {
13
+ export class TaxRate extends TenantModel<InferAttributes<TaxRate>, InferCreationAttributes<TaxRate>> {
13
14
  declare id: CreationOptional<string>;
14
15
  declare livemode: boolean;
16
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
15
17
  declare active: boolean;
16
18
 
17
19
  declare country: string; // ISO 3166-1 alpha-2 country code
@@ -89,24 +91,30 @@ export class TaxRate extends Model<InferAttributes<TaxRate>, InferCreationAttrib
89
91
  };
90
92
 
91
93
  public static initialize(sequelize: any) {
92
- this.init(TaxRate.GENESIS_ATTRIBUTES, {
93
- sequelize,
94
- modelName: 'TaxRate',
95
- tableName: 'tax_rates',
96
- createdAt: 'created_at',
97
- updatedAt: 'updated_at',
98
- indexes: [
99
- {
100
- fields: ['country'],
101
- },
102
- {
103
- fields: ['country', 'state'],
104
- },
105
- {
106
- fields: ['country', 'state', 'postal_code'],
107
- },
108
- ],
109
- });
94
+ this.init(
95
+ {
96
+ ...TaxRate.GENESIS_ATTRIBUTES,
97
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
98
+ },
99
+ {
100
+ sequelize,
101
+ modelName: 'TaxRate',
102
+ tableName: 'tax_rates',
103
+ createdAt: 'created_at',
104
+ updatedAt: 'updated_at',
105
+ indexes: [
106
+ {
107
+ fields: ['country'],
108
+ },
109
+ {
110
+ fields: ['country', 'state'],
111
+ },
112
+ {
113
+ fields: ['country', 'state', 'postal_code'],
114
+ },
115
+ ],
116
+ }
117
+ );
110
118
  }
111
119
 
112
120
  public static associate() {}
@@ -1,15 +1,18 @@
1
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model, Op } from 'sequelize';
1
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Op } from 'sequelize';
2
2
  import type { LiteralUnion } from 'type-fest';
3
+ import { TenantModel } from '../tenant-model';
4
+ import { getInstanceDid } from '../../libs/context';
3
5
 
4
6
  import { createIdGenerator } from '../../libs/util';
5
7
 
6
8
  const nextId = createIdGenerator('mbur', 24);
7
9
 
8
10
  // eslint-disable-next-line prettier/prettier
9
- export class UsageRecord extends Model<InferAttributes<UsageRecord>, InferCreationAttributes<UsageRecord>> {
11
+ export class UsageRecord extends TenantModel<InferAttributes<UsageRecord>, InferCreationAttributes<UsageRecord>> {
10
12
  declare id: CreationOptional<string>;
11
13
 
12
14
  declare livemode: boolean;
15
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
13
16
  declare billed: boolean;
14
17
 
15
18
  // The timestamp when this usage occurred.
@@ -72,6 +75,12 @@ export class UsageRecord extends Model<InferAttributes<UsageRecord>, InferCreati
72
75
  this.init(
73
76
  {
74
77
  ...UsageRecord.GENESIS_ATTRIBUTES,
78
+ instance_did: {
79
+ type: DataTypes.STRING(64),
80
+ allowNull: true,
81
+ // bare creates must still land in the active tenant (single mode = app DID)
82
+ defaultValue: () => getInstanceDid(),
83
+ },
75
84
  billed: {
76
85
  type: DataTypes.BOOLEAN,
77
86
  defaultValue: false,
@@ -1,14 +1,17 @@
1
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
1
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
2
2
  import type { LiteralUnion } from 'type-fest';
3
+ import { TenantModel } from '../tenant-model';
4
+ import { getInstanceDid } from '../../libs/context';
3
5
 
4
6
  import { createIdGenerator } from '../../libs/util';
5
7
 
6
8
  const nextId = createIdGenerator('wa', 24);
7
9
 
8
10
  // eslint-disable-next-line prettier/prettier
9
- export class WebhookAttempt extends Model<InferAttributes<WebhookAttempt>, InferCreationAttributes<WebhookAttempt>> {
11
+ export class WebhookAttempt extends TenantModel<InferAttributes<WebhookAttempt>, InferCreationAttributes<WebhookAttempt>> {
10
12
  declare id: CreationOptional<string>;
11
13
  declare livemode: boolean;
14
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
12
15
 
13
16
  declare event_id: string;
14
17
  declare webhook_endpoint_id: string;
@@ -70,13 +73,19 @@ export class WebhookAttempt extends Model<InferAttributes<WebhookAttempt>, Infer
70
73
  };
71
74
 
72
75
  public static initialize(sequelize: any) {
73
- this.init(WebhookAttempt.GENESIS_ATTRIBUTES, {
74
- sequelize,
75
- modelName: 'WebhookAttempt',
76
- tableName: 'webhook_attempts',
77
- createdAt: 'created_at',
78
- updatedAt: 'updated_at',
79
- });
76
+ this.init(
77
+ {
78
+ ...WebhookAttempt.GENESIS_ATTRIBUTES,
79
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
80
+ },
81
+ {
82
+ sequelize,
83
+ modelName: 'WebhookAttempt',
84
+ tableName: 'webhook_attempts',
85
+ createdAt: 'created_at',
86
+ updatedAt: 'updated_at',
87
+ }
88
+ );
80
89
  }
81
90
 
82
91
  public static associate(models: any) {
@@ -1,5 +1,7 @@
1
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
1
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
2
2
  import type { LiteralUnion } from 'type-fest';
3
+ import { TenantModel } from '../tenant-model';
4
+ import { getInstanceDid } from '../../libs/context';
3
5
 
4
6
  import { createIdGenerator } from '../../libs/util';
5
7
  import type { EventType } from './types';
@@ -7,9 +9,10 @@ import type { EventType } from './types';
7
9
  const nextId = createIdGenerator('we', 24);
8
10
 
9
11
  // eslint-disable-next-line prettier/prettier
10
- export class WebhookEndpoint extends Model<InferAttributes<WebhookEndpoint>, InferCreationAttributes<WebhookEndpoint>> {
12
+ export class WebhookEndpoint extends TenantModel<InferAttributes<WebhookEndpoint>, InferCreationAttributes<WebhookEndpoint>> {
11
13
  declare id: CreationOptional<string>;
12
14
  declare livemode: boolean;
15
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
13
16
  declare api_version: string;
14
17
 
15
18
  declare url: string;
@@ -75,13 +78,19 @@ export class WebhookEndpoint extends Model<InferAttributes<WebhookEndpoint>, Inf
75
78
  };
76
79
 
77
80
  public static initialize(sequelize: any) {
78
- this.init(WebhookEndpoint.GENESIS_ATTRIBUTES, {
79
- sequelize,
80
- modelName: 'WebhookEndpoint',
81
- tableName: 'webhook_endpoints',
82
- createdAt: 'created_at',
83
- updatedAt: 'updated_at',
84
- });
81
+ this.init(
82
+ {
83
+ ...WebhookEndpoint.GENESIS_ATTRIBUTES,
84
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
85
+ },
86
+ {
87
+ sequelize,
88
+ modelName: 'WebhookEndpoint',
89
+ tableName: 'webhook_endpoints',
90
+ createdAt: 'created_at',
91
+ updatedAt: 'updated_at',
92
+ }
93
+ );
85
94
  }
86
95
 
87
96
  public static associate(models: any) {
@@ -0,0 +1,55 @@
1
+ // Tenant scope primitives — the single source for tenant-scoping logic shared
2
+ // by:
3
+ // - scoped.ts (the opt-in scoped*/system* helper functions)
4
+ // - tenant-model.ts (the TenantModel base class)
5
+ //
6
+ // Before this module each of those carried its own inline copy of scopeWhere /
7
+ // stampTenant / the tenant-table check (W1′ task 3 de-dup). The semantics are
8
+ // identical and load-bearing, so they live in exactly one place now.
9
+ //
10
+ // IMPORTANT: this module must stay free of Node-only / workerd-only imports so
11
+ // the worker shim engine can import it too (Phase 3 cross-engine assertion).
12
+ // Its only ambient dependency is the request-context ALS in libs/context,
13
+ // which is async_hooks on Node and nodejs_compat on the worker — the same ALS
14
+ // the whole isolation design rides on.
15
+ import { getInstanceDid } from '../libs/context';
16
+ import { TENANT_MISMATCH, TenantError } from '../libs/tenant';
17
+ import { TENANT_TABLES } from './tenant-tables';
18
+
19
+ const TENANT_TABLE_SET: ReadonlySet<string> = new Set(TENANT_TABLES);
20
+
21
+ /** Is this table one of the 38 tenant-scoped tables? */
22
+ export function isTenantTable(tableName: string): boolean {
23
+ return TENANT_TABLE_SET.has(tableName);
24
+ }
25
+
26
+ /**
27
+ * Merge the active tenant into a where clause.
28
+ *
29
+ * - fail-closed: an explicit caller-provided `where.instance_did` that disagrees
30
+ * with the active tenant throws TENANT_MISMATCH — never silently overridden.
31
+ * - idempotent: an equal `instance_did` is a no-op, so the double injection from
32
+ * internal delegation (findByPk -> findOne -> findAll) is absorbed cleanly.
33
+ */
34
+ export function scopeWhere(where: Record<string, any> | undefined): Record<string, any> {
35
+ const instanceDid = getInstanceDid();
36
+ if (where && 'instance_did' in where && where.instance_did !== instanceDid) {
37
+ throw new TenantError(
38
+ TENANT_MISMATCH,
39
+ `explicit where.instance_did (${JSON.stringify(where.instance_did)}) conflicts with the active tenant`
40
+ );
41
+ }
42
+ return { ...where, instance_did: instanceDid };
43
+ }
44
+
45
+ /**
46
+ * Stamp the active tenant onto create values. An explicit mismatched tenant is
47
+ * refused (writes never cross tenants); an equal one is a no-op.
48
+ */
49
+ export function stampTenant(values: Record<string, any>): Record<string, any> {
50
+ const instanceDid = getInstanceDid();
51
+ if (values && 'instance_did' in values && values.instance_did !== instanceDid) {
52
+ throw new TenantError(TENANT_MISMATCH, 'explicit instance_did conflicts with the active tenant');
53
+ }
54
+ return { ...values, instance_did: instanceDid };
55
+ }
@@ -0,0 +1,247 @@
1
+ /* eslint-disable max-classes-per-file */
2
+ import type {
3
+ Attributes,
4
+ CountOptions,
5
+ CreateOptions,
6
+ DestroyOptions,
7
+ FindOptions,
8
+ Model,
9
+ ModelStatic,
10
+ Sequelize,
11
+ UpdateOptions,
12
+ } from 'sequelize';
13
+
14
+ import { context } from '../libs/context';
15
+ import { INVALID_TENANT_TABLE, TENANT_MISMATCH, TenantError } from '../libs/tenant';
16
+ import { isTenantTable, scopeWhere } from './scoped-core';
17
+
18
+ // Phase 3 (W1-2): tenant-scoped query wrappers.
19
+ //
20
+ // Explicit wrapper functions (no global sequelize hooks) so every scoped call
21
+ // is visible and auditable at the call site. The CI scanner
22
+ // (scripts/scan-tenant-queries.js) rejects bare findByPk/findOne/findAll/
23
+ // findAndCountAll/sequelize.query on tenant models outside this module;
24
+ // the 38-table list is shared via ./tenant-tables (single source).
25
+
26
+ export { TENANT_TABLES } from './tenant-tables';
27
+
28
+ // scopeWhere / isTenantTable now live in ./scoped-core (shared with the
29
+ // TenantModel base class — one copy of the tenant-scoping logic).
30
+
31
+ function assertTenantModel(model: ModelStatic<any>) {
32
+ if (!isTenantTable(model.tableName)) {
33
+ throw new TenantError(
34
+ INVALID_TENANT_TABLE,
35
+ `${model.tableName} is not a tenant table — use the model API directly (exempt: jobs/locks/archive/exchange_rate_providers)`
36
+ );
37
+ }
38
+ }
39
+
40
+ // validation errors must surface as rejections (callers use .catch / await),
41
+ // even though the checks themselves are synchronous
42
+ function asAsync<T>(fn: () => Promise<T> | T): Promise<T> {
43
+ try {
44
+ return Promise.resolve(fn());
45
+ } catch (err) {
46
+ return Promise.reject(err);
47
+ }
48
+ }
49
+
50
+ export function scopedFindAll<M extends Model>(
51
+ model: ModelStatic<M>,
52
+ options: FindOptions<Attributes<M>> = {}
53
+ ): Promise<M[]> {
54
+ return asAsync(() => {
55
+ assertTenantModel(model);
56
+ return model.findAll({ ...options, where: scopeWhere(options.where as any) as any });
57
+ });
58
+ }
59
+
60
+ export function scopedFindOne<M extends Model>(
61
+ model: ModelStatic<M>,
62
+ options: FindOptions<Attributes<M>> = {}
63
+ ): Promise<M | null> {
64
+ return asAsync(() => {
65
+ assertTenantModel(model);
66
+ return model.findOne({ ...options, where: scopeWhere(options.where as any) as any });
67
+ });
68
+ }
69
+
70
+ export function scopedFindAndCountAll<M extends Model>(
71
+ model: ModelStatic<M>,
72
+ options: FindOptions<Attributes<M>> = {}
73
+ ): Promise<{ rows: M[]; count: number }> {
74
+ return asAsync(() => {
75
+ assertTenantModel(model);
76
+ return (model as any).findAndCountAll({ ...options, where: scopeWhere(options.where as any) });
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Primary keys are globally unique, so a bare findByPk could load another
82
+ * tenant's row. The row is loaded first, then its tenant is enforced:
83
+ * mismatch -> TENANT_MISMATCH (no data returned, nothing written).
84
+ */
85
+ export async function scopedFindByPk<M extends Model>(
86
+ model: ModelStatic<M>,
87
+ pk: string | number | undefined | null,
88
+ options: Omit<FindOptions<Attributes<M>>, 'where'> = {}
89
+ ): Promise<M | null> {
90
+ assertTenantModel(model);
91
+ if (pk === undefined || pk === null) return null;
92
+ const instanceDid = context.getInstanceDid();
93
+ const row: any = await model.findByPk(pk as any, options as any);
94
+ if (!row) return null;
95
+ if (row.instance_did !== instanceDid) {
96
+ throw new TenantError(TENANT_MISMATCH, `${model.tableName}#${String(pk)} belongs to another tenant`);
97
+ }
98
+ return row;
99
+ }
100
+
101
+ export function scopedCount<M extends Model>(
102
+ model: ModelStatic<M>,
103
+ options: CountOptions<Attributes<M>> = {}
104
+ ): Promise<number> {
105
+ return asAsync(() => {
106
+ assertTenantModel(model);
107
+ return model.count({ ...options, where: scopeWhere(options.where as any) as any });
108
+ });
109
+ }
110
+
111
+ export function scopedSum<M extends Model>(
112
+ model: ModelStatic<M>,
113
+ field: keyof Attributes<M>,
114
+ options: { where?: Record<string, any> } = {}
115
+ ): Promise<number> {
116
+ return asAsync(() => {
117
+ assertTenantModel(model);
118
+ return (model as any).sum(field, { ...options, where: scopeWhere(options.where) });
119
+ });
120
+ }
121
+
122
+ export function scopedAggregate<M extends Model>(
123
+ model: ModelStatic<M>,
124
+ field: keyof Attributes<M> | '*',
125
+ aggregateFunction: string,
126
+ options: { where?: Record<string, any> } = {}
127
+ ): Promise<unknown> {
128
+ return asAsync(() => {
129
+ assertTenantModel(model);
130
+ return (model as any).aggregate(field, aggregateFunction, { ...options, where: scopeWhere(options.where) });
131
+ });
132
+ }
133
+
134
+ /** Create with the active tenant; an explicit mismatched tenant is refused. */
135
+ export function scopedCreate<M extends Model>(
136
+ model: ModelStatic<M>,
137
+ values: Record<string, any>,
138
+ options?: CreateOptions<Attributes<M>>
139
+ ): Promise<M> {
140
+ return asAsync(() => {
141
+ assertTenantModel(model);
142
+ const instanceDid = context.getInstanceDid();
143
+ if ('instance_did' in values && values.instance_did !== instanceDid) {
144
+ throw new TenantError(TENANT_MISMATCH, 'explicit instance_did conflicts with the active tenant');
145
+ }
146
+ return model.create({ ...values, instance_did: instanceDid } as any, options) as Promise<M>;
147
+ });
148
+ }
149
+
150
+ export function scopedUpdate<M extends Model>(
151
+ model: ModelStatic<M>,
152
+ values: Record<string, any>,
153
+ options: UpdateOptions<Attributes<M>>
154
+ ): Promise<[affectedCount: number]> {
155
+ return asAsync(() => {
156
+ assertTenantModel(model);
157
+ if ('instance_did' in values) {
158
+ throw new TenantError(TENANT_MISMATCH, 'instance_did is immutable — rows never change tenant');
159
+ }
160
+ return model.update(values as any, { ...options, where: scopeWhere(options.where as any) as any });
161
+ });
162
+ }
163
+
164
+ export function scopedDestroy<M extends Model>(
165
+ model: ModelStatic<M>,
166
+ options: DestroyOptions<Attributes<M>> = {}
167
+ ): Promise<number> {
168
+ return asAsync(() => {
169
+ assertTenantModel(model);
170
+ return model.destroy({ ...options, where: scopeWhere(options.where as any) as any });
171
+ });
172
+ }
173
+
174
+ /**
175
+ * Raw SQL with mandatory tenant binding: the statement must reference
176
+ * $instance_did (or :instance_did) and the bind value is supplied here from
177
+ * the context — callers cannot forget or override it.
178
+ */
179
+ export function scopedQuery(sequelize: Sequelize, sql: string, options: { bind?: Record<string, any> } = {}) {
180
+ if (!/[$:]instance_did\b/.test(sql)) {
181
+ throw new TenantError(
182
+ TENANT_MISMATCH,
183
+ 'raw SQL on tenant tables must bind $instance_did — add it to the WHERE clause or use scopedQuery on a scoped view'
184
+ );
185
+ }
186
+ const instanceDid = context.getInstanceDid();
187
+ const bind = { ...options.bind, instance_did: instanceDid };
188
+ return sequelize.query(sql, { ...options, bind });
189
+ }
190
+
191
+ // ---------------------------------------------------------------------------
192
+ // system* family — EXPLICIT cross-tenant reads for system paths.
193
+ //
194
+ // Queue handlers load rows by globally-unique primary key from a
195
+ // tenant-stamped payload and then enforce row tenant via
196
+ // assertJobObjectTenant (libs/queue); dispatch/recovery sweeps and
197
+ // fanout-by-row-tenant (queues/event.ts) legitimately read across tenants.
198
+ // Naming these calls system* keeps every query auditable: anything not
199
+ // scoped* or system* is a scanner violation.
200
+ // ---------------------------------------------------------------------------
201
+
202
+ // Each system* call runs inside context.runAsSystem so the TenantModel base
203
+ // class bypasses scoping for the read — otherwise the model's overridden
204
+ // findByPk/findAll/... would re-scope to the active tenant and a legitimate
205
+ // cross-tenant read (queue dispatch, IAP reverse-lookup, fan-out) would resolve
206
+ // to null. The caller still enforces the row's tenant afterwards.
207
+
208
+ export function systemFindByPk<M extends Model>(
209
+ model: ModelStatic<M>,
210
+ pk: string | number | undefined | null,
211
+ options?: Omit<FindOptions<Attributes<M>>, 'where'>
212
+ ): Promise<M | null> {
213
+ if (pk === undefined || pk === null) return Promise.resolve(null);
214
+ // forward options only when provided — keeps call shapes identical for
215
+ // existing spies/assertions on model.findByPk
216
+ return context.runAsSystem(() =>
217
+ options ? model.findByPk(pk as any, options as any) : model.findByPk(pk as any)
218
+ ) as Promise<M | null>;
219
+ }
220
+
221
+ export function systemFindAll<M extends Model>(
222
+ model: ModelStatic<M>,
223
+ options: FindOptions<Attributes<M>> = {}
224
+ ): Promise<M[]> {
225
+ return context.runAsSystem(() => model.findAll(options));
226
+ }
227
+
228
+ export function systemFindOne<M extends Model>(
229
+ model: ModelStatic<M>,
230
+ options: FindOptions<Attributes<M>> = {}
231
+ ): Promise<M | null> {
232
+ return context.runAsSystem(() => model.findOne(options));
233
+ }
234
+
235
+ export function systemFindAndCountAll<M extends Model>(
236
+ model: ModelStatic<M>,
237
+ options: FindOptions<Attributes<M>> = {}
238
+ ): Promise<{ rows: M[]; count: number }> {
239
+ return context.runAsSystem(() => (model as any).findAndCountAll(options));
240
+ }
241
+
242
+ export function systemCount<M extends Model>(
243
+ model: ModelStatic<M>,
244
+ options: CountOptions<Attributes<M>> = {}
245
+ ): Promise<number> {
246
+ return context.runAsSystem(() => model.count(options));
247
+ }
@@ -6,31 +6,75 @@ import { join } from 'path';
6
6
 
7
7
  import CLS from 'cls-hooked';
8
8
  import { Sequelize } from 'sequelize';
9
-
10
- import env, { sequelizeOptionsPoolIdle, sequelizeOptionsPoolMax, sequelizeOptionsPoolMin } from '../libs/env';
9
+ import env, {
10
+ sqlLog,
11
+ sqlBenchmark,
12
+ sequelizeOptionsPoolIdle,
13
+ sequelizeOptionsPoolMax,
14
+ sequelizeOptionsPoolMin,
15
+ } from '../libs/env';
11
16
 
12
17
  const namespace = CLS.createNamespace('payment-kit');
13
18
 
14
19
  Sequelize.useCLS(namespace);
15
20
 
21
+ // Phase 13b: the blocklet-server's default sqlite instance is built from
22
+ // `env.dataDir`, which is absent in a bare host (arc embedding before its blocklet
23
+ // runtime is wired). In that mode the host injects its OWN sequelize via the db
24
+ // slot and this default is never used — so importing the models must not eagerly
25
+ // construct it (it would crash on join(undefined, …)). Construct EAGERLY when a
26
+ // data dir is present (blocklet server: BLOCKLET_DATA_DIR; CF worker: shim '/tmp')
27
+ // so their behavior and hot path are byte-for-byte unchanged — no proxy on the
28
+ // query path, CLS/transaction identity preserved. Otherwise defer behind a proxy
29
+ // that builds on first access (only ever hit by code that uses this default).
30
+ function buildSequelize(): Sequelize {
31
+ const seq = new Sequelize({
32
+ dialect: 'sqlite',
33
+ logging: sqlLog(),
34
+ benchmark: sqlLog() && sqlBenchmark(),
35
+ storage: join(env.dataDir, 'payment-kit.db'),
36
+ pool: {
37
+ min: sequelizeOptionsPoolMin(),
38
+ max: sequelizeOptionsPoolMax(),
39
+ idle: sequelizeOptionsPoolIdle(),
40
+ },
41
+ });
42
+
43
+ // SQLite PRAGMAs — run once at startup on the single reused connection.
44
+ // Note: SQLite in Sequelize reuses a cached connection (connection-manager.js:43-44),
45
+ // so these fire-and-forget calls reliably apply to all subsequent queries.
46
+ // Failures are non-fatal (pragmas are perf tuning) and must not crash the
47
+ // process via unhandledRejection, e.g. when jest teardown removes the data dir.
48
+ const pragma = (sql: string) => seq.query(sql).catch(() => {});
49
+ pragma('PRAGMA journal_mode = WAL');
50
+ pragma('PRAGMA synchronous = NORMAL');
51
+ pragma('PRAGMA journal_size_limit = 67108864');
52
+ pragma('PRAGMA busy_timeout = 5000');
53
+ pragma('PRAGMA cache_size = -16000'); // 16MB page cache (default ~2MB)
54
+
55
+ return seq;
56
+ }
57
+
58
+ let instance: Sequelize | undefined;
59
+ const getSequelize = (): Sequelize => {
60
+ instance ??= buildSequelize();
61
+ return instance;
62
+ };
63
+
16
64
  // eslint-disable-next-line import/prefer-default-export
17
- export const sequelize = new Sequelize({
18
- dialect: 'sqlite',
19
- logging: process.env.SQL_LOG === '1',
20
- benchmark: process.env.SQL_LOG === '1' && process.env.SQL_BENCHMARK === '1',
21
- storage: join(env.dataDir, 'payment-kit.db'),
22
- pool: {
23
- min: sequelizeOptionsPoolMin,
24
- max: sequelizeOptionsPoolMax,
25
- idle: sequelizeOptionsPoolIdle,
26
- },
27
- });
28
-
29
- // SQLite PRAGMAs — run once at startup on the single reused connection.
30
- // Note: SQLite in Sequelize reuses a cached connection (connection-manager.js:43-44),
31
- // so these fire-and-forget calls reliably apply to all subsequent queries.
32
- sequelize.query('PRAGMA journal_mode = WAL');
33
- sequelize.query('PRAGMA synchronous = NORMAL');
34
- sequelize.query('PRAGMA journal_size_limit = 67108864');
35
- sequelize.query('PRAGMA busy_timeout = 5000');
36
- sequelize.query('PRAGMA cache_size = -16000'); // 16MB page cache (default ~2MB)
65
+ export const sequelize: Sequelize = env.dataDir
66
+ ? getSequelize()
67
+ : new Proxy({} as Sequelize, {
68
+ get(_t, prop) {
69
+ const seq = getSequelize();
70
+ const value: any = (seq as any)[prop];
71
+ return typeof value === 'function' ? value.bind(seq) : value;
72
+ },
73
+ set(_t, prop, value) {
74
+ (getSequelize() as any)[prop] = value;
75
+ return true;
76
+ },
77
+ has(_t, prop) {
78
+ return prop in (getSequelize() as any);
79
+ },
80
+ });