payment-kit 1.29.0 → 1.29.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/docs/2026-06-10-bundle-size-analysis.md +288 -0
- 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 +31 -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/node-fetch.ts +35 -0
- 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,9 +1,11 @@
|
|
|
1
1
|
import isEmpty from 'lodash/isEmpty';
|
|
2
|
-
|
|
3
2
|
import { BN } from '@ocap/util';
|
|
3
|
+
import { isCfWorker } from '../libs/env';
|
|
4
|
+
import { systemFindAll, systemFindByPk, systemFindOne } from '../store/scoped';
|
|
5
|
+
|
|
4
6
|
import { ensureStakedForGas } from '../integrations/arcblock/stake';
|
|
5
7
|
import { transferErc20FromUser } from '../integrations/ethereum/token';
|
|
6
|
-
import { createEvent } from '../libs/audit';
|
|
8
|
+
import { createEvent, reportAuditFailure } from '../libs/audit';
|
|
7
9
|
import { blocklet, wallet } from '../libs/auth';
|
|
8
10
|
import dayjs from '../libs/dayjs';
|
|
9
11
|
import CustomError from '../libs/error';
|
|
@@ -41,7 +43,7 @@ import { notificationQueue } from './notification';
|
|
|
41
43
|
import { ensureOverdraftProtectionInvoiceAndItems } from '../libs/invoice';
|
|
42
44
|
import { AutoRechargeConfig, Lock, MeterEvent } from '../store/models';
|
|
43
45
|
import { ensureOverdraftProtectionPrice } from '../libs/overdraft-protection';
|
|
44
|
-
import createQueue from '../libs/queue';
|
|
46
|
+
import createQueue, { assertJobObjectTenant } from '../libs/queue';
|
|
45
47
|
import { CHARGE_SUPPORTED_CHAIN_TYPES, EVM_CHAIN_TYPES } from '../libs/constants';
|
|
46
48
|
import { getCheckoutSessionSubscriptionIds, getSubscriptionCreateSetup, SlippageOptions } from '../libs/session';
|
|
47
49
|
import { syncStripeSubscriptionAfterRecovery } from '../integrations/stripe/handlers/subscription';
|
|
@@ -170,11 +172,11 @@ export async function updateSubscriptionOnPaymentSuccess(
|
|
|
170
172
|
// Trigger renewal and upgrade events
|
|
171
173
|
if (triggerRenew && (!invoice || invoice.billing_reason !== 'subscription_update')) {
|
|
172
174
|
if (!invoice || invoice.billing_reason === 'subscription_cycle' || paymentIntent?.capture_method === 'manual') {
|
|
173
|
-
createEvent('Subscription', 'customer.subscription.renewed', subscription).catch(
|
|
175
|
+
createEvent('Subscription', 'customer.subscription.renewed', subscription).catch(reportAuditFailure);
|
|
174
176
|
}
|
|
175
177
|
}
|
|
176
178
|
if (invoice?.billing_reason === 'subscription_update') {
|
|
177
|
-
createEvent('Subscription', 'customer.subscription.upgraded', subscription).catch(
|
|
179
|
+
createEvent('Subscription', 'customer.subscription.upgraded', subscription).catch(reportAuditFailure);
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -232,11 +234,11 @@ export async function handlePastDueSubscriptionRecovery(
|
|
|
232
234
|
}
|
|
233
235
|
|
|
234
236
|
// Reset billing cycle
|
|
235
|
-
const subscriptionItems = await SubscriptionItem
|
|
237
|
+
const subscriptionItems = await systemFindAll(SubscriptionItem, { where: { subscription_id: subscription.id } });
|
|
236
238
|
const lineItems = await Price.expand(subscriptionItems.map((x) => x.toJSON()));
|
|
237
239
|
// Use the subscription's slippage config if available, otherwise use default 0.5%
|
|
238
240
|
const slippageConfig = subscription.slippage_config;
|
|
239
|
-
const currency = await PaymentCurrency
|
|
241
|
+
const currency = await systemFindByPk(PaymentCurrency, subscription.currency_id);
|
|
240
242
|
const slippageOptions: SlippageOptions = {
|
|
241
243
|
percent: slippageConfig?.percent ?? 0.5,
|
|
242
244
|
minAcceptableRate: slippageConfig?.min_acceptable_rate,
|
|
@@ -255,7 +257,7 @@ export async function handlePastDueSubscriptionRecovery(
|
|
|
255
257
|
cancelation_details: null,
|
|
256
258
|
});
|
|
257
259
|
|
|
258
|
-
createEvent('Subscription', 'customer.subscription.recovered', subscription).catch(
|
|
260
|
+
createEvent('Subscription', 'customer.subscription.recovered', subscription).catch(reportAuditFailure);
|
|
259
261
|
const recoveryReason =
|
|
260
262
|
subscription.cancelation_details?.reason === 'insufficient_credit' ? 'credit replenished' : 'payment done';
|
|
261
263
|
logger.info(
|
|
@@ -405,20 +407,20 @@ export const handlePaymentSucceed = async (
|
|
|
405
407
|
|
|
406
408
|
let invoice;
|
|
407
409
|
if (paymentIntent.invoice_id) {
|
|
408
|
-
invoice = await Invoice
|
|
410
|
+
invoice = await systemFindByPk(Invoice, paymentIntent.invoice_id);
|
|
409
411
|
}
|
|
410
412
|
|
|
411
413
|
// Handle checkout session when no invoice exists
|
|
412
414
|
if (!invoice && !slashStake) {
|
|
413
|
-
const checkoutSession = await CheckoutSession
|
|
415
|
+
const checkoutSession = await systemFindOne(CheckoutSession, { where: { payment_intent_id: paymentIntent.id } });
|
|
414
416
|
if (checkoutSession) {
|
|
415
417
|
if (
|
|
416
|
-
(
|
|
418
|
+
isCfWorker() &&
|
|
417
419
|
checkoutSession.mode === 'payment' &&
|
|
418
420
|
checkoutSession.invoice_creation?.enabled &&
|
|
419
421
|
!checkoutSession.invoice_id
|
|
420
422
|
) {
|
|
421
|
-
const customer = await Customer
|
|
423
|
+
const customer = await systemFindByPk(Customer, checkoutSession.customer_id);
|
|
422
424
|
if (customer) {
|
|
423
425
|
try {
|
|
424
426
|
const result = await ensureInvoiceForCheckout({
|
|
@@ -480,7 +482,7 @@ export const handlePaymentSucceed = async (
|
|
|
480
482
|
}
|
|
481
483
|
// Update subscription status
|
|
482
484
|
if (invoice && invoice.subscription_id && !slashStake) {
|
|
483
|
-
const subscription = await Subscription
|
|
485
|
+
const subscription = await systemFindByPk(Subscription, invoice.subscription_id);
|
|
484
486
|
if (subscription) {
|
|
485
487
|
await updateSubscriptionOnPaymentSuccess(paymentIntent, subscription, invoice, triggerRenew);
|
|
486
488
|
}
|
|
@@ -488,7 +490,7 @@ export const handlePaymentSucceed = async (
|
|
|
488
490
|
|
|
489
491
|
// Update checkout session
|
|
490
492
|
if (invoice && invoice.checkout_session_id && !slashStake) {
|
|
491
|
-
const checkoutSession = await CheckoutSession
|
|
493
|
+
const checkoutSession = await systemFindByPk(CheckoutSession, invoice.checkout_session_id);
|
|
492
494
|
if (checkoutSession) {
|
|
493
495
|
await updateCheckoutSessionOnPaymentSuccess(paymentIntent, checkoutSession, invoice);
|
|
494
496
|
}
|
|
@@ -508,7 +510,7 @@ export const doOverdraftProtection = async (
|
|
|
508
510
|
});
|
|
509
511
|
return;
|
|
510
512
|
}
|
|
511
|
-
const existProtectedInvoice = await Invoice
|
|
513
|
+
const existProtectedInvoice = await systemFindOne(Invoice, {
|
|
512
514
|
where: {
|
|
513
515
|
subscription_id: subscription.id,
|
|
514
516
|
billing_reason: 'overdraft_protection',
|
|
@@ -593,10 +595,11 @@ export const handlePaymentFailed = async (
|
|
|
593
595
|
if (!invoice.subscription_id) {
|
|
594
596
|
return updates.retry;
|
|
595
597
|
}
|
|
596
|
-
const subscription = await Subscription
|
|
598
|
+
const subscription = await systemFindByPk(Subscription, invoice.subscription_id);
|
|
597
599
|
if (!subscription) {
|
|
598
600
|
return updates.retry;
|
|
599
601
|
}
|
|
602
|
+
assertJobObjectTenant(subscription);
|
|
600
603
|
|
|
601
604
|
const { interval } = subscription.pending_invoice_item_interval;
|
|
602
605
|
updates.retry.minRetryMail = getMinRetryMail(interval);
|
|
@@ -636,7 +639,7 @@ export const handlePaymentFailed = async (
|
|
|
636
639
|
return updates.terminate;
|
|
637
640
|
}
|
|
638
641
|
// check overdraft protection, if protected, no need to check due
|
|
639
|
-
const customer = await Customer
|
|
642
|
+
const customer = await systemFindByPk(Customer, invoice.customer_id);
|
|
640
643
|
|
|
641
644
|
const { enabled: enableOverdraftProtection, unused: unusedAmount } =
|
|
642
645
|
await isSubscriptionOverdraftProtectionEnabled(subscription);
|
|
@@ -649,7 +652,9 @@ export const handlePaymentFailed = async (
|
|
|
649
652
|
const isLock = await Lock.isLocked(lockKey);
|
|
650
653
|
if (!isLock) {
|
|
651
654
|
await Lock.acquire(lockKey, subscription.current_period_end);
|
|
652
|
-
createEvent('Subscription', 'subscription.overdraft_protection.exhausted', subscription).catch(
|
|
655
|
+
createEvent('Subscription', 'subscription.overdraft_protection.exhausted', subscription).catch(
|
|
656
|
+
reportAuditFailure
|
|
657
|
+
);
|
|
653
658
|
}
|
|
654
659
|
}
|
|
655
660
|
|
|
@@ -735,7 +740,10 @@ export const handlePaymentFailed = async (
|
|
|
735
740
|
});
|
|
736
741
|
|
|
737
742
|
if (invoice.billing_reason === 'auto_recharge' && invoice.metadata?.recharge_config?.recharge_id) {
|
|
738
|
-
const autoRechargeConfig = await
|
|
743
|
+
const autoRechargeConfig = await systemFindByPk(
|
|
744
|
+
AutoRechargeConfig,
|
|
745
|
+
invoice.metadata?.recharge_config?.recharge_id
|
|
746
|
+
);
|
|
739
747
|
if (autoRechargeConfig && autoRechargeConfig.enabled) {
|
|
740
748
|
autoRechargeConfig.update({
|
|
741
749
|
enabled: false,
|
|
@@ -760,7 +768,7 @@ const handleStakeSlash = async (
|
|
|
760
768
|
customer: Customer,
|
|
761
769
|
paymentCurrency: PaymentCurrency
|
|
762
770
|
) => {
|
|
763
|
-
const subscription = await Subscription
|
|
771
|
+
const subscription = await systemFindByPk(Subscription, invoice.subscription_id);
|
|
764
772
|
if (!subscription) {
|
|
765
773
|
logger.warn('Stake slashing skipped because Subscription not found', {
|
|
766
774
|
subscription: invoice.subscription_id,
|
|
@@ -769,6 +777,7 @@ const handleStakeSlash = async (
|
|
|
769
777
|
});
|
|
770
778
|
return;
|
|
771
779
|
}
|
|
780
|
+
assertJobObjectTenant(subscription);
|
|
772
781
|
if (!subscription.cancelation_details?.slash_stake || subscription.status !== 'canceled') {
|
|
773
782
|
logger.warn('Stake slashing skipped because subscription not canceled or slash_stake is false', {
|
|
774
783
|
subscription: invoice.subscription_id,
|
|
@@ -871,22 +880,24 @@ const handleStakeSlash = async (
|
|
|
871
880
|
export const handlePayment = async (job: PaymentJob) => {
|
|
872
881
|
logger.info('handle payment', job);
|
|
873
882
|
|
|
874
|
-
const paymentIntent = await PaymentIntent
|
|
883
|
+
const paymentIntent = await systemFindByPk(PaymentIntent, job.paymentIntentId);
|
|
875
884
|
if (!paymentIntent) {
|
|
876
885
|
logger.warn('PaymentIntent not found', { id: job.paymentIntentId });
|
|
877
886
|
return;
|
|
878
887
|
}
|
|
888
|
+
assertJobObjectTenant(paymentIntent);
|
|
879
889
|
|
|
880
890
|
if (['requires_capture', 'processing'].includes(paymentIntent.status) === false) {
|
|
881
891
|
logger.warn('PaymentIntent status not expected', { id: paymentIntent.id, status: paymentIntent.status });
|
|
882
892
|
return;
|
|
883
893
|
}
|
|
884
894
|
|
|
885
|
-
const paymentMethod = await PaymentMethod
|
|
895
|
+
const paymentMethod = await systemFindByPk(PaymentMethod, paymentIntent.payment_method_id);
|
|
886
896
|
if (!paymentMethod) {
|
|
887
897
|
logger.warn('PaymentMethod not found', { id: paymentIntent.payment_method_id });
|
|
888
898
|
return;
|
|
889
899
|
}
|
|
900
|
+
assertJobObjectTenant(paymentMethod);
|
|
890
901
|
|
|
891
902
|
const supportAutoCharge = await PaymentMethod.supportAutoCharge(paymentIntent.payment_method_id);
|
|
892
903
|
if (supportAutoCharge === false) {
|
|
@@ -894,26 +905,28 @@ export const handlePayment = async (job: PaymentJob) => {
|
|
|
894
905
|
return;
|
|
895
906
|
}
|
|
896
907
|
|
|
897
|
-
const paymentCurrency = await PaymentCurrency
|
|
908
|
+
const paymentCurrency = await systemFindByPk(PaymentCurrency, paymentIntent.currency_id);
|
|
898
909
|
if (!paymentCurrency) {
|
|
899
910
|
logger.warn('PaymentCurrency not found', { id: paymentIntent.currency_id });
|
|
900
911
|
return;
|
|
901
912
|
}
|
|
913
|
+
assertJobObjectTenant(paymentCurrency);
|
|
902
914
|
|
|
903
915
|
if (paymentCurrency.isCredit()) {
|
|
904
916
|
logger.info('PaymentIntent capture skipped because paymentCurrency is credit', { id: paymentIntent.id });
|
|
905
917
|
return;
|
|
906
918
|
}
|
|
907
919
|
|
|
908
|
-
const customer = await Customer
|
|
920
|
+
const customer = await systemFindByPk(Customer, paymentIntent.customer_id);
|
|
909
921
|
if (!customer) {
|
|
910
922
|
logger.warn('Customer not found', { id: paymentIntent.customer_id });
|
|
911
923
|
return;
|
|
912
924
|
}
|
|
925
|
+
assertJobObjectTenant(customer);
|
|
913
926
|
|
|
914
|
-
const invoice = await Invoice
|
|
927
|
+
const invoice = await systemFindByPk(Invoice, paymentIntent.invoice_id);
|
|
915
928
|
// Fetch subscription early for migration fallback support and overdraft protection check
|
|
916
|
-
const subscription = invoice?.subscription_id ? await Subscription
|
|
929
|
+
const subscription = invoice?.subscription_id ? await systemFindByPk(Subscription, invoice.subscription_id) : null;
|
|
917
930
|
|
|
918
931
|
if (invoice?.status === 'void') {
|
|
919
932
|
await paymentIntent.update({
|
|
@@ -1359,7 +1372,7 @@ export const paymentQueue = createQueue<PaymentJob>({
|
|
|
1359
1372
|
});
|
|
1360
1373
|
|
|
1361
1374
|
export const startPaymentQueue = async () => {
|
|
1362
|
-
const payments = await PaymentIntent
|
|
1375
|
+
const payments = await systemFindAll(PaymentIntent, {
|
|
1363
1376
|
where: {
|
|
1364
1377
|
status: ['requires_capture', 'processing'],
|
|
1365
1378
|
capture_method: 'automatic',
|
|
@@ -1384,7 +1397,7 @@ paymentQueue.on('failed', ({ id, job, error }) => {
|
|
|
1384
1397
|
|
|
1385
1398
|
// Do gas stake as soon as possible after payment succeed
|
|
1386
1399
|
events.on('payment_intent.succeeded', async (paymentIntent: PaymentIntent) => {
|
|
1387
|
-
const paymentMethod = await PaymentMethod
|
|
1400
|
+
const paymentMethod = await systemFindByPk(PaymentMethod, paymentIntent.payment_method_id);
|
|
1388
1401
|
if (paymentMethod && paymentMethod.type === 'arcblock') {
|
|
1389
1402
|
ensureStakedForGas();
|
|
1390
1403
|
}
|
package/api/src/queues/payout.ts
CHANGED
|
@@ -2,7 +2,7 @@ import dayjs from '../libs/dayjs';
|
|
|
2
2
|
import { events } from '../libs/event';
|
|
3
3
|
import logger from '../libs/logger';
|
|
4
4
|
import { getGasPayerExtra } from '../libs/payment';
|
|
5
|
-
import createQueue from '../libs/queue';
|
|
5
|
+
import createQueue, { assertJobObjectTenant } from '../libs/queue';
|
|
6
6
|
import { wallet, ethWallet } from '../libs/auth';
|
|
7
7
|
import { sendErc20ToUser } from '../integrations/ethereum/token';
|
|
8
8
|
import { PaymentMethod } from '../store/models/payment-method';
|
|
@@ -11,6 +11,7 @@ import { Payout } from '../store/models/payout';
|
|
|
11
11
|
import { EVM_CHAIN_TYPES } from '../libs/constants';
|
|
12
12
|
import type { PaymentError } from '../store/models/types';
|
|
13
13
|
import { getNextRetry, MAX_RETRY_COUNT } from '../libs/util';
|
|
14
|
+
import { systemFindAll, systemFindByPk } from '../store/scoped';
|
|
14
15
|
|
|
15
16
|
type PayoutJob = {
|
|
16
17
|
payoutId: string;
|
|
@@ -23,28 +24,31 @@ type ValidationResult =
|
|
|
23
24
|
|
|
24
25
|
// Validate payout and fetch required data
|
|
25
26
|
async function validatePayoutAndFetchData(job: PayoutJob): Promise<ValidationResult> {
|
|
26
|
-
const payout = await Payout
|
|
27
|
+
const payout = await systemFindByPk(Payout, job.payoutId);
|
|
27
28
|
if (!payout) {
|
|
28
29
|
logger.warn('Payout not found', { id: job.payoutId });
|
|
29
30
|
return { valid: false };
|
|
30
31
|
}
|
|
32
|
+
assertJobObjectTenant(payout);
|
|
31
33
|
|
|
32
34
|
if (payout.status !== 'pending') {
|
|
33
35
|
logger.warn('Payout status not expected', { id: payout.id, status: payout.status });
|
|
34
36
|
return { valid: false };
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
const paymentMethod = await PaymentMethod
|
|
39
|
+
const paymentMethod = await systemFindByPk(PaymentMethod, payout.payment_method_id);
|
|
38
40
|
if (!paymentMethod) {
|
|
39
41
|
logger.warn('PaymentMethod not found', { id: payout.payment_method_id });
|
|
40
42
|
return { valid: false };
|
|
41
43
|
}
|
|
44
|
+
assertJobObjectTenant(paymentMethod);
|
|
42
45
|
|
|
43
|
-
const paymentCurrency = await PaymentCurrency
|
|
46
|
+
const paymentCurrency = await systemFindByPk(PaymentCurrency, payout.currency_id);
|
|
44
47
|
if (!paymentCurrency) {
|
|
45
48
|
logger.warn('PaymentCurrency not found', { id: payout.currency_id });
|
|
46
49
|
return { valid: false };
|
|
47
50
|
}
|
|
51
|
+
assertJobObjectTenant(paymentCurrency);
|
|
48
52
|
|
|
49
53
|
return {
|
|
50
54
|
valid: true,
|
|
@@ -234,7 +238,7 @@ payoutQueue.on('failed', ({ id, job, error }) => {
|
|
|
234
238
|
|
|
235
239
|
// Start queue, find all payouts with "pending" status
|
|
236
240
|
export const startPayoutQueue = async () => {
|
|
237
|
-
const payouts = await Payout
|
|
241
|
+
const payouts = await systemFindAll(Payout, {
|
|
238
242
|
where: {
|
|
239
243
|
status: 'pending',
|
|
240
244
|
},
|
package/api/src/queues/refund.ts
CHANGED
|
@@ -7,7 +7,7 @@ import CustomError, { NonRetryableError } from '../libs/error';
|
|
|
7
7
|
import { events } from '../libs/event';
|
|
8
8
|
import logger from '../libs/logger';
|
|
9
9
|
import { getGasPayerExtra, isBalanceSufficientForRefund } from '../libs/payment';
|
|
10
|
-
import createQueue from '../libs/queue';
|
|
10
|
+
import createQueue, { assertJobObjectTenant } from '../libs/queue';
|
|
11
11
|
import { MAX_RETRY_COUNT, getNextRetry } from '../libs/util';
|
|
12
12
|
import { Customer } from '../store/models/customer';
|
|
13
13
|
import { PaymentCurrency } from '../store/models/payment-currency';
|
|
@@ -20,6 +20,7 @@ import { Invoice } from '../store/models/invoice';
|
|
|
20
20
|
import { burnToken, getAccountState } from '../integrations/arcblock/token';
|
|
21
21
|
import type { EVMChainType, PaymentError } from '../store/models/types';
|
|
22
22
|
import { EVM_CHAIN_TYPES } from '../libs/constants';
|
|
23
|
+
import { systemFindAll, systemFindByPk } from '../store/scoped';
|
|
23
24
|
|
|
24
25
|
type RefundJob = {
|
|
25
26
|
refundId: string;
|
|
@@ -83,11 +84,12 @@ export const handleRefundFailed = (refund: Refund, error: PaymentError) => {
|
|
|
83
84
|
export const handleRefund = async (job: RefundJob) => {
|
|
84
85
|
logger.info('handle refund', job);
|
|
85
86
|
|
|
86
|
-
const refund = await Refund
|
|
87
|
+
const refund = await systemFindByPk(Refund, job.refundId);
|
|
87
88
|
if (!refund) {
|
|
88
89
|
logger.warn(`refund not found: ${job.refundId}`);
|
|
89
90
|
return;
|
|
90
91
|
}
|
|
92
|
+
assertJobObjectTenant(refund);
|
|
91
93
|
|
|
92
94
|
if (['pending'].includes(refund.status) === false) {
|
|
93
95
|
logger.warn(`refund status not expected: ${refund.status}`);
|
|
@@ -106,25 +108,28 @@ export const handleRefund = async (job: RefundJob) => {
|
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
const paymentCurrency = await PaymentCurrency
|
|
111
|
+
const paymentCurrency = await systemFindByPk(PaymentCurrency, refund.currency_id);
|
|
110
112
|
if (!paymentCurrency) {
|
|
111
113
|
logger.warn(`PaymentCurrency not found: ${refund.currency_id}`);
|
|
112
114
|
await markRefundNonRetryable(refund, 'CURRENCY_NOT_FOUND', 'Payment currency not found');
|
|
113
115
|
return;
|
|
114
116
|
}
|
|
115
|
-
|
|
117
|
+
assertJobObjectTenant(paymentCurrency);
|
|
118
|
+
const paymentMethod = await systemFindByPk(PaymentMethod, paymentCurrency.payment_method_id);
|
|
116
119
|
if (!paymentMethod) {
|
|
117
120
|
logger.warn(`PaymentMethod not found: ${paymentCurrency.payment_method_id}`);
|
|
118
121
|
await markRefundNonRetryable(refund, 'PAYMENT_METHOD_NOT_FOUND', 'Payment method not found');
|
|
119
122
|
return;
|
|
120
123
|
}
|
|
124
|
+
assertJobObjectTenant(paymentMethod);
|
|
121
125
|
|
|
122
|
-
const customer = await Customer
|
|
126
|
+
const customer = await systemFindByPk(Customer, refund.customer_id);
|
|
123
127
|
if (!customer) {
|
|
124
128
|
logger.warn(`Customer not found: ${refund.customer_id}`);
|
|
125
129
|
await markRefundNonRetryable(refund, 'CUSTOMER_NOT_FOUND', 'Customer not found', paymentMethod);
|
|
126
130
|
return;
|
|
127
131
|
}
|
|
132
|
+
assertJobObjectTenant(customer);
|
|
128
133
|
|
|
129
134
|
if (refund?.type === 'stake_return') {
|
|
130
135
|
await handleStakeReturnJob(job, refund, paymentCurrency, paymentMethod, customer);
|
|
@@ -197,10 +202,11 @@ const handleRefundJob = async (
|
|
|
197
202
|
if (!refund.payment_intent_id) {
|
|
198
203
|
throw new NonRetryableError('PAYMENT_INTENT_NOT_FOUND', 'payment_intent_id is missing for refund');
|
|
199
204
|
}
|
|
200
|
-
const paymentIntent = await PaymentIntent
|
|
205
|
+
const paymentIntent = await systemFindByPk(PaymentIntent, refund.payment_intent_id);
|
|
201
206
|
if (!paymentIntent) {
|
|
202
207
|
throw new NonRetryableError('PAYMENT_INTENT_NOT_FOUND', 'PaymentIntent not found');
|
|
203
208
|
}
|
|
209
|
+
assertJobObjectTenant(paymentIntent);
|
|
204
210
|
let result;
|
|
205
211
|
if (paymentMethod.type === 'arcblock') {
|
|
206
212
|
const client = paymentMethod.getOcapClient();
|
|
@@ -378,7 +384,7 @@ const handleStakeReturnJob = async (
|
|
|
378
384
|
return;
|
|
379
385
|
}
|
|
380
386
|
const client = paymentMethod.getOcapClient();
|
|
381
|
-
const subscription = await Subscription
|
|
387
|
+
const subscription = await systemFindByPk(Subscription, refund.subscription_id);
|
|
382
388
|
const address =
|
|
383
389
|
arcblockDetail?.staking?.address ||
|
|
384
390
|
(await getSubscriptionStakeAddress(subscription!, customer.did, paymentMethod));
|
|
@@ -486,7 +492,7 @@ export const refundQueue = createQueue<RefundJob>({
|
|
|
486
492
|
});
|
|
487
493
|
|
|
488
494
|
export const startRefundQueue = async () => {
|
|
489
|
-
const refunds = await Refund
|
|
495
|
+
const refunds = await systemFindAll(Refund, { where: { status: ['pending'] } });
|
|
490
496
|
refunds.forEach(async (x) => {
|
|
491
497
|
const exist = await refundQueue.get(x.id);
|
|
492
498
|
if (!exist) {
|
|
@@ -528,8 +534,8 @@ export async function handleCreditRefund(refund: Refund): Promise<string | undef
|
|
|
528
534
|
return undefined;
|
|
529
535
|
}
|
|
530
536
|
|
|
531
|
-
const invoice = await Invoice
|
|
532
|
-
const customer = await Customer
|
|
537
|
+
const invoice = await systemFindByPk(Invoice, refund.invoice_id);
|
|
538
|
+
const customer = await systemFindByPk(Customer, refund.customer_id);
|
|
533
539
|
|
|
534
540
|
if (!invoice || !customer?.did) {
|
|
535
541
|
throw new Error('Invoice or customer not found for refund');
|
|
@@ -541,7 +547,7 @@ export async function handleCreditRefund(refund: Refund): Promise<string | undef
|
|
|
541
547
|
}
|
|
542
548
|
|
|
543
549
|
// Find ALL credit grants related to this invoice (both on-chain and off-chain).
|
|
544
|
-
const allGrants = await CreditGrant
|
|
550
|
+
const allGrants = await systemFindAll(CreditGrant, {
|
|
545
551
|
where: {
|
|
546
552
|
customer_id: refund.customer_id,
|
|
547
553
|
status: ['pending', 'granted'],
|
|
@@ -570,7 +576,7 @@ export async function handleCreditRefund(refund: Refund): Promise<string | undef
|
|
|
570
576
|
for (const creditGrant of creditGrants) {
|
|
571
577
|
// Get the currency for THIS grant
|
|
572
578
|
// eslint-disable-next-line no-await-in-loop
|
|
573
|
-
const grantCurrency = await PaymentCurrency
|
|
579
|
+
const grantCurrency = await systemFindByPk(PaymentCurrency, creditGrant.currency_id);
|
|
574
580
|
|
|
575
581
|
if (!grantCurrency) {
|
|
576
582
|
logger.error('Payment currency not found for credit grant refund', {
|