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,13 +1,14 @@
|
|
|
1
1
|
import { fromTokenToUnit } from '@ocap/util';
|
|
2
2
|
import Sequelize from 'sequelize';
|
|
3
3
|
import { joinURL } from 'ufo';
|
|
4
|
+
import { blockletMountPoints } from '../../libs/env';
|
|
4
5
|
|
|
5
6
|
import { createIdGenerator } from '../../libs/util';
|
|
6
7
|
import type { Migration } from '../migrate';
|
|
7
8
|
|
|
8
9
|
const getUrl = (...parts: string[]): string => {
|
|
9
10
|
const { BLOCKLET_COMPONENT_DID, BLOCKLET_APP_URL } = process.env;
|
|
10
|
-
const components = JSON.parse(
|
|
11
|
+
const components = JSON.parse(blockletMountPoints() || '[]');
|
|
11
12
|
const component = components.find((x: any) => [x.title, x.name, x.did].includes(BLOCKLET_COMPONENT_DID));
|
|
12
13
|
const mountPoint = component?.mountPoint || '/';
|
|
13
14
|
return joinURL(BLOCKLET_APP_URL as string, mountPoint === '/' ? '' : mountPoint, ...parts);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Migration } from '../migrate';
|
|
2
|
+
|
|
3
|
+
// The DID Space billing-mirror integration was removed (libs/did-space.ts,
|
|
4
|
+
// queues/space.ts). Rows in `jobs` with queue='did-space' can never be picked
|
|
5
|
+
// up again — the scheduled-job scan only matches registered queue names — so
|
|
6
|
+
// they would sit in the table forever. Delete them.
|
|
7
|
+
//
|
|
8
|
+
// Idempotent: re-running deletes nothing.
|
|
9
|
+
//
|
|
10
|
+
// Dated 20260609 (before the tenant-columns/tenant-backfill pair; written
|
|
11
|
+
// 2026-06-12): the tenant-backfill acceptance spec drives umzug positionally
|
|
12
|
+
// and requires 20260611-tenant-backfill to stay the LAST migration. The jobs
|
|
13
|
+
// table exists since genesis, so running earlier is semantically identical;
|
|
14
|
+
// on already-migrated deployments umzug executes pending migrations
|
|
15
|
+
// regardless of how their names sort against executed ones.
|
|
16
|
+
|
|
17
|
+
export const up: Migration = async ({ context }) => {
|
|
18
|
+
await context.sequelize.query("DELETE FROM `jobs` WHERE `queue` = 'did-space'");
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const down: Migration = async () => {
|
|
22
|
+
// Deleted jobs are not restorable (and the queue no longer exists).
|
|
23
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Migration } from '../migrate';
|
|
2
|
+
import { TENANT_TABLES } from '../tenant-tables';
|
|
3
|
+
|
|
4
|
+
// Phase 1 (W1-1a): add a nullable instance_did column to all 38 tenant tables.
|
|
5
|
+
// No constraints, no indexes, no backfill — those land in Phase 2 (W1-1b).
|
|
6
|
+
// Until then the column stays NULL and no code reads or writes it, so runtime
|
|
7
|
+
// behavior is byte-for-byte identical to the previous release.
|
|
8
|
+
//
|
|
9
|
+
// Uses PRAGMA table_info + raw ALTER TABLE (mirroring cloudflare/migrations/
|
|
10
|
+
// 0006_tenant_columns.sql) instead of describeTable/removeColumn: sequelize's
|
|
11
|
+
// sqlite describeTable chokes on some of our partial indexes, and removeColumn
|
|
12
|
+
// rebuilds the whole table for no benefit here. Table names are static literals
|
|
13
|
+
// from TENANT_TABLES — nothing is interpolated from config or env.
|
|
14
|
+
|
|
15
|
+
async function hasInstanceDid(context: any, table: string): Promise<boolean> {
|
|
16
|
+
const [rows] = await context.sequelize.query(`PRAGMA table_info(${table})`);
|
|
17
|
+
return (rows as { name: string }[]).some((row) => row.name === 'instance_did');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const up: Migration = async ({ context }) => {
|
|
21
|
+
for (const table of TENANT_TABLES) {
|
|
22
|
+
// eslint-disable-next-line no-await-in-loop
|
|
23
|
+
if (!(await hasInstanceDid(context, table))) {
|
|
24
|
+
// eslint-disable-next-line no-await-in-loop
|
|
25
|
+
await context.sequelize.query(`ALTER TABLE ${table} ADD COLUMN instance_did VARCHAR(64)`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const down: Migration = async ({ context }) => {
|
|
31
|
+
for (const table of TENANT_TABLES) {
|
|
32
|
+
// eslint-disable-next-line no-await-in-loop
|
|
33
|
+
if (await hasInstanceDid(context, table)) {
|
|
34
|
+
// SQLite >= 3.35 supports DROP COLUMN; safe here because Phase 1 adds
|
|
35
|
+
// no indexes or constraints on the column.
|
|
36
|
+
// eslint-disable-next-line no-await-in-loop
|
|
37
|
+
await context.sequelize.query(`ALTER TABLE ${table} DROP COLUMN instance_did`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Migration } from '../migrate';
|
|
2
|
+
import { UNIQUE_KEY_REVISIONS, runTenantBackfill } from '../tenant-backfill';
|
|
3
|
+
import { TENANT_TABLES } from '../tenant-tables';
|
|
4
|
+
|
|
5
|
+
// Phase 2 (W1-1b): backfill instance_did with the deployment app DID, revise
|
|
6
|
+
// business unique keys to (instance_did, ...) composites, add tenant indexes.
|
|
7
|
+
// All heavy lifting lives in ../tenant-backfill.ts, shared with the CF worker
|
|
8
|
+
// runtime compensation path (static D1 SQL cannot know the app DID).
|
|
9
|
+
//
|
|
10
|
+
// Idempotent: backfill touches NULL rows only; rebuilds detect already-rebuilt
|
|
11
|
+
// DDL; index creation is IF NOT EXISTS. Re-running after a crash continues.
|
|
12
|
+
|
|
13
|
+
export const up: Migration = async ({ context }) => {
|
|
14
|
+
await runTenantBackfill(context.sequelize as any);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const down: Migration = async ({ context }) => {
|
|
18
|
+
const { sequelize } = context as any;
|
|
19
|
+
// Reverting Phase 2 = dropping the composite uniques and tenant indexes.
|
|
20
|
+
// Backfilled values stay (the column is nullable in DDL for non-rebuilt
|
|
21
|
+
// tables and harmless when unused); restoring the old inline single-column
|
|
22
|
+
// uniques is deliberately NOT done — they would forbid the cross-tenant
|
|
23
|
+
// duplicates this phase exists to allow, and recreating them on a DB that
|
|
24
|
+
// already contains such duplicates would corrupt the rollback.
|
|
25
|
+
for (const revision of UNIQUE_KEY_REVISIONS) {
|
|
26
|
+
// eslint-disable-next-line no-await-in-loop
|
|
27
|
+
await sequelize.query(`DROP INDEX IF EXISTS \`${revision.index}\``);
|
|
28
|
+
}
|
|
29
|
+
for (const table of TENANT_TABLES) {
|
|
30
|
+
// eslint-disable-next-line no-await-in-loop
|
|
31
|
+
await sequelize.query(`DROP INDEX IF EXISTS \`idx_${table}_instance_did\``);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/lines-between-class-members */
|
|
2
|
-
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes
|
|
3
|
-
|
|
2
|
+
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes } from 'sequelize';
|
|
4
3
|
import { BN } from '@ocap/util';
|
|
4
|
+
import { TenantModel } from '../tenant-model';
|
|
5
|
+
import { getInstanceDid } from '../../libs/context';
|
|
6
|
+
|
|
5
7
|
import { createIdGenerator } from '../../libs/util';
|
|
6
8
|
import { PaymentDetails, PaymentSettings } from './types';
|
|
7
9
|
|
|
8
10
|
const nextId = createIdGenerator('carc', 24);
|
|
9
11
|
|
|
10
12
|
// eslint-disable-next-line prettier/prettier
|
|
11
|
-
export class AutoRechargeConfig extends
|
|
13
|
+
export class AutoRechargeConfig extends TenantModel<
|
|
14
|
+
InferAttributes<AutoRechargeConfig>,
|
|
15
|
+
InferCreationAttributes<AutoRechargeConfig>
|
|
16
|
+
> {
|
|
12
17
|
declare id: CreationOptional<string>;
|
|
13
18
|
declare customer_id: string;
|
|
14
19
|
declare livemode: boolean;
|
|
20
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
15
21
|
|
|
16
22
|
declare enabled: boolean;
|
|
17
23
|
declare threshold: string;
|
|
@@ -150,13 +156,19 @@ export class AutoRechargeConfig extends Model<InferAttributes<AutoRechargeConfig
|
|
|
150
156
|
};
|
|
151
157
|
|
|
152
158
|
public static initialize(sequelize: any) {
|
|
153
|
-
this.init(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
this.init(
|
|
160
|
+
{
|
|
161
|
+
...AutoRechargeConfig.GENESIS_ATTRIBUTES,
|
|
162
|
+
instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
sequelize,
|
|
166
|
+
modelName: 'AutoRechargeConfig',
|
|
167
|
+
tableName: 'auto_recharge_configs',
|
|
168
|
+
createdAt: 'created_at',
|
|
169
|
+
updatedAt: 'updated_at',
|
|
170
|
+
}
|
|
171
|
+
);
|
|
160
172
|
}
|
|
161
173
|
|
|
162
174
|
public static associate(models: any) {
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/lines-between-class-members */
|
|
2
2
|
/* eslint-disable @typescript-eslint/indent */
|
|
3
|
-
import {
|
|
4
|
-
CreationOptional,
|
|
5
|
-
DataTypes,
|
|
6
|
-
FindOptions,
|
|
7
|
-
InferAttributes,
|
|
8
|
-
InferCreationAttributes,
|
|
9
|
-
Model,
|
|
10
|
-
Op,
|
|
11
|
-
} from 'sequelize';
|
|
3
|
+
import { CreationOptional, DataTypes, FindOptions, InferAttributes, InferCreationAttributes, Op } from 'sequelize';
|
|
12
4
|
import type { LiteralUnion } from 'type-fest';
|
|
5
|
+
import { TenantModel } from '../tenant-model';
|
|
6
|
+
import { getInstanceDid } from '../../libs/context';
|
|
13
7
|
|
|
14
|
-
import { createCustomEvent, createEvent, createStatusEvent } from '../../libs/audit';
|
|
8
|
+
import { createCustomEvent, createEvent, createStatusEvent, reportAuditFailure } from '../../libs/audit';
|
|
15
9
|
import dayjs from '../../libs/dayjs';
|
|
16
10
|
import { CHECKOUT_SESSION_TTL, createIdGenerator } from '../../libs/util';
|
|
17
11
|
import type {
|
|
@@ -35,10 +29,11 @@ export const nextCheckoutSessionId = createIdGenerator('cs', 58);
|
|
|
35
29
|
|
|
36
30
|
// @link https://stripe.com/docs/api/checkout/sessions
|
|
37
31
|
// eslint-disable-next-line prettier/prettier
|
|
38
|
-
export class CheckoutSession extends
|
|
32
|
+
export class CheckoutSession extends TenantModel<InferAttributes<CheckoutSession>, InferCreationAttributes<CheckoutSession>> {
|
|
39
33
|
// Unique identifier for the object.
|
|
40
34
|
declare id: CreationOptional<string>;
|
|
41
35
|
declare livemode: boolean;
|
|
36
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
42
37
|
declare client_reference_id?: string;
|
|
43
38
|
|
|
44
39
|
// ID of the payment currency
|
|
@@ -445,6 +440,12 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
445
440
|
this.init(
|
|
446
441
|
{
|
|
447
442
|
...CheckoutSession.GENESIS_ATTRIBUTES,
|
|
443
|
+
instance_did: {
|
|
444
|
+
type: DataTypes.STRING(64),
|
|
445
|
+
allowNull: true,
|
|
446
|
+
// bare creates must still land in the active tenant (single mode = app DID)
|
|
447
|
+
defaultValue: () => getInstanceDid(),
|
|
448
|
+
},
|
|
448
449
|
discounts: {
|
|
449
450
|
type: DataTypes.JSON,
|
|
450
451
|
allowNull: true,
|
|
@@ -503,7 +504,7 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
503
504
|
updatedAt: 'updated_at',
|
|
504
505
|
hooks: {
|
|
505
506
|
afterCreate: (model: CheckoutSession, options) => {
|
|
506
|
-
createEvent('CheckoutSession', 'checkout.session.created', model, options).catch(
|
|
507
|
+
createEvent('CheckoutSession', 'checkout.session.created', model, options).catch(reportAuditFailure);
|
|
507
508
|
},
|
|
508
509
|
afterUpdate: (model: CheckoutSession, options) => {
|
|
509
510
|
createStatusEvent(
|
|
@@ -512,7 +513,7 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
512
513
|
{ complete: 'completed', expired: 'expired' },
|
|
513
514
|
model,
|
|
514
515
|
options
|
|
515
|
-
).catch(
|
|
516
|
+
).catch(reportAuditFailure);
|
|
516
517
|
createCustomEvent(
|
|
517
518
|
'CheckoutSession',
|
|
518
519
|
'checkout.session',
|
|
@@ -524,7 +525,7 @@ export class CheckoutSession extends Model<InferAttributes<CheckoutSession>, Inf
|
|
|
524
525
|
},
|
|
525
526
|
model,
|
|
526
527
|
options
|
|
527
|
-
).catch(
|
|
528
|
+
).catch(reportAuditFailure);
|
|
528
529
|
},
|
|
529
530
|
},
|
|
530
531
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
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
3
|
import type { LiteralUnion } from 'type-fest';
|
|
4
4
|
import { fromTokenToUnit } from '@ocap/util';
|
|
5
|
+
import { getInstanceDid } from '../../libs/context';
|
|
6
|
+
import { TenantModel } from '../tenant-model';
|
|
5
7
|
|
|
6
|
-
import { createEvent } from '../../libs/audit';
|
|
8
|
+
import { createEvent, reportAuditFailure } from '../../libs/audit';
|
|
7
9
|
import { createCodeGenerator, formatMetadata } from '../../libs/util';
|
|
8
10
|
import { trimDecimals } from '../../libs/math-utils';
|
|
9
11
|
import logger from '../../libs/logger';
|
|
@@ -12,9 +14,10 @@ import type { TPaymentCurrency } from './payment-currency';
|
|
|
12
14
|
const nextId = createCodeGenerator('', 8);
|
|
13
15
|
|
|
14
16
|
// eslint-disable-next-line prettier/prettier
|
|
15
|
-
export class Coupon extends
|
|
17
|
+
export class Coupon extends TenantModel<InferAttributes<Coupon>, InferCreationAttributes<Coupon>> {
|
|
16
18
|
declare id: CreationOptional<string>;
|
|
17
19
|
declare livemode: boolean;
|
|
20
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
18
21
|
declare locked: CreationOptional<boolean>;
|
|
19
22
|
|
|
20
23
|
declare amount_off: string;
|
|
@@ -146,24 +149,30 @@ export class Coupon extends Model<InferAttributes<Coupon>, InferCreationAttribut
|
|
|
146
149
|
};
|
|
147
150
|
|
|
148
151
|
public static initialize(sequelize: any) {
|
|
149
|
-
this.init(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
createdAt: 'created_at',
|
|
154
|
-
updatedAt: 'updated_at',
|
|
155
|
-
hooks: {
|
|
156
|
-
afterCreate: (model: Coupon, options) => {
|
|
157
|
-
createEvent('Coupon', 'coupon.created', model, options).catch(console.error);
|
|
158
|
-
},
|
|
159
|
-
afterUpdate: (model: Coupon, options) => {
|
|
160
|
-
createEvent('Coupon', 'coupon.updated', model, options).catch(console.error);
|
|
161
|
-
},
|
|
162
|
-
afterDestroy: (model: Coupon, options) => {
|
|
163
|
-
createEvent('Coupon', 'coupon.deleted', model, options).catch(console.error);
|
|
164
|
-
},
|
|
152
|
+
this.init(
|
|
153
|
+
{
|
|
154
|
+
...Coupon.GENESIS_ATTRIBUTES,
|
|
155
|
+
instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
|
|
165
156
|
},
|
|
166
|
-
|
|
157
|
+
{
|
|
158
|
+
sequelize,
|
|
159
|
+
modelName: 'Coupon',
|
|
160
|
+
tableName: 'coupons',
|
|
161
|
+
createdAt: 'created_at',
|
|
162
|
+
updatedAt: 'updated_at',
|
|
163
|
+
hooks: {
|
|
164
|
+
afterCreate: (model: Coupon, options) => {
|
|
165
|
+
createEvent('Coupon', 'coupon.created', model, options).catch(reportAuditFailure);
|
|
166
|
+
},
|
|
167
|
+
afterUpdate: (model: Coupon, options) => {
|
|
168
|
+
createEvent('Coupon', 'coupon.updated', model, options).catch(reportAuditFailure);
|
|
169
|
+
},
|
|
170
|
+
afterDestroy: (model: Coupon, options) => {
|
|
171
|
+
createEvent('Coupon', 'coupon.deleted', model, options).catch(reportAuditFailure);
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
);
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
public static associate(models: any) {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/lines-between-class-members */
|
|
2
2
|
import { BN } from '@ocap/util';
|
|
3
|
-
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, literal,
|
|
3
|
+
import { CreationOptional, DataTypes, InferAttributes, InferCreationAttributes, literal, Op } from 'sequelize';
|
|
4
4
|
import type { LiteralUnion } from 'type-fest';
|
|
5
|
+
import { TenantModel } from '../tenant-model';
|
|
6
|
+
import { getInstanceDid } from '../../libs/context';
|
|
5
7
|
|
|
6
|
-
import { createEvent } from '../../libs/audit';
|
|
8
|
+
import { createEvent, reportAuditFailure } from '../../libs/audit';
|
|
7
9
|
import { createIdGenerator } from '../../libs/util';
|
|
8
10
|
import dayjs from '../../libs/dayjs';
|
|
9
11
|
import { CreditGrantApplicabilityConfig, CreditGrantChainDetail, CreditGrantChainStatus } from './types';
|
|
@@ -43,7 +45,7 @@ async function createCreditGrantStatusEvent(model: CreditGrant, options: any): P
|
|
|
43
45
|
|
|
44
46
|
export const nextCreditGrantId = createIdGenerator('credgr', 14);
|
|
45
47
|
|
|
46
|
-
export class CreditGrant extends
|
|
48
|
+
export class CreditGrant extends TenantModel<InferAttributes<CreditGrant>, InferCreationAttributes<CreditGrant>> {
|
|
47
49
|
declare id: CreationOptional<string>;
|
|
48
50
|
declare object: CreationOptional<string>;
|
|
49
51
|
declare amount: string;
|
|
@@ -54,6 +56,7 @@ export class CreditGrant extends Model<InferAttributes<CreditGrant>, InferCreati
|
|
|
54
56
|
declare effective_at?: number;
|
|
55
57
|
declare expires_at?: number;
|
|
56
58
|
declare livemode: boolean;
|
|
59
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
57
60
|
declare metadata?: Record<string, any>;
|
|
58
61
|
declare name?: string;
|
|
59
62
|
declare priority: number; // 0-100, 0为最高优先级
|
|
@@ -265,7 +268,7 @@ export class CreditGrant extends Model<InferAttributes<CreditGrant>, InferCreati
|
|
|
265
268
|
// Fire-and-forget: audit event should not block the consumption hot path.
|
|
266
269
|
// Trade-off: if the process crashes between save() and this call, the audit event is lost,
|
|
267
270
|
// but grant state is already persisted and can be reconciled from DB.
|
|
268
|
-
createEvent('CreditGrant', 'customer.credit_grant.consumed', this).catch(
|
|
271
|
+
createEvent('CreditGrant', 'customer.credit_grant.consumed', this).catch(reportAuditFailure);
|
|
269
272
|
}
|
|
270
273
|
|
|
271
274
|
return {
|
|
@@ -302,32 +305,38 @@ export class CreditGrant extends Model<InferAttributes<CreditGrant>, InferCreati
|
|
|
302
305
|
}
|
|
303
306
|
|
|
304
307
|
public static initialize(sequelize: any) {
|
|
305
|
-
this.init(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
createdAt: 'created_at',
|
|
310
|
-
updatedAt: 'updated_at',
|
|
311
|
-
indexes: [
|
|
312
|
-
{ fields: ['status'], name: 'idx_credit_grant_status' },
|
|
313
|
-
{ fields: ['effective_at'], name: 'idx_credit_grant_effective_at' },
|
|
314
|
-
{ fields: ['expires_at'], name: 'idx_credit_grant_expires_at' },
|
|
315
|
-
],
|
|
316
|
-
hooks: {
|
|
317
|
-
afterCreate: (model: CreditGrant, options) => {
|
|
318
|
-
createEvent('CreditGrant', 'customer.credit_grant.created', model, options).catch(console.error);
|
|
319
|
-
},
|
|
320
|
-
afterUpdate: (model: CreditGrant, options) => {
|
|
321
|
-
createEvent('CreditGrant', 'customer.credit_grant.updated', model, options).catch(console.error);
|
|
322
|
-
|
|
323
|
-
if (model.changed('status')) {
|
|
324
|
-
createCreditGrantStatusEvent(model, options).catch(console.error);
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
afterDestroy: (model: CreditGrant, options) =>
|
|
328
|
-
createEvent('CreditGrant', 'customer.credit_grant.deleted', model, options).catch(console.error),
|
|
308
|
+
this.init(
|
|
309
|
+
{
|
|
310
|
+
...this.GENESIS_ATTRIBUTES,
|
|
311
|
+
instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
|
|
329
312
|
},
|
|
330
|
-
|
|
313
|
+
{
|
|
314
|
+
sequelize,
|
|
315
|
+
modelName: 'CreditGrant',
|
|
316
|
+
tableName: 'credit_grants',
|
|
317
|
+
createdAt: 'created_at',
|
|
318
|
+
updatedAt: 'updated_at',
|
|
319
|
+
indexes: [
|
|
320
|
+
{ fields: ['status'], name: 'idx_credit_grant_status' },
|
|
321
|
+
{ fields: ['effective_at'], name: 'idx_credit_grant_effective_at' },
|
|
322
|
+
{ fields: ['expires_at'], name: 'idx_credit_grant_expires_at' },
|
|
323
|
+
],
|
|
324
|
+
hooks: {
|
|
325
|
+
afterCreate: (model: CreditGrant, options) => {
|
|
326
|
+
createEvent('CreditGrant', 'customer.credit_grant.created', model, options).catch(reportAuditFailure);
|
|
327
|
+
},
|
|
328
|
+
afterUpdate: (model: CreditGrant, options) => {
|
|
329
|
+
createEvent('CreditGrant', 'customer.credit_grant.updated', model, options).catch(reportAuditFailure);
|
|
330
|
+
|
|
331
|
+
if (model.changed('status')) {
|
|
332
|
+
createCreditGrantStatusEvent(model, options).catch(reportAuditFailure);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
afterDestroy: (model: CreditGrant, options) =>
|
|
336
|
+
createEvent('CreditGrant', 'customer.credit_grant.deleted', model, options).catch(reportAuditFailure),
|
|
337
|
+
},
|
|
338
|
+
}
|
|
339
|
+
);
|
|
331
340
|
}
|
|
332
341
|
|
|
333
342
|
public static associate(models: any) {
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/lines-between-class-members */
|
|
2
|
-
import { col, CreationOptional, DataTypes, fn, InferAttributes, InferCreationAttributes,
|
|
3
|
-
|
|
2
|
+
import { col, CreationOptional, DataTypes, fn, InferAttributes, InferCreationAttributes, Op } from 'sequelize';
|
|
4
3
|
import { BN } from '@ocap/util';
|
|
5
|
-
import {
|
|
4
|
+
import { TenantModel } from '../tenant-model';
|
|
5
|
+
import { getInstanceDid } from '../../libs/context';
|
|
6
|
+
|
|
7
|
+
import { createEvent, reportAuditFailure } from '../../libs/audit';
|
|
6
8
|
import { createIdGenerator } from '../../libs/util';
|
|
7
9
|
import { CreditGrant } from './credit-grant';
|
|
8
10
|
|
|
9
11
|
export const nextCreditTransactionId = createIdGenerator('cbtxn', 14);
|
|
10
12
|
|
|
11
|
-
export class CreditTransaction extends
|
|
13
|
+
export class CreditTransaction extends TenantModel<
|
|
12
14
|
InferAttributes<CreditTransaction>,
|
|
13
15
|
InferCreationAttributes<CreditTransaction>
|
|
14
16
|
> {
|
|
15
17
|
declare id: CreationOptional<string>;
|
|
18
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
16
19
|
declare quantity: string;
|
|
17
20
|
declare credit_amount: string;
|
|
18
21
|
declare remaining_balance: string;
|
|
@@ -113,24 +116,32 @@ export class CreditTransaction extends Model<
|
|
|
113
116
|
};
|
|
114
117
|
|
|
115
118
|
public static initialize(sequelize: any) {
|
|
116
|
-
this.init(
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
createdAt: 'created_at',
|
|
121
|
-
updatedAt: 'updated_at',
|
|
122
|
-
indexes: [
|
|
123
|
-
{ fields: ['customer_id'] },
|
|
124
|
-
{ fields: ['credit_grant_id'] },
|
|
125
|
-
{ fields: ['source'] },
|
|
126
|
-
{ fields: ['transfer_status'] },
|
|
127
|
-
],
|
|
128
|
-
hooks: {
|
|
129
|
-
afterCreate: (model: CreditTransaction, options) => {
|
|
130
|
-
createEvent('CreditTransaction', 'customer.credit_transaction.created', model, options).catch(console.error);
|
|
131
|
-
},
|
|
119
|
+
this.init(
|
|
120
|
+
{
|
|
121
|
+
...this.GENESIS_ATTRIBUTES,
|
|
122
|
+
instance_did: { type: DataTypes.STRING(64), allowNull: true, defaultValue: () => getInstanceDid() },
|
|
132
123
|
},
|
|
133
|
-
|
|
124
|
+
{
|
|
125
|
+
sequelize,
|
|
126
|
+
modelName: 'CreditTransaction',
|
|
127
|
+
tableName: 'credit_transactions',
|
|
128
|
+
createdAt: 'created_at',
|
|
129
|
+
updatedAt: 'updated_at',
|
|
130
|
+
indexes: [
|
|
131
|
+
{ fields: ['customer_id'] },
|
|
132
|
+
{ fields: ['credit_grant_id'] },
|
|
133
|
+
{ fields: ['source'] },
|
|
134
|
+
{ fields: ['transfer_status'] },
|
|
135
|
+
],
|
|
136
|
+
hooks: {
|
|
137
|
+
afterCreate: (model: CreditTransaction, options) => {
|
|
138
|
+
createEvent('CreditTransaction', 'customer.credit_transaction.created', model, options).catch(
|
|
139
|
+
reportAuditFailure
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
}
|
|
144
|
+
);
|
|
134
145
|
}
|
|
135
146
|
|
|
136
147
|
public static associate(models: any) {
|
|
@@ -2,19 +2,14 @@
|
|
|
2
2
|
import { BN } from '@ocap/util';
|
|
3
3
|
import cloneDeep from 'lodash/cloneDeep';
|
|
4
4
|
import padStart from 'lodash/padStart';
|
|
5
|
-
import {
|
|
6
|
-
CreationOptional,
|
|
7
|
-
DataTypes,
|
|
8
|
-
FindOptions,
|
|
9
|
-
InferAttributes,
|
|
10
|
-
InferCreationAttributes,
|
|
11
|
-
Model,
|
|
12
|
-
Op,
|
|
13
|
-
} from 'sequelize';
|
|
14
|
-
|
|
5
|
+
import { CreationOptional, DataTypes, FindOptions, InferAttributes, InferCreationAttributes, Op } from 'sequelize';
|
|
15
6
|
import merge from 'lodash/merge';
|
|
7
|
+
import { cfEnv } from '../../libs/env';
|
|
8
|
+
import { TenantModel } from '../tenant-model';
|
|
9
|
+
|
|
10
|
+
import { getInstanceDid } from '../../libs/context';
|
|
16
11
|
import { getLock } from '../../libs/lock';
|
|
17
|
-
import { createEvent } from '../../libs/audit';
|
|
12
|
+
import { createEvent, reportAuditFailure } from '../../libs/audit';
|
|
18
13
|
import CustomError from '../../libs/error';
|
|
19
14
|
import { createCodeGenerator, createIdGenerator } from '../../libs/util';
|
|
20
15
|
import type { CustomerAddress, CustomerPreferences, CustomerShipping } from './types';
|
|
@@ -23,9 +18,10 @@ export const nextCustomerId = createIdGenerator('cus', 14);
|
|
|
23
18
|
export const nextInvoicePrefix = createCodeGenerator('', 8);
|
|
24
19
|
|
|
25
20
|
// eslint-disable-next-line prettier/prettier
|
|
26
|
-
export class Customer extends
|
|
21
|
+
export class Customer extends TenantModel<InferAttributes<Customer>, InferCreationAttributes<Customer>> {
|
|
27
22
|
declare id: CreationOptional<string>;
|
|
28
23
|
declare livemode: boolean;
|
|
24
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
29
25
|
|
|
30
26
|
declare did: string;
|
|
31
27
|
declare description: string;
|
|
@@ -85,7 +81,7 @@ export class Customer extends Model<InferAttributes<Customer>, InferCreationAttr
|
|
|
85
81
|
did: {
|
|
86
82
|
type: DataTypes.STRING(40),
|
|
87
83
|
allowNull: false,
|
|
88
|
-
|
|
84
|
+
// uniqueness is per tenant since Phase 2: see uq_* composite indexes in tenant-backfill.ts
|
|
89
85
|
},
|
|
90
86
|
address: {
|
|
91
87
|
type: DataTypes.JSON,
|
|
@@ -177,7 +173,7 @@ export class Customer extends Model<InferAttributes<Customer>, InferCreationAttr
|
|
|
177
173
|
//
|
|
178
174
|
// SQLite serializes writes at the DB level, so the application-level lock is
|
|
179
175
|
// redundant for both D1 and Blocklet Server's SQLite.
|
|
180
|
-
const d1 = (
|
|
176
|
+
const d1 = cfEnv()?.DB;
|
|
181
177
|
if (d1) {
|
|
182
178
|
try {
|
|
183
179
|
const sql =
|
|
@@ -265,6 +261,12 @@ export class Customer extends Model<InferAttributes<Customer>, InferCreationAttr
|
|
|
265
261
|
this.init(
|
|
266
262
|
{
|
|
267
263
|
...Customer.GENESIS_ATTRIBUTES,
|
|
264
|
+
instance_did: {
|
|
265
|
+
type: DataTypes.STRING(64),
|
|
266
|
+
allowNull: true,
|
|
267
|
+
// bare creates must still land in the active tenant (single mode = app DID)
|
|
268
|
+
defaultValue: () => getInstanceDid(),
|
|
269
|
+
},
|
|
268
270
|
token_balance: {
|
|
269
271
|
type: DataTypes.JSON,
|
|
270
272
|
defaultValue: {},
|
|
@@ -295,13 +297,13 @@ export class Customer extends Model<InferAttributes<Customer>, InferCreationAttr
|
|
|
295
297
|
updatedAt: 'updated_at',
|
|
296
298
|
hooks: {
|
|
297
299
|
afterCreate: (model: Customer, options) => {
|
|
298
|
-
createEvent('Customer', 'customer.created', model, options).catch(
|
|
300
|
+
createEvent('Customer', 'customer.created', model, options).catch(reportAuditFailure);
|
|
299
301
|
},
|
|
300
302
|
afterUpdate: (model: Customer, options) => {
|
|
301
|
-
createEvent('Customer', 'customer.updated', model, options).catch(
|
|
303
|
+
createEvent('Customer', 'customer.updated', model, options).catch(reportAuditFailure);
|
|
302
304
|
},
|
|
303
305
|
afterDestroy: (model: Customer, options) => {
|
|
304
|
-
createEvent('Customer', 'customer.deleted', model, options).catch(
|
|
306
|
+
createEvent('Customer', 'customer.deleted', model, options).catch(reportAuditFailure);
|
|
305
307
|
},
|
|
306
308
|
},
|
|
307
309
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
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 { createCodeGenerator } from '../../libs/util';
|
|
5
7
|
|
|
@@ -7,9 +9,10 @@ const nextId = createCodeGenerator('', 8);
|
|
|
7
9
|
|
|
8
10
|
// @link https://stripe.com/docs/api/discounts
|
|
9
11
|
// eslint-disable-next-line prettier/prettier
|
|
10
|
-
export class Discount extends
|
|
12
|
+
export class Discount extends TenantModel<InferAttributes<Discount>, InferCreationAttributes<Discount>> {
|
|
11
13
|
declare id: CreationOptional<string>;
|
|
12
14
|
declare livemode: boolean;
|
|
15
|
+
declare instance_did?: string; // tenant column (Phase 1, W1-1a), nullable until Phase 2 backfill; scoped queries land in Phase 3
|
|
13
16
|
|
|
14
17
|
declare coupon_id: string;
|
|
15
18
|
declare promotion_code_id?: string;
|
|
@@ -105,6 +108,12 @@ export class Discount extends Model<InferAttributes<Discount>, InferCreationAttr
|
|
|
105
108
|
this.init(
|
|
106
109
|
{
|
|
107
110
|
...Discount.GENESIS_ATTRIBUTES,
|
|
111
|
+
instance_did: {
|
|
112
|
+
type: DataTypes.STRING(64),
|
|
113
|
+
allowNull: true,
|
|
114
|
+
// bare creates must still land in the active tenant (single mode = app DID)
|
|
115
|
+
defaultValue: () => getInstanceDid(),
|
|
116
|
+
},
|
|
108
117
|
confirmed: {
|
|
109
118
|
type: DataTypes.BOOLEAN,
|
|
110
119
|
defaultValue: true,
|