payment-kit 1.29.1 → 1.29.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/api/dev.ts +41 -2
  2. package/api/hono.d.ts +42 -0
  3. package/api/node-sqlite.d.ts +12 -0
  4. package/api/src/bootstrap.ts +36 -0
  5. package/api/src/crons/base.ts +3 -3
  6. package/api/src/crons/currency.ts +1 -1
  7. package/api/src/crons/index.ts +27 -24
  8. package/api/src/crons/metering-subscription-detection.ts +1 -1
  9. package/api/src/crons/overdue-detection.ts +2 -2
  10. package/api/src/crons/retry-pending-events.ts +6 -0
  11. package/api/src/index.ts +22 -161
  12. package/api/src/integrations/app-store/client.ts +3 -4
  13. package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
  14. package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
  15. package/api/src/integrations/arcblock/token.ts +21 -7
  16. package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
  17. package/api/src/integrations/google-play/handlers/voided.ts +2 -2
  18. package/api/src/integrations/google-play/verify.ts +3 -2
  19. package/api/src/integrations/iap-reconcile.ts +3 -5
  20. package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
  21. package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
  22. package/api/src/libs/archive/query.ts +19 -0
  23. package/api/src/libs/audit.ts +61 -4
  24. package/api/src/libs/auth.ts +99 -38
  25. package/api/src/libs/context.ts +78 -1
  26. package/api/src/libs/currency.ts +2 -2
  27. package/api/src/libs/dayjs.ts +8 -2
  28. package/api/src/libs/drivers/auth-storage.ts +118 -0
  29. package/api/src/libs/drivers/cron.ts +264 -0
  30. package/api/src/libs/drivers/db.ts +170 -0
  31. package/api/src/libs/drivers/identity.ts +81 -0
  32. package/api/src/libs/drivers/index.ts +40 -0
  33. package/api/src/libs/drivers/locks.ts +226 -0
  34. package/api/src/libs/drivers/migrate-runner.ts +70 -0
  35. package/api/src/libs/drivers/queue.ts +104 -0
  36. package/api/src/libs/drivers/secrets.ts +194 -0
  37. package/api/src/libs/env.ts +170 -54
  38. package/api/src/libs/exchange-rate/service.ts +7 -6
  39. package/api/src/libs/http-fetch-adapter.ts +50 -0
  40. package/api/src/libs/invoice.ts +1 -1
  41. package/api/src/libs/lock.ts +51 -47
  42. package/api/src/libs/logger.ts +48 -8
  43. package/api/src/libs/notification/index.ts +1 -1
  44. package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
  45. package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
  46. package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
  47. package/api/src/libs/overdraft-protection.ts +1 -1
  48. package/api/src/libs/payout.ts +1 -1
  49. package/api/src/libs/queue/index.ts +259 -52
  50. package/api/src/libs/queue/runtime.ts +175 -0
  51. package/api/src/libs/resource.ts +3 -3
  52. package/api/src/libs/secrets.ts +38 -0
  53. package/api/src/libs/session.ts +3 -2
  54. package/api/src/libs/subscription.ts +5 -5
  55. package/api/src/libs/tenant.ts +92 -0
  56. package/api/src/libs/url.ts +3 -3
  57. package/api/src/libs/util.ts +21 -13
  58. package/api/src/middlewares/hono/cdn.ts +63 -0
  59. package/api/src/middlewares/hono/context.ts +73 -0
  60. package/api/src/middlewares/hono/csrf.ts +72 -0
  61. package/api/src/middlewares/hono/fallback.ts +194 -0
  62. package/api/src/middlewares/hono/pipeline.ts +73 -0
  63. package/api/src/middlewares/hono/resource-mount.ts +42 -0
  64. package/api/src/middlewares/hono/resource.ts +63 -0
  65. package/api/src/middlewares/hono/security.ts +214 -0
  66. package/api/src/middlewares/hono/session.ts +114 -0
  67. package/api/src/middlewares/hono/xss.ts +61 -0
  68. package/api/src/queues/auto-recharge.ts +12 -10
  69. package/api/src/queues/checkout-session.ts +17 -12
  70. package/api/src/queues/credit-consume.ts +40 -36
  71. package/api/src/queues/credit-grant.ts +25 -18
  72. package/api/src/queues/credit-reconciliation.ts +7 -5
  73. package/api/src/queues/discount-status.ts +9 -6
  74. package/api/src/queues/event.ts +12 -4
  75. package/api/src/queues/exchange-rate-health.ts +49 -30
  76. package/api/src/queues/invoice.ts +18 -15
  77. package/api/src/queues/notification.ts +14 -7
  78. package/api/src/queues/payment.ts +41 -28
  79. package/api/src/queues/payout.ts +9 -5
  80. package/api/src/queues/refund.ts +18 -12
  81. package/api/src/queues/subscription.ts +83 -53
  82. package/api/src/queues/token-transfer.ts +15 -10
  83. package/api/src/queues/usage-record.ts +8 -5
  84. package/api/src/queues/vendors/commission.ts +7 -5
  85. package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
  86. package/api/src/queues/vendors/fulfillment.ts +4 -2
  87. package/api/src/queues/vendors/return-processor.ts +5 -3
  88. package/api/src/queues/vendors/return-scanner.ts +5 -4
  89. package/api/src/queues/vendors/status-check.ts +10 -7
  90. package/api/src/queues/webhook.ts +60 -32
  91. package/api/src/routes/connect/shared.ts +1 -2
  92. package/api/src/routes/connect/subscribe.ts +3 -3
  93. package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
  94. package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
  95. package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
  96. package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
  97. package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
  98. package/api/src/routes/hono/credit-tokens.ts +43 -0
  99. package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
  100. package/api/src/routes/{customers.ts → hono/customers.ts} +193 -223
  101. package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
  102. package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
  103. package/api/src/routes/{events.ts → hono/events.ts} +107 -71
  104. package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
  105. package/api/src/routes/hono/exchange-rates.ts +77 -0
  106. package/api/src/routes/hono/index.ts +115 -0
  107. package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
  108. package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
  109. package/api/src/routes/hono/integrations/stripe.ts +74 -0
  110. package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
  111. package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
  112. package/api/src/routes/hono/meters.ts +288 -0
  113. package/api/src/routes/hono/passports.ts +73 -0
  114. package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
  115. package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
  116. package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
  117. package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
  118. package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
  119. package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
  120. package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
  121. package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
  122. package/api/src/routes/{products.ts → hono/products.ts} +172 -159
  123. package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
  124. package/api/src/routes/hono/redirect.ts +24 -0
  125. package/api/src/routes/{refunds.ts → hono/refunds.ts} +96 -80
  126. package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
  127. package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
  128. package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
  129. package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
  130. package/api/src/routes/hono/tool.ts +69 -0
  131. package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
  132. package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
  133. package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
  134. package/api/src/routes/hono/webhook-endpoints.ts +126 -0
  135. package/api/src/service.ts +667 -0
  136. package/api/src/store/migrations/20230911-seeding.ts +2 -1
  137. package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
  138. package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
  139. package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
  140. package/api/src/store/models/auto-recharge-config.ts +22 -10
  141. package/api/src/store/models/checkout-session.ts +15 -14
  142. package/api/src/store/models/coupon.ts +29 -20
  143. package/api/src/store/models/credit-grant.ts +38 -29
  144. package/api/src/store/models/credit-transaction.ts +32 -21
  145. package/api/src/store/models/customer.ts +19 -17
  146. package/api/src/store/models/discount.ts +11 -2
  147. package/api/src/store/models/entitlement-grant.ts +21 -9
  148. package/api/src/store/models/entitlement-product.ts +21 -9
  149. package/api/src/store/models/entitlement.ts +19 -10
  150. package/api/src/store/models/event.ts +18 -9
  151. package/api/src/store/models/exchange-rate-provider.ts +17 -4
  152. package/api/src/store/models/invoice-item.ts +18 -9
  153. package/api/src/store/models/invoice.ts +16 -8
  154. package/api/src/store/models/meter-event.ts +27 -9
  155. package/api/src/store/models/meter.ts +31 -22
  156. package/api/src/store/models/payment-currency.ts +25 -8
  157. package/api/src/store/models/payment-intent.ts +15 -6
  158. package/api/src/store/models/payment-link.ts +15 -6
  159. package/api/src/store/models/payment-method.ts +38 -22
  160. package/api/src/store/models/payment-stat.ts +18 -9
  161. package/api/src/store/models/payout.ts +15 -6
  162. package/api/src/store/models/price-quote.ts +17 -8
  163. package/api/src/store/models/price.ts +24 -12
  164. package/api/src/store/models/pricing-table.ts +29 -20
  165. package/api/src/store/models/product-vendor.ts +20 -10
  166. package/api/src/store/models/product.ts +15 -6
  167. package/api/src/store/models/promotion-code.ts +14 -6
  168. package/api/src/store/models/refund.ts +15 -6
  169. package/api/src/store/models/revenue-snapshot.ts +21 -9
  170. package/api/src/store/models/setting.ts +18 -9
  171. package/api/src/store/models/setup-intent.ts +36 -27
  172. package/api/src/store/models/subscription-item.ts +21 -9
  173. package/api/src/store/models/subscription-schedule.ts +21 -9
  174. package/api/src/store/models/subscription.ts +21 -10
  175. package/api/src/store/models/tax-rate.ts +29 -21
  176. package/api/src/store/models/usage-record.ts +11 -2
  177. package/api/src/store/models/webhook-attempt.ts +18 -9
  178. package/api/src/store/models/webhook-endpoint.ts +18 -9
  179. package/api/src/store/scoped-core.ts +55 -0
  180. package/api/src/store/scoped.ts +247 -0
  181. package/api/src/store/sequelize.ts +66 -22
  182. package/api/src/store/sql-migrations.ts +20 -0
  183. package/api/src/store/tenant-backfill.ts +260 -0
  184. package/api/src/store/tenant-model.ts +124 -0
  185. package/api/src/store/tenant-tables.ts +50 -0
  186. package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
  187. package/api/tests/fixtures/bare-query-violation.ts +13 -0
  188. package/api/tests/fixtures/core-env-violation.ts +10 -0
  189. package/api/tests/fixtures/host-read-violation.ts +19 -0
  190. package/api/tests/fixtures/tenants.ts +4 -0
  191. package/api/tests/integrations/iap-tenant.spec.ts +284 -0
  192. package/api/tests/libs/archive-query.spec.ts +26 -0
  193. package/api/tests/libs/audit-tenant.spec.ts +153 -0
  194. package/api/tests/libs/context.spec.ts +204 -0
  195. package/api/tests/libs/core-config.spec.ts +115 -0
  196. package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
  197. package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
  198. package/api/tests/libs/lock-tenant.spec.ts +66 -0
  199. package/api/tests/libs/scoped.spec.ts +222 -0
  200. package/api/tests/libs/secrets-facade.spec.ts +52 -0
  201. package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
  202. package/api/tests/libs/tenant-middleware.spec.ts +42 -0
  203. package/api/tests/libs/tenant-scanner.spec.ts +120 -0
  204. package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
  205. package/api/tests/middlewares/hono/context.spec.ts +113 -0
  206. package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
  207. package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
  208. package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
  209. package/api/tests/middlewares/hono/security.spec.ts +181 -0
  210. package/api/tests/middlewares/hono/session.spec.ts +42 -0
  211. package/api/tests/middlewares/hono/xss.spec.ts +81 -0
  212. package/api/tests/models/tenant-backfill.spec.ts +287 -0
  213. package/api/tests/models/tenant-columns-model.spec.ts +46 -0
  214. package/api/tests/models/tenant-columns.spec.ts +161 -0
  215. package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
  216. package/api/tests/queues/credit-consume.spec.ts +8 -1
  217. package/api/tests/queues/event-tenant.spec.ts +236 -0
  218. package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
  219. package/api/tests/queues/queue-parity.spec.ts +249 -0
  220. package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
  221. package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
  222. package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
  223. package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
  224. package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
  225. package/api/tests/service/collapse.spec.ts +96 -0
  226. package/api/tests/store/tenant-crosscut.spec.ts +202 -0
  227. package/api/tests/store/tenant-model-spike.spec.ts +177 -0
  228. package/api/tests/store/tenant-model.spec.ts +162 -0
  229. package/api/tests/store/tenant-residual.spec.ts +196 -0
  230. package/api/third.d.ts +4 -0
  231. package/blocklet.yml +1 -1
  232. package/cloudflare/README.md +26 -6
  233. package/cloudflare/build.ts +28 -13
  234. package/cloudflare/did-connect-auth.ts +0 -217
  235. package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
  236. package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
  237. package/cloudflare/migrations/0008_schema_parity.sql +16 -0
  238. package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
  239. package/cloudflare/queue-runtime-mode.ts +13 -0
  240. package/cloudflare/run-build.js +10 -56
  241. package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
  242. package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
  243. package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
  244. package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
  245. package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
  246. package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
  247. package/cloudflare/shims/blocklet-sdk/util-csrf.ts +13 -0
  248. package/cloudflare/shims/blocklet-sdk/util-wallet.ts +8 -0
  249. package/cloudflare/shims/cron.ts +38 -158
  250. package/cloudflare/shims/events.ts +124 -0
  251. package/cloudflare/shims/fastq.ts +15 -1
  252. package/cloudflare/shims/nedb-storage.ts +16 -8
  253. package/cloudflare/shims/xss.ts +8 -0
  254. package/cloudflare/tenant-middleware.ts +36 -0
  255. package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
  256. package/cloudflare/tests/worker-handler-gate.spec.ts +44 -0
  257. package/cloudflare/worker.ts +204 -433
  258. package/cloudflare/wrangler.local-e2e.jsonc +26 -0
  259. package/jest.config.js +3 -1
  260. package/package.json +33 -38
  261. package/scripts/core-env-whitelist.json +1 -0
  262. package/scripts/e2e-12b-runtime.ts +149 -0
  263. package/scripts/e2e-core-config.ts +125 -0
  264. package/scripts/e2e-d1-tenancy.ts +116 -0
  265. package/scripts/e2e-d2-cron-queue.ts +139 -0
  266. package/scripts/e2e-d3-embedded-multi.ts +171 -0
  267. package/scripts/e2e-hono-s2.ts +125 -0
  268. package/scripts/e2e-hono-s3e.ts +135 -0
  269. package/scripts/e2e-hono-s4.ts +114 -0
  270. package/scripts/e2e-migration-contract.ts +100 -0
  271. package/scripts/e2e-s0.ts +61 -0
  272. package/scripts/e2e-s1.ts +107 -0
  273. package/scripts/e2e-s2.ts +178 -0
  274. package/scripts/e2e-s3.ts +110 -0
  275. package/scripts/e2e-s4.ts +191 -0
  276. package/scripts/e2e-s5.ts +139 -0
  277. package/scripts/e2e-s6.ts +127 -0
  278. package/scripts/e2e-tenant-model.ts +119 -0
  279. package/scripts/e2e-tenant-worker.ts +199 -0
  280. package/scripts/gen-sql-migrations.js +46 -0
  281. package/scripts/phase8-codemod.js +219 -0
  282. package/scripts/phase9a-env-getters-codemod.js +82 -0
  283. package/scripts/scan-core-env.js +109 -0
  284. package/scripts/scan-tenant-queries.js +235 -0
  285. package/scripts/schema-drift-guard.ts +210 -0
  286. package/scripts/tenant-scan-whitelist.json +1 -0
  287. package/src/env.d.ts +13 -1
  288. package/tsconfig.json +1 -1
  289. package/api/src/libs/did-space.ts +0 -235
  290. package/api/src/libs/middleware.ts +0 -50
  291. package/api/src/libs/security.ts +0 -192
  292. package/api/src/queues/space.ts +0 -662
  293. package/api/src/routes/credit-tokens.ts +0 -38
  294. package/api/src/routes/exchange-rates.ts +0 -87
  295. package/api/src/routes/index.ts +0 -142
  296. package/api/src/routes/integrations/stripe.ts +0 -61
  297. package/api/src/routes/meters.ts +0 -274
  298. package/api/src/routes/passports.ts +0 -68
  299. package/api/src/routes/redirect.ts +0 -20
  300. package/api/src/routes/tool.ts +0 -65
  301. package/api/src/routes/webhook-endpoints.ts +0 -126
  302. package/api/tests/routes/credit-grants.spec.ts +0 -1261
  303. package/cloudflare/shims/did-space-js.ts +0 -17
  304. package/cloudflare/shims/did-space.ts +0 -11
  305. package/cloudflare/shims/express-compat/index.ts +0 -80
  306. package/cloudflare/shims/express-compat/types.ts +0 -41
  307. package/cloudflare/shims/lock.ts +0 -115
  308. package/cloudflare/shims/queue.ts +0 -611
  309. package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
  310. package/cloudflare/tests/shims/queue-scheduled.spec.ts +0 -186
@@ -1,10 +1,12 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
2
  /* eslint-disable @typescript-eslint/indent */
3
3
  import { BN } from '@ocap/util';
4
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model, Op, Sequelize } from 'sequelize';
4
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Op, Sequelize } from 'sequelize';
5
5
  import type { LiteralUnion } from 'type-fest';
6
+ import { TenantModel } from '../tenant-model';
7
+ import { getInstanceDid } from '../../libs/context';
6
8
 
7
- import { createEvent, createStatusEvent } from '../../libs/audit';
9
+ import { createEvent, createStatusEvent, reportAuditFailure } from '../../libs/audit';
8
10
  import { createIdGenerator } from '../../libs/util';
9
11
  import type { GroupedBN, PaymentBeneficiary, PaymentDetails, PaymentError } from './types';
10
12
 
@@ -12,11 +14,12 @@ export const nextPaymentIntentId = createIdGenerator('pi', 24);
12
14
 
13
15
  // @link https://stripe.com/docs/api/payment_intents
14
16
  // eslint-disable-next-line prettier/prettier
15
- export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCreationAttributes<PaymentIntent>> {
17
+ export class PaymentIntent extends TenantModel<InferAttributes<PaymentIntent>, InferCreationAttributes<PaymentIntent>> {
16
18
  // Unique identifier for the object.
17
19
  declare id: CreationOptional<string>;
18
20
 
19
21
  declare livemode: boolean;
22
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
20
23
  declare description: string;
21
24
 
22
25
  declare amount: string;
@@ -244,6 +247,12 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
244
247
  this.init(
245
248
  {
246
249
  ...PaymentIntent.GENESIS_ATTRIBUTES,
250
+ instance_did: {
251
+ type: DataTypes.STRING(64),
252
+ allowNull: true,
253
+ // bare creates must still land in the active tenant (single mode = app DID)
254
+ defaultValue: () => getInstanceDid(),
255
+ },
247
256
  beneficiaries: {
248
257
  type: DataTypes.JSON,
249
258
  allowNull: true,
@@ -258,7 +267,7 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
258
267
  updatedAt: 'updated_at',
259
268
  hooks: {
260
269
  afterCreate: (model: PaymentIntent, options) => {
261
- createEvent('PaymentIntent', 'payment_intent.created', model, options).catch(console.error);
270
+ createEvent('PaymentIntent', 'payment_intent.created', model, options).catch(reportAuditFailure);
262
271
  },
263
272
  afterUpdate: (model: PaymentIntent, options) => {
264
273
  createStatusEvent(
@@ -272,10 +281,10 @@ export class PaymentIntent extends Model<InferAttributes<PaymentIntent>, InferCr
272
281
  },
273
282
  model,
274
283
  options
275
- ).catch(console.error);
284
+ ).catch(reportAuditFailure);
276
285
  },
277
286
  afterDestroy: (model: PaymentIntent, options) => {
278
- createEvent('PaymentIntent', 'payment_intent.deleted', model, options).catch(console.error);
287
+ createEvent('PaymentIntent', 'payment_intent.deleted', model, options).catch(reportAuditFailure);
279
288
  },
280
289
  },
281
290
  }
@@ -1,8 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model, Op } from 'sequelize';
2
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Op } from 'sequelize';
3
3
  import type { LiteralUnion } from 'type-fest';
4
+ import { TenantModel } from '../tenant-model';
5
+ import { getInstanceDid } from '../../libs/context';
4
6
 
5
- import { createEvent } from '../../libs/audit';
7
+ import { createEvent, reportAuditFailure } from '../../libs/audit';
6
8
  import { createIdGenerator } from '../../libs/util';
7
9
  import type {
8
10
  AfterPayment,
@@ -17,13 +19,14 @@ import type {
17
19
  export const nextPaymentLinkId = createIdGenerator('plink', 24);
18
20
 
19
21
  // @link https://stripe.com/docs/api/payment_links/payment_links
20
- export class PaymentLink extends Model<InferAttributes<PaymentLink>, InferCreationAttributes<PaymentLink>> {
22
+ export class PaymentLink extends TenantModel<InferAttributes<PaymentLink>, InferCreationAttributes<PaymentLink>> {
21
23
  // Unique identifier for the object.
22
24
  declare id: CreationOptional<string>;
23
25
 
24
26
  // Whether the PaymentLink is currently available for purchase.
25
27
  declare active: boolean;
26
28
  declare livemode: boolean;
29
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
27
30
 
28
31
  declare name: string;
29
32
 
@@ -211,6 +214,12 @@ export class PaymentLink extends Model<InferAttributes<PaymentLink>, InferCreati
211
214
  this.init(
212
215
  {
213
216
  ...PaymentLink.GENESIS_ATTRIBUTES,
217
+ instance_did: {
218
+ type: DataTypes.STRING(64),
219
+ allowNull: true,
220
+ // bare creates must still land in the active tenant (single mode = app DID)
221
+ defaultValue: () => getInstanceDid(),
222
+ },
214
223
  nft_mint_settings: {
215
224
  type: DataTypes.JSON,
216
225
  allowNull: true,
@@ -240,13 +249,13 @@ export class PaymentLink extends Model<InferAttributes<PaymentLink>, InferCreati
240
249
  updatedAt: 'updated_at',
241
250
  hooks: {
242
251
  afterCreate: (model: PaymentLink, options) => {
243
- createEvent('PaymentLink', 'payment_link.created', model, options).catch(console.error);
252
+ createEvent('PaymentLink', 'payment_link.created', model, options).catch(reportAuditFailure);
244
253
  },
245
254
  afterUpdate: (model: PaymentLink, options) => {
246
- createEvent('PaymentLink', 'payment_link.updated', model, options).catch(console.error);
255
+ createEvent('PaymentLink', 'payment_link.updated', model, options).catch(reportAuditFailure);
247
256
  },
248
257
  afterDestroy: (model: PaymentLink, options) => {
249
- createEvent('PaymentLink', 'payment_link.deleted', model, options).catch(console.error);
258
+ createEvent('PaymentLink', 'payment_link.deleted', model, options).catch(reportAuditFailure);
250
259
  },
251
260
  },
252
261
  }
@@ -1,11 +1,18 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
- import security from '@blocklet/sdk/lib/security';
3
2
  import OcapClient from '@ocap/client';
4
- import { JsonRpcProvider, ethers } from 'ethers';
3
+ // Phase 13b2: ethers is a TYPE-only import here + lazy-required at the one runtime
4
+ // call site. This model is bound by initialize() during createEmbeddedPaymentService,
5
+ // so an eager `import 'ethers'` loaded ethers at factory time — crashing in a host
6
+ // that force-resolves an incompatible @noble/hashes (arc's `@noble/hashes:^2.2.0`
7
+ // override vs ethers@6.16's pinned 1.3.2). EVM clients build only when used.
8
+ import type { JsonRpcProvider } from 'ethers';
5
9
  import cloneDeep from 'lodash/cloneDeep';
6
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
10
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
7
11
  import Stripe from 'stripe';
8
12
  import type { LiteralUnion } from 'type-fest';
13
+ import { TenantModel } from '../tenant-model';
14
+ import { getInstanceDid } from '../../libs/context';
15
+ import { encryptSecret, decryptSecret } from '../../libs/secrets';
9
16
 
10
17
  import { AppStoreClient } from '../../integrations/app-store/client';
11
18
  import { GooglePlayClient } from '../../integrations/google-play/client';
@@ -23,12 +30,13 @@ const googlePlayClients = new Map<string, GooglePlayClient>();
23
30
  const appStoreClients = new Map<string, AppStoreClient>();
24
31
 
25
32
  // eslint-disable-next-line prettier/prettier
26
- export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCreationAttributes<PaymentMethod>> {
33
+ export class PaymentMethod extends TenantModel<InferAttributes<PaymentMethod>, InferCreationAttributes<PaymentMethod>> {
27
34
  // Unique identifier for the object.
28
35
  declare id: CreationOptional<string>;
29
36
 
30
37
  declare active: boolean;
31
38
  declare livemode: boolean;
39
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
32
40
  declare locked: boolean;
33
41
 
34
42
  declare type: LiteralUnion<
@@ -130,13 +138,19 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
130
138
 
131
139
  // eslint-disable-next-line @typescript-eslint/no-shadow
132
140
  public static initialize(sequelize: any) {
133
- this.init(PaymentMethod.GENESIS_ATTRIBUTES, {
134
- sequelize,
135
- modelName: 'PaymentMethod',
136
- tableName: 'payment_methods',
137
- createdAt: 'created_at',
138
- updatedAt: 'updated_at',
139
- });
141
+ this.init(
142
+ {
143
+ ...PaymentMethod.GENESIS_ATTRIBUTES,
144
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
145
+ },
146
+ {
147
+ sequelize,
148
+ modelName: 'PaymentMethod',
149
+ tableName: 'payment_methods',
150
+ createdAt: 'created_at',
151
+ updatedAt: 'updated_at',
152
+ }
153
+ );
140
154
  }
141
155
 
142
156
  public static associate(models: any) {
@@ -157,17 +171,17 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
157
171
  public static encryptSettings(settings: PaymentMethodSettings) {
158
172
  const tmp = cloneDeep(settings);
159
173
  if (tmp.stripe) {
160
- tmp.stripe.secret_key = security.encrypt(tmp.stripe.secret_key);
161
- tmp.stripe.webhook_signing_secret = security.encrypt(tmp.stripe.webhook_signing_secret);
174
+ tmp.stripe.secret_key = encryptSecret(tmp.stripe.secret_key);
175
+ tmp.stripe.webhook_signing_secret = encryptSecret(tmp.stripe.webhook_signing_secret);
162
176
  }
163
177
  if (tmp.google_play) {
164
- tmp.google_play.service_account_json = security.encrypt(tmp.google_play.service_account_json);
178
+ tmp.google_play.service_account_json = encryptSecret(tmp.google_play.service_account_json);
165
179
  }
166
180
  if (tmp.app_store?.private_key_pem) {
167
- tmp.app_store.private_key_pem = security.encrypt(tmp.app_store.private_key_pem);
181
+ tmp.app_store.private_key_pem = encryptSecret(tmp.app_store.private_key_pem);
168
182
  }
169
183
  if (tmp.app_store?.shared_secret) {
170
- tmp.app_store.shared_secret = security.encrypt(tmp.app_store.shared_secret);
184
+ tmp.app_store.shared_secret = encryptSecret(tmp.app_store.shared_secret);
171
185
  }
172
186
 
173
187
  return tmp;
@@ -176,17 +190,17 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
176
190
  public static decryptSettings(settings: PaymentMethodSettings) {
177
191
  const tmp = cloneDeep(settings);
178
192
  if (tmp.stripe) {
179
- tmp.stripe.secret_key = security.decrypt(tmp.stripe.secret_key);
180
- tmp.stripe.webhook_signing_secret = security.decrypt(tmp.stripe.webhook_signing_secret);
193
+ tmp.stripe.secret_key = decryptSecret(tmp.stripe.secret_key);
194
+ tmp.stripe.webhook_signing_secret = decryptSecret(tmp.stripe.webhook_signing_secret);
181
195
  }
182
196
  if (tmp.google_play) {
183
- tmp.google_play.service_account_json = security.decrypt(tmp.google_play.service_account_json);
197
+ tmp.google_play.service_account_json = decryptSecret(tmp.google_play.service_account_json);
184
198
  }
185
199
  if (tmp.app_store?.private_key_pem) {
186
- tmp.app_store.private_key_pem = security.decrypt(tmp.app_store.private_key_pem);
200
+ tmp.app_store.private_key_pem = decryptSecret(tmp.app_store.private_key_pem);
187
201
  }
188
202
  if (tmp.app_store?.shared_secret) {
189
- tmp.app_store.shared_secret = security.decrypt(tmp.app_store.shared_secret);
203
+ tmp.app_store.shared_secret = decryptSecret(tmp.app_store.shared_secret);
190
204
  }
191
205
 
192
206
  return tmp;
@@ -258,8 +272,10 @@ export class PaymentMethod extends Model<InferAttributes<PaymentMethod>, InferCr
258
272
  }
259
273
 
260
274
  const settings = PaymentMethod.decryptSettings(this.settings);
275
+ // eslint-disable-next-line global-require, import/no-extraneous-dependencies
276
+ const { JsonRpcProvider: EthersJsonRpcProvider } = require('ethers');
261
277
  // @ts-ignore
262
- const client = new ethers.JsonRpcProvider(settings[this.type as keyof PaymentMethodSettings]?.api_host);
278
+ const client = new EthersJsonRpcProvider(settings[this.type as keyof PaymentMethodSettings]?.api_host);
263
279
  evmClients.set(this.id, client);
264
280
 
265
281
  return client as JsonRpcProvider;
@@ -1,14 +1,17 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
2
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
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('ps', 24);
7
9
 
8
10
  // eslint-disable-next-line prettier/prettier
9
- export class PaymentStat extends Model<InferAttributes<PaymentStat>, InferCreationAttributes<PaymentStat>> {
11
+ export class PaymentStat extends TenantModel<InferAttributes<PaymentStat>, InferCreationAttributes<PaymentStat>> {
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 timestamp: number;
14
17
  declare currency_id: string;
@@ -64,13 +67,19 @@ export class PaymentStat extends Model<InferAttributes<PaymentStat>, InferCreati
64
67
  };
65
68
 
66
69
  public static initialize(sequelize: any) {
67
- this.init(PaymentStat.GENESIS_ATTRIBUTES, {
68
- sequelize,
69
- modelName: 'PaymentStat',
70
- tableName: 'payment_stats',
71
- createdAt: 'created_at',
72
- updatedAt: 'updated_at',
73
- });
70
+ this.init(
71
+ {
72
+ ...PaymentStat.GENESIS_ATTRIBUTES,
73
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
74
+ },
75
+ {
76
+ sequelize,
77
+ modelName: 'PaymentStat',
78
+ tableName: 'payment_stats',
79
+ createdAt: 'created_at',
80
+ updatedAt: 'updated_at',
81
+ }
82
+ );
74
83
  }
75
84
 
76
85
  public static associate() {}
@@ -1,21 +1,24 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
2
  /* eslint-disable @typescript-eslint/indent */
3
3
  import { BN } from '@ocap/util';
4
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model, Op, Sequelize } from 'sequelize';
4
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Op, Sequelize } from 'sequelize';
5
5
  import type { LiteralUnion } from 'type-fest';
6
+ import { TenantModel } from '../tenant-model';
7
+ import { getInstanceDid } from '../../libs/context';
6
8
 
7
- import { createEvent, createStatusEvent } from '../../libs/audit';
9
+ import { createEvent, createStatusEvent, reportAuditFailure } from '../../libs/audit';
8
10
  import { createIdGenerator } from '../../libs/util';
9
11
  import type { GroupedBN, PaymentDetails, PaymentError } from './types';
10
12
 
11
13
  export const nextPayoutId = createIdGenerator('po', 24);
12
14
 
13
15
  // @link https://stripe.com/docs/api/payouts
14
- export class Payout extends Model<InferAttributes<Payout>, InferCreationAttributes<Payout>> {
16
+ export class Payout extends TenantModel<InferAttributes<Payout>, InferCreationAttributes<Payout>> {
15
17
  // Unique identifier for the object.
16
18
  declare id: CreationOptional<string>;
17
19
 
18
20
  declare livemode: boolean;
21
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
19
22
  declare automatic: boolean;
20
23
  declare description: string;
21
24
  declare destination: string;
@@ -178,6 +181,12 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
178
181
  this.init(
179
182
  {
180
183
  ...Payout.GENESIS_ATTRIBUTES,
184
+ instance_did: {
185
+ type: DataTypes.STRING(64),
186
+ allowNull: true,
187
+ // bare creates must still land in the active tenant (single mode = app DID)
188
+ defaultValue: () => getInstanceDid(),
189
+ },
181
190
  vendor_info: {
182
191
  type: DataTypes.JSON,
183
192
  allowNull: true,
@@ -191,9 +200,9 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
191
200
  updatedAt: 'updated_at',
192
201
  hooks: {
193
202
  afterCreate: (model: Payout, options) => {
194
- createEvent('Payout', 'payout.created', model, options).catch(console.error);
203
+ createEvent('Payout', 'payout.created', model, options).catch(reportAuditFailure);
195
204
  if (model.status === 'paid') {
196
- createEvent('Payout', 'payout.paid', model, options).catch(console.error);
205
+ createEvent('Payout', 'payout.paid', model, options).catch(reportAuditFailure);
197
206
  }
198
207
  },
199
208
  afterUpdate: (model: Payout, options) => {
@@ -203,7 +212,7 @@ export class Payout extends Model<InferAttributes<Payout>, InferCreationAttribut
203
212
  { canceled: 'canceled', failed: 'failed', paid: 'paid' },
204
213
  model,
205
214
  options
206
- ).catch(console.error);
215
+ ).catch(reportAuditFailure);
207
216
  },
208
217
  },
209
218
  }
@@ -1,7 +1,9 @@
1
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model, Transaction } from 'sequelize';
1
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Transaction } 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
- import { createEvent } from '../../libs/audit';
6
+ import { createEvent, reportAuditFailure } from '../../libs/audit';
5
7
  import { createIdGenerator } from '../../libs/util';
6
8
  import { QuoteMetadata, QuoteStatus } from './types';
7
9
 
@@ -33,8 +35,9 @@ export interface CreateQuoteInput {
33
35
  metadata?: QuoteMetadata;
34
36
  }
35
37
 
36
- export class PriceQuote extends Model<InferAttributes<PriceQuote>, InferCreationAttributes<PriceQuote>> {
38
+ export class PriceQuote extends TenantModel<InferAttributes<PriceQuote>, InferCreationAttributes<PriceQuote>> {
37
39
  declare id: CreationOptional<string>;
40
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a); scoped queries land in Phase 3
38
41
  declare price_id: string;
39
42
  declare session_id?: string;
40
43
  declare invoice_id?: string;
@@ -79,6 +82,12 @@ export class PriceQuote extends Model<InferAttributes<PriceQuote>, InferCreation
79
82
  allowNull: false,
80
83
  defaultValue: nextPriceQuoteId,
81
84
  },
85
+ instance_did: {
86
+ type: DataTypes.STRING(64),
87
+ allowNull: true,
88
+ // bare creates must still land in the active tenant (single mode = app DID)
89
+ defaultValue: () => getInstanceDid(),
90
+ },
82
91
  price_id: {
83
92
  type: DataTypes.STRING(32),
84
93
  allowNull: false,
@@ -94,7 +103,7 @@ export class PriceQuote extends Model<InferAttributes<PriceQuote>, InferCreation
94
103
  idempotency_key: {
95
104
  type: DataTypes.STRING(128),
96
105
  allowNull: false,
97
- unique: true,
106
+ // uniqueness is per tenant since Phase 2: see uq_* composite indexes in tenant-backfill.ts
98
107
  },
99
108
  base_currency: {
100
109
  type: DataTypes.STRING(8),
@@ -181,11 +190,11 @@ export class PriceQuote extends Model<InferAttributes<PriceQuote>, InferCreation
181
190
  if (options.transaction) {
182
191
  // Defer until after transaction commits
183
192
  options.transaction.afterCommit(() => {
184
- createEvent('PriceQuote', 'price_quote.created', model, options).catch(console.error);
193
+ createEvent('PriceQuote', 'price_quote.created', model, options).catch(reportAuditFailure);
185
194
  });
186
195
  } else {
187
196
  // No transaction, create immediately
188
- createEvent('PriceQuote', 'price_quote.created', model, options).catch(console.error);
197
+ createEvent('PriceQuote', 'price_quote.created', model, options).catch(reportAuditFailure);
189
198
  }
190
199
  },
191
200
  afterUpdate: (model: PriceQuote, options) => {
@@ -193,11 +202,11 @@ export class PriceQuote extends Model<InferAttributes<PriceQuote>, InferCreation
193
202
  if (options.transaction) {
194
203
  // Defer until after transaction commits
195
204
  options.transaction.afterCommit(() => {
196
- createEvent('PriceQuote', 'price_quote.updated', model, options).catch(console.error);
205
+ createEvent('PriceQuote', 'price_quote.updated', model, options).catch(reportAuditFailure);
197
206
  });
198
207
  } else {
199
208
  // No transaction, create immediately
200
- createEvent('PriceQuote', 'price_quote.updated', model, options).catch(console.error);
209
+ createEvent('PriceQuote', 'price_quote.updated', model, options).catch(reportAuditFailure);
201
210
  }
202
211
  },
203
212
  },
@@ -8,13 +8,14 @@ import {
8
8
  FindOptions,
9
9
  InferAttributes,
10
10
  InferCreationAttributes,
11
- Model,
12
11
  Op,
13
12
  QueryTypes,
14
13
  } from 'sequelize';
15
14
  import type { LiteralUnion } from 'type-fest';
15
+ import { TenantModel } from '../tenant-model';
16
+ import { getInstanceDid } from '../../libs/context';
16
17
 
17
- import { createEvent } from '../../libs/audit';
18
+ import { createEvent, reportAuditFailure } from '../../libs/audit';
18
19
  import logger from '../../libs/logger';
19
20
  import { createIdGenerator, formatMetadata } from '../../libs/util';
20
21
  import { sequelize } from '../sequelize';
@@ -38,7 +39,7 @@ type TPriceExpanded = TPrice & {
38
39
  type TLineItemExpanded = LineItem & { price: TPriceExpanded; upsell_price: TPriceExpanded };
39
40
 
40
41
  // @link https://stripe.com/docs/api/prices
41
- export class Price extends Model<InferAttributes<Price>, InferCreationAttributes<Price>> {
42
+ export class Price extends TenantModel<InferAttributes<Price>, InferCreationAttributes<Price>> {
42
43
  // Unique identifier for the object.
43
44
  declare id: CreationOptional<string>;
44
45
 
@@ -51,6 +52,7 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
51
52
  // Whether the price can be used for new purchases.
52
53
  declare active: boolean;
53
54
  declare livemode: boolean;
55
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
54
56
  declare locked: CreationOptional<boolean>;
55
57
 
56
58
  // One of one_time or recurring depending on whether the price is for a one-time purchase or a recurring (subscription) purchase.
@@ -200,6 +202,12 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
200
202
  this.init(
201
203
  {
202
204
  ...Price.GENESIS_ATTRIBUTES,
205
+ instance_did: {
206
+ type: DataTypes.STRING(64),
207
+ allowNull: true,
208
+ // bare creates must still land in the active tenant (single mode = app DID)
209
+ defaultValue: () => getInstanceDid(),
210
+ },
203
211
  upsell: {
204
212
  type: DataTypes.JSON,
205
213
  allowNull: true,
@@ -250,13 +258,13 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
250
258
  updatedAt: 'updated_at',
251
259
  hooks: {
252
260
  afterCreate: (model: Price, options) => {
253
- createEvent('Price', 'price.created', model, options).catch(console.error);
261
+ createEvent('Price', 'price.created', model, options).catch(reportAuditFailure);
254
262
  },
255
263
  afterUpdate: (model: Price, options) => {
256
- createEvent('Price', 'price.updated', model, options).catch(console.error);
264
+ createEvent('Price', 'price.updated', model, options).catch(reportAuditFailure);
257
265
  },
258
266
  afterDestroy: (model: Price, options) => {
259
- createEvent('Price', 'price.deleted', model, options).catch(console.error);
267
+ createEvent('Price', 'price.deleted', model, options).catch(reportAuditFailure);
260
268
  },
261
269
  },
262
270
  }
@@ -522,10 +530,14 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
522
530
  return true;
523
531
  }
524
532
 
533
+ // 洞 G (Phase 4): raw reads on tenant tables (pricing_tables / payment_links /
534
+ // checkout_sessions) — guard with instance_did so "is this price used?" only
535
+ // ever counts the price's own tenant. price_id is now a bound param too.
536
+ const guard = { price_id: this.id, instance_did: getInstanceDid() };
525
537
  // @ts-ignore
526
538
  let [{ count }] = await this.sequelize.query(
527
- `SELECT count(*) AS count FROM pricing_tables JOIN json_each(items) AS item ON json_extract(item.value, '$.price_id') = '${this.id}'`,
528
- { type: QueryTypes.SELECT }
539
+ "SELECT count(*) AS count FROM pricing_tables JOIN json_each(items) AS item ON json_extract(item.value, '$.price_id') = :price_id WHERE pricing_tables.instance_did = :instance_did",
540
+ { replacements: guard, type: QueryTypes.SELECT }
529
541
  );
530
542
  used = count > 0;
531
543
  if (used) {
@@ -535,8 +547,8 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
535
547
 
536
548
  // @ts-ignore
537
549
  [{ count }] = await this.sequelize.query(
538
- `SELECT count(*) AS count FROM payment_links JOIN json_each(line_items) AS item ON json_extract(item.value, '$.price_id') = '${this.id}'`,
539
- { type: QueryTypes.SELECT }
550
+ "SELECT count(*) AS count FROM payment_links JOIN json_each(line_items) AS item ON json_extract(item.value, '$.price_id') = :price_id WHERE payment_links.instance_did = :instance_did",
551
+ { replacements: guard, type: QueryTypes.SELECT }
540
552
  );
541
553
  used = count > 0;
542
554
  if (used) {
@@ -546,8 +558,8 @@ export class Price extends Model<InferAttributes<Price>, InferCreationAttributes
546
558
 
547
559
  // @ts-ignore
548
560
  [{ count }] = await this.sequelize.query(
549
- `SELECT count(cs.id) AS count FROM checkout_sessions AS cs JOIN json_each(line_items) AS item ON json_extract(item.value, '$.price_id') = '${this.id}' WHERE cs.status != 'expired'`,
550
- { type: QueryTypes.SELECT }
561
+ "SELECT count(cs.id) AS count FROM checkout_sessions AS cs JOIN json_each(line_items) AS item ON json_extract(item.value, '$.price_id') = :price_id WHERE cs.status != 'expired' AND cs.instance_did = :instance_did",
562
+ { replacements: guard, type: QueryTypes.SELECT }
551
563
  );
552
564
  used = count > 0;
553
565
  if (used) {
@@ -1,23 +1,26 @@
1
1
  /* eslint-disable @typescript-eslint/lines-between-class-members */
2
2
  import pick from 'lodash/pick';
3
3
  import uniq from 'lodash/uniq';
4
- import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, Model } from 'sequelize';
4
+ import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
5
5
  import type { LiteralUnion } from 'type-fest';
6
+ import { TenantModel } from '../tenant-model';
7
+ import { getInstanceDid } from '../../libs/context';
6
8
 
7
- import { createEvent } from '../../libs/audit';
9
+ import { createEvent, reportAuditFailure } from '../../libs/audit';
8
10
  import { createIdGenerator, formatMetadata } from '../../libs/util';
9
11
  import type { BrandSettings, PricingTableItem } from './types';
10
12
 
11
13
  export const nextPricingTableId = createIdGenerator('prctbl', 24);
12
14
 
13
15
  // @link https://stripe.com/docs/api/payment_links/payment_links
14
- export class PricingTable extends Model<InferAttributes<PricingTable>, InferCreationAttributes<PricingTable>> {
16
+ export class PricingTable extends TenantModel<InferAttributes<PricingTable>, InferCreationAttributes<PricingTable>> {
15
17
  // Unique identifier for the object.
16
18
  declare id: CreationOptional<string>;
17
19
 
18
20
  // Whether the PricingTable is currently available for purchase.
19
21
  declare active: boolean;
20
22
  declare livemode: boolean;
23
+ declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
21
24
  declare locked: boolean;
22
25
 
23
26
  declare name: string;
@@ -84,24 +87,30 @@ export class PricingTable extends Model<InferAttributes<PricingTable>, InferCrea
84
87
  };
85
88
 
86
89
  public static initialize(sequelize: any) {
87
- this.init(PricingTable.GENESIS_ATTRIBUTES, {
88
- sequelize,
89
- modelName: 'PricingTable',
90
- tableName: 'pricing_tables',
91
- createdAt: 'created_at',
92
- updatedAt: 'updated_at',
93
- hooks: {
94
- afterCreate: (model: PricingTable, options) => {
95
- createEvent('PricingTable', 'pricing_table.created', model, options).catch(console.error);
96
- },
97
- afterUpdate: (model: PricingTable, options) => {
98
- createEvent('PricingTable', 'pricing_table.updated', model, options).catch(console.error);
99
- },
100
- afterDestroy: (model: PricingTable, options) => {
101
- createEvent('PricingTable', 'pricing_table.deleted', model, options).catch(console.error);
102
- },
90
+ this.init(
91
+ {
92
+ ...PricingTable.GENESIS_ATTRIBUTES,
93
+ instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
103
94
  },
104
- });
95
+ {
96
+ sequelize,
97
+ modelName: 'PricingTable',
98
+ tableName: 'pricing_tables',
99
+ createdAt: 'created_at',
100
+ updatedAt: 'updated_at',
101
+ hooks: {
102
+ afterCreate: (model: PricingTable, options) => {
103
+ createEvent('PricingTable', 'pricing_table.created', model, options).catch(reportAuditFailure);
104
+ },
105
+ afterUpdate: (model: PricingTable, options) => {
106
+ createEvent('PricingTable', 'pricing_table.updated', model, options).catch(reportAuditFailure);
107
+ },
108
+ afterDestroy: (model: PricingTable, options) => {
109
+ createEvent('PricingTable', 'pricing_table.deleted', model, options).catch(reportAuditFailure);
110
+ },
111
+ },
112
+ }
113
+ );
105
114
  }
106
115
 
107
116
  public static associate() {