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.
- package/api/dev.ts +41 -2
- package/api/hono.d.ts +42 -0
- package/api/node-sqlite.d.ts +12 -0
- package/api/src/bootstrap.ts +36 -0
- package/api/src/crons/base.ts +3 -3
- package/api/src/crons/currency.ts +1 -1
- package/api/src/crons/index.ts +27 -24
- package/api/src/crons/metering-subscription-detection.ts +1 -1
- package/api/src/crons/overdue-detection.ts +2 -2
- package/api/src/crons/retry-pending-events.ts +6 -0
- package/api/src/index.ts +22 -161
- package/api/src/integrations/app-store/client.ts +3 -4
- package/api/src/integrations/app-store/handlers/subscription.ts +7 -7
- package/api/src/integrations/app-store/signed-data-verifier.ts +3 -2
- package/api/src/integrations/arcblock/token.ts +21 -7
- package/api/src/integrations/google-play/handlers/subscription.ts +6 -6
- package/api/src/integrations/google-play/handlers/voided.ts +2 -2
- package/api/src/integrations/google-play/verify.ts +3 -2
- package/api/src/integrations/iap-reconcile.ts +3 -5
- package/api/src/integrations/stripe/handlers/invoice.ts +2 -2
- package/api/src/integrations/stripe/handlers/subscription.ts +3 -3
- package/api/src/libs/archive/query.ts +19 -0
- package/api/src/libs/audit.ts +61 -4
- package/api/src/libs/auth.ts +99 -38
- package/api/src/libs/context.ts +78 -1
- package/api/src/libs/currency.ts +2 -2
- package/api/src/libs/dayjs.ts +8 -2
- package/api/src/libs/drivers/auth-storage.ts +118 -0
- package/api/src/libs/drivers/cron.ts +264 -0
- package/api/src/libs/drivers/db.ts +170 -0
- package/api/src/libs/drivers/identity.ts +81 -0
- package/api/src/libs/drivers/index.ts +40 -0
- package/api/src/libs/drivers/locks.ts +226 -0
- package/api/src/libs/drivers/migrate-runner.ts +70 -0
- package/api/src/libs/drivers/queue.ts +104 -0
- package/api/src/libs/drivers/secrets.ts +194 -0
- package/api/src/libs/env.ts +170 -54
- package/api/src/libs/exchange-rate/service.ts +7 -6
- package/api/src/libs/http-fetch-adapter.ts +50 -0
- package/api/src/libs/invoice.ts +1 -1
- package/api/src/libs/lock.ts +51 -47
- package/api/src/libs/logger.ts +48 -8
- package/api/src/libs/notification/index.ts +1 -1
- package/api/src/libs/notification/template/customer-credit-low-balance.ts +2 -1
- package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -1
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -1
- package/api/src/libs/overdraft-protection.ts +1 -1
- package/api/src/libs/payout.ts +1 -1
- package/api/src/libs/queue/index.ts +259 -52
- package/api/src/libs/queue/runtime.ts +175 -0
- package/api/src/libs/resource.ts +3 -3
- package/api/src/libs/secrets.ts +38 -0
- package/api/src/libs/session.ts +3 -2
- package/api/src/libs/subscription.ts +5 -5
- package/api/src/libs/tenant.ts +92 -0
- package/api/src/libs/url.ts +3 -3
- package/api/src/libs/util.ts +21 -13
- package/api/src/middlewares/hono/cdn.ts +63 -0
- package/api/src/middlewares/hono/context.ts +73 -0
- package/api/src/middlewares/hono/csrf.ts +72 -0
- package/api/src/middlewares/hono/fallback.ts +194 -0
- package/api/src/middlewares/hono/pipeline.ts +73 -0
- package/api/src/middlewares/hono/resource-mount.ts +42 -0
- package/api/src/middlewares/hono/resource.ts +63 -0
- package/api/src/middlewares/hono/security.ts +214 -0
- package/api/src/middlewares/hono/session.ts +114 -0
- package/api/src/middlewares/hono/xss.ts +61 -0
- package/api/src/queues/auto-recharge.ts +12 -10
- package/api/src/queues/checkout-session.ts +17 -12
- package/api/src/queues/credit-consume.ts +40 -36
- package/api/src/queues/credit-grant.ts +25 -18
- package/api/src/queues/credit-reconciliation.ts +7 -5
- package/api/src/queues/discount-status.ts +9 -6
- package/api/src/queues/event.ts +12 -4
- package/api/src/queues/exchange-rate-health.ts +49 -30
- package/api/src/queues/invoice.ts +18 -15
- package/api/src/queues/notification.ts +14 -7
- package/api/src/queues/payment.ts +41 -28
- package/api/src/queues/payout.ts +9 -5
- package/api/src/queues/refund.ts +18 -12
- package/api/src/queues/subscription.ts +83 -53
- package/api/src/queues/token-transfer.ts +15 -10
- package/api/src/queues/usage-record.ts +8 -5
- package/api/src/queues/vendors/commission.ts +7 -5
- package/api/src/queues/vendors/fulfillment-coordinator.ts +17 -13
- package/api/src/queues/vendors/fulfillment.ts +4 -2
- package/api/src/queues/vendors/return-processor.ts +5 -3
- package/api/src/queues/vendors/return-scanner.ts +5 -4
- package/api/src/queues/vendors/status-check.ts +10 -7
- package/api/src/queues/webhook.ts +60 -32
- package/api/src/routes/connect/shared.ts +1 -2
- package/api/src/routes/connect/subscribe.ts +3 -3
- package/api/src/routes/{archive.ts → hono/archive.ts} +69 -64
- package/api/src/routes/{auto-recharge-configs.ts → hono/auto-recharge-configs.ts} +39 -28
- package/api/src/routes/{checkout-sessions.ts → hono/checkout-sessions.ts} +790 -923
- package/api/src/routes/{coupons.ts → hono/coupons.ts} +93 -76
- package/api/src/routes/{credit-grants.ts → hono/credit-grants.ts} +140 -126
- package/api/src/routes/hono/credit-tokens.ts +43 -0
- package/api/src/routes/{credit-transactions.ts → hono/credit-transactions.ts} +37 -29
- package/api/src/routes/{customers.ts → hono/customers.ts} +193 -223
- package/api/src/routes/{donations.ts → hono/donations.ts} +41 -32
- package/api/src/routes/{entitlements.ts → hono/entitlements.ts} +28 -25
- package/api/src/routes/{events.ts → hono/events.ts} +107 -71
- package/api/src/routes/{exchange-rate-providers.ts → hono/exchange-rate-providers.ts} +138 -126
- package/api/src/routes/hono/exchange-rates.ts +77 -0
- package/api/src/routes/hono/index.ts +115 -0
- package/api/src/routes/{integrations → hono/integrations}/app-store.ts +68 -48
- package/api/src/routes/{integrations → hono/integrations}/google-play.ts +78 -58
- package/api/src/routes/hono/integrations/stripe.ts +74 -0
- package/api/src/routes/{invoices.ts → hono/invoices.ts} +253 -244
- package/api/src/routes/{meter-events.ts → hono/meter-events.ts} +120 -110
- package/api/src/routes/hono/meters.ts +288 -0
- package/api/src/routes/hono/passports.ts +73 -0
- package/api/src/routes/{payment-currencies.ts → hono/payment-currencies.ts} +219 -197
- package/api/src/routes/{payment-intents.ts → hono/payment-intents.ts} +136 -132
- package/api/src/routes/{payment-links.ts → hono/payment-links.ts} +145 -128
- package/api/src/routes/{payment-methods.ts → hono/payment-methods.ts} +125 -93
- package/api/src/routes/{payment-stats.ts → hono/payment-stats.ts} +30 -25
- package/api/src/routes/{payouts.ts → hono/payouts.ts} +55 -47
- package/api/src/routes/{prices.ts → hono/prices.ts} +265 -242
- package/api/src/routes/{pricing-table.ts → hono/pricing-table.ts} +94 -87
- package/api/src/routes/{products.ts → hono/products.ts} +172 -159
- package/api/src/routes/{promotion-codes.ts → hono/promotion-codes.ts} +207 -185
- package/api/src/routes/hono/redirect.ts +24 -0
- package/api/src/routes/{refunds.ts → hono/refunds.ts} +96 -80
- package/api/src/routes/{settings.ts → hono/settings.ts} +64 -55
- package/api/src/routes/{subscription-items.ts → hono/subscription-items.ts} +64 -57
- package/api/src/routes/{subscriptions.ts → hono/subscriptions.ts} +475 -528
- package/api/src/routes/{tax-rates.ts → hono/tax-rates.ts} +71 -70
- package/api/src/routes/hono/tool.ts +69 -0
- package/api/src/routes/{usage-records.ts → hono/usage-records.ts} +47 -42
- package/api/src/routes/{vendor.ts → hono/vendor.ts} +315 -167
- package/api/src/routes/{webhook-attempts.ts → hono/webhook-attempts.ts} +17 -13
- package/api/src/routes/hono/webhook-endpoints.ts +126 -0
- package/api/src/service.ts +667 -0
- package/api/src/store/migrations/20230911-seeding.ts +2 -1
- package/api/src/store/migrations/20260609-remove-did-space-jobs.ts +23 -0
- package/api/src/store/migrations/20260610-tenant-columns.ts +40 -0
- package/api/src/store/migrations/20260611-tenant-backfill.ts +33 -0
- package/api/src/store/models/auto-recharge-config.ts +22 -10
- package/api/src/store/models/checkout-session.ts +15 -14
- package/api/src/store/models/coupon.ts +29 -20
- package/api/src/store/models/credit-grant.ts +38 -29
- package/api/src/store/models/credit-transaction.ts +32 -21
- package/api/src/store/models/customer.ts +19 -17
- package/api/src/store/models/discount.ts +11 -2
- package/api/src/store/models/entitlement-grant.ts +21 -9
- package/api/src/store/models/entitlement-product.ts +21 -9
- package/api/src/store/models/entitlement.ts +19 -10
- package/api/src/store/models/event.ts +18 -9
- package/api/src/store/models/exchange-rate-provider.ts +17 -4
- package/api/src/store/models/invoice-item.ts +18 -9
- package/api/src/store/models/invoice.ts +16 -8
- package/api/src/store/models/meter-event.ts +27 -9
- package/api/src/store/models/meter.ts +31 -22
- package/api/src/store/models/payment-currency.ts +25 -8
- package/api/src/store/models/payment-intent.ts +15 -6
- package/api/src/store/models/payment-link.ts +15 -6
- package/api/src/store/models/payment-method.ts +38 -22
- package/api/src/store/models/payment-stat.ts +18 -9
- package/api/src/store/models/payout.ts +15 -6
- package/api/src/store/models/price-quote.ts +17 -8
- package/api/src/store/models/price.ts +24 -12
- package/api/src/store/models/pricing-table.ts +29 -20
- package/api/src/store/models/product-vendor.ts +20 -10
- package/api/src/store/models/product.ts +15 -6
- package/api/src/store/models/promotion-code.ts +14 -6
- package/api/src/store/models/refund.ts +15 -6
- package/api/src/store/models/revenue-snapshot.ts +21 -9
- package/api/src/store/models/setting.ts +18 -9
- package/api/src/store/models/setup-intent.ts +36 -27
- package/api/src/store/models/subscription-item.ts +21 -9
- package/api/src/store/models/subscription-schedule.ts +21 -9
- package/api/src/store/models/subscription.ts +21 -10
- package/api/src/store/models/tax-rate.ts +29 -21
- package/api/src/store/models/usage-record.ts +11 -2
- package/api/src/store/models/webhook-attempt.ts +18 -9
- package/api/src/store/models/webhook-endpoint.ts +18 -9
- package/api/src/store/scoped-core.ts +55 -0
- package/api/src/store/scoped.ts +247 -0
- package/api/src/store/sequelize.ts +66 -22
- package/api/src/store/sql-migrations.ts +20 -0
- package/api/src/store/tenant-backfill.ts +260 -0
- package/api/src/store/tenant-model.ts +124 -0
- package/api/src/store/tenant-tables.ts +50 -0
- package/api/tests/embedded/embedded-multi-mode-d3.spec.ts +257 -0
- package/api/tests/fixtures/bare-query-violation.ts +13 -0
- package/api/tests/fixtures/core-env-violation.ts +10 -0
- package/api/tests/fixtures/host-read-violation.ts +19 -0
- package/api/tests/fixtures/tenants.ts +4 -0
- package/api/tests/integrations/iap-tenant.spec.ts +284 -0
- package/api/tests/libs/archive-query.spec.ts +26 -0
- package/api/tests/libs/audit-tenant.spec.ts +153 -0
- package/api/tests/libs/context.spec.ts +204 -0
- package/api/tests/libs/core-config.spec.ts +115 -0
- package/api/tests/libs/cron-driver-d2.spec.ts +237 -0
- package/api/tests/libs/crons-conservation-d2.spec.ts +52 -0
- package/api/tests/libs/lock-tenant.spec.ts +66 -0
- package/api/tests/libs/scoped.spec.ts +222 -0
- package/api/tests/libs/secrets-facade.spec.ts +52 -0
- package/api/tests/libs/tenancy-slot-authority.spec.ts +209 -0
- package/api/tests/libs/tenant-middleware.spec.ts +42 -0
- package/api/tests/libs/tenant-scanner.spec.ts +120 -0
- package/api/tests/middlewares/hono/cdn.spec.ts +70 -0
- package/api/tests/middlewares/hono/context.spec.ts +113 -0
- package/api/tests/middlewares/hono/csrf.spec.ts +136 -0
- package/api/tests/middlewares/hono/fallback.spec.ts +67 -0
- package/api/tests/middlewares/hono/pipeline.spec.ts +47 -0
- package/api/tests/middlewares/hono/security.spec.ts +181 -0
- package/api/tests/middlewares/hono/session.spec.ts +42 -0
- package/api/tests/middlewares/hono/xss.spec.ts +81 -0
- package/api/tests/models/tenant-backfill.spec.ts +287 -0
- package/api/tests/models/tenant-columns-model.spec.ts +46 -0
- package/api/tests/models/tenant-columns.spec.ts +161 -0
- package/api/tests/queues/credit-consume-batch.spec.ts +8 -1
- package/api/tests/queues/credit-consume.spec.ts +8 -1
- package/api/tests/queues/event-tenant.spec.ts +236 -0
- package/api/tests/queues/exchange-rate-health-tenant-d6.spec.ts +62 -0
- package/api/tests/queues/queue-parity.spec.ts +249 -0
- package/api/tests/queues/queue-runtime-surface.spec.ts +277 -0
- package/api/tests/queues/queue-teardown-d2.spec.ts +127 -0
- package/api/tests/queues/tenant-matrix-a.spec.ts +245 -0
- package/api/tests/queues/tenant-matrix-b.spec.ts +168 -0
- package/api/tests/routes/connect/hono-attach.spec.ts +107 -0
- package/api/tests/service/collapse.spec.ts +96 -0
- package/api/tests/store/tenant-crosscut.spec.ts +202 -0
- package/api/tests/store/tenant-model-spike.spec.ts +177 -0
- package/api/tests/store/tenant-model.spec.ts +162 -0
- package/api/tests/store/tenant-residual.spec.ts +196 -0
- package/api/third.d.ts +4 -0
- package/blocklet.yml +1 -1
- package/cloudflare/README.md +26 -6
- package/cloudflare/build.ts +28 -13
- package/cloudflare/did-connect-auth.ts +0 -217
- package/cloudflare/migrations/0006_tenant_columns.sql +46 -0
- package/cloudflare/migrations/0007_tenant_backfill_indexes.sql +65 -0
- package/cloudflare/migrations/0008_schema_parity.sql +16 -0
- package/cloudflare/migrations/0009_remove_did_space_jobs.sql +5 -0
- package/cloudflare/queue-runtime-mode.ts +13 -0
- package/cloudflare/run-build.js +10 -56
- package/cloudflare/shims/blocklet-sdk/asset-host-transformer.ts +20 -0
- package/cloudflare/shims/blocklet-sdk/config.ts +8 -1
- package/cloudflare/shims/blocklet-sdk/login.ts +12 -0
- package/cloudflare/shims/blocklet-sdk/service-api.ts +14 -0
- package/cloudflare/shims/blocklet-sdk/session.ts +4 -2
- package/cloudflare/shims/blocklet-sdk/util-constants.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/util-csrf.ts +13 -0
- package/cloudflare/shims/blocklet-sdk/util-wallet.ts +8 -0
- package/cloudflare/shims/cron.ts +38 -158
- package/cloudflare/shims/events.ts +124 -0
- package/cloudflare/shims/fastq.ts +15 -1
- package/cloudflare/shims/nedb-storage.ts +16 -8
- package/cloudflare/shims/xss.ts +8 -0
- package/cloudflare/tenant-middleware.ts +36 -0
- package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
- package/cloudflare/tests/worker-handler-gate.spec.ts +44 -0
- package/cloudflare/worker.ts +204 -433
- package/cloudflare/wrangler.local-e2e.jsonc +26 -0
- package/jest.config.js +3 -1
- package/package.json +33 -38
- package/scripts/core-env-whitelist.json +1 -0
- package/scripts/e2e-12b-runtime.ts +149 -0
- package/scripts/e2e-core-config.ts +125 -0
- package/scripts/e2e-d1-tenancy.ts +116 -0
- package/scripts/e2e-d2-cron-queue.ts +139 -0
- package/scripts/e2e-d3-embedded-multi.ts +171 -0
- package/scripts/e2e-hono-s2.ts +125 -0
- package/scripts/e2e-hono-s3e.ts +135 -0
- package/scripts/e2e-hono-s4.ts +114 -0
- package/scripts/e2e-migration-contract.ts +100 -0
- package/scripts/e2e-s0.ts +61 -0
- package/scripts/e2e-s1.ts +107 -0
- package/scripts/e2e-s2.ts +178 -0
- package/scripts/e2e-s3.ts +110 -0
- package/scripts/e2e-s4.ts +191 -0
- package/scripts/e2e-s5.ts +139 -0
- package/scripts/e2e-s6.ts +127 -0
- package/scripts/e2e-tenant-model.ts +119 -0
- package/scripts/e2e-tenant-worker.ts +199 -0
- package/scripts/gen-sql-migrations.js +46 -0
- package/scripts/phase8-codemod.js +219 -0
- package/scripts/phase9a-env-getters-codemod.js +82 -0
- package/scripts/scan-core-env.js +109 -0
- package/scripts/scan-tenant-queries.js +235 -0
- package/scripts/schema-drift-guard.ts +210 -0
- package/scripts/tenant-scan-whitelist.json +1 -0
- package/src/env.d.ts +13 -1
- package/tsconfig.json +1 -1
- package/api/src/libs/did-space.ts +0 -235
- package/api/src/libs/middleware.ts +0 -50
- package/api/src/libs/security.ts +0 -192
- package/api/src/queues/space.ts +0 -662
- package/api/src/routes/credit-tokens.ts +0 -38
- package/api/src/routes/exchange-rates.ts +0 -87
- package/api/src/routes/index.ts +0 -142
- package/api/src/routes/integrations/stripe.ts +0 -61
- package/api/src/routes/meters.ts +0 -274
- package/api/src/routes/passports.ts +0 -68
- package/api/src/routes/redirect.ts +0 -20
- package/api/src/routes/tool.ts +0 -65
- package/api/src/routes/webhook-endpoints.ts +0 -126
- package/api/tests/routes/credit-grants.spec.ts +0 -1261
- package/cloudflare/shims/did-space-js.ts +0 -17
- package/cloudflare/shims/did-space.ts +0 -11
- package/cloudflare/shims/express-compat/index.ts +0 -80
- package/cloudflare/shims/express-compat/types.ts +0 -41
- package/cloudflare/shims/lock.ts +0 -115
- package/cloudflare/shims/queue.ts +0 -611
- package/cloudflare/tests/shims/queue-delayed-persist.spec.ts +0 -87
- 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,
|
|
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
|
|
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(
|
|
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(
|
|
284
|
+
).catch(reportAuditFailure);
|
|
276
285
|
},
|
|
277
286
|
afterDestroy: (model: PaymentIntent, options) => {
|
|
278
|
-
createEvent('PaymentIntent', 'payment_intent.deleted', model, options).catch(
|
|
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,
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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 =
|
|
161
|
-
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
180
|
-
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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,
|
|
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
|
|
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(
|
|
203
|
+
createEvent('Payout', 'payout.created', model, options).catch(reportAuditFailure);
|
|
195
204
|
if (model.status === 'paid') {
|
|
196
|
-
createEvent('Payout', 'payout.paid', model, options).catch(
|
|
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(
|
|
215
|
+
).catch(reportAuditFailure);
|
|
207
216
|
},
|
|
208
217
|
},
|
|
209
218
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes,
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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() {
|