payment-kit 1.29.1 → 1.29.3
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 +47 -0
- package/api/src/crons/base.ts +3 -3
- package/api/src/crons/currency.ts +1 -1
- package/api/src/crons/index.ts +41 -37
- 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/crons/tenant-fanout.ts +82 -0
- package/api/src/host-node/did-connect-runtime-node.ts +33 -0
- package/api/src/host-node/serve-static-arc.ts +68 -0
- package/api/src/host-node/serve-static.ts +41 -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 +247 -47
- package/api/src/libs/context.ts +89 -1
- package/api/src/libs/currency.ts +2 -2
- package/api/src/libs/dayjs.ts +8 -2
- package/api/src/libs/did-connect/runtime-did-connect-js.ts +88 -0
- package/api/src/libs/did-connect/tenant-identity.ts +221 -0
- 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 +142 -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 +60 -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 +271 -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 +80 -0
- package/api/src/middlewares/hono/csrf.ts +83 -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 +209 -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 +38 -21
- 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 +41 -11
- 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 +64 -37
- package/api/src/queues/payout.ts +37 -21
- package/api/src/queues/refund.ts +36 -18
- 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} +199 -224
- 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} +98 -83
- 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 +814 -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 +82 -23
- 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/bootstrap/bootstrap.spec.ts +162 -0
- package/api/tests/crons/tenant-fanout.spec.ts +158 -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/did-connect-runtime-js.spec.ts +98 -0
- package/api/tests/libs/did-connect-tenant-identity.spec.ts +159 -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/service-host.spec.ts +37 -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 +292 -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/service/didconnect-storage-slot.spec.ts +60 -0
- package/api/tests/service/fail-closed-http.spec.ts +79 -0
- package/api/tests/service/static-arc-handler.spec.ts +101 -0
- package/api/tests/service/static-externalized.spec.ts +48 -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/MIGRATION-RUNBOOK.md +3 -8
- package/cloudflare/README.md +34 -27
- package/cloudflare/STAGING-MIGRATION-GUIDE.md +3 -15
- package/cloudflare/build.ts +33 -13
- package/cloudflare/cf-adapter.ts +419 -0
- package/cloudflare/did-connect-runtime.ts +96 -0
- package/cloudflare/did-connect-token-storage.ts +151 -0
- package/cloudflare/esbuild-cf-config.cjs +407 -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 +33 -403
- package/cloudflare/scripts/cf-package-import-probe.mjs +90 -0
- package/cloudflare/scripts/didconnect-mock-smoke.mjs +140 -0
- 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/wallet-authenticator.ts +16 -1
- package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +18 -3
- 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/cf-adapter.spec.ts +244 -0
- package/cloudflare/tests/did-connect-token-storage.spec.ts +105 -0
- package/cloudflare/tests/tenant-middleware.spec.ts +160 -0
- package/cloudflare/tests/worker-handler-gate.spec.ts +69 -0
- package/cloudflare/vite.config.ts +53 -45
- package/cloudflare/worker.ts +261 -448
- package/cloudflare/wrangler.json +0 -6
- package/cloudflare/wrangler.jsonc +0 -6
- package/cloudflare/wrangler.local-e2e.jsonc +25 -0
- package/cloudflare/wrangler.staging.json +0 -6
- package/jest.config.js +3 -1
- package/package.json +33 -38
- package/scripts/bootstrap-inject.ts +166 -0
- 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/app.tsx +2 -1
- package/src/env.d.ts +13 -1
- package/src/libs/service-host.ts +13 -0
- package/tsconfig.json +1 -1
- package/vite.arc.config.ts +159 -0
- 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/did-connect-auth.ts +0 -527
- 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,19 +1,26 @@
|
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of routes/donations.ts. Sub-app with
|
|
2
|
+
// routes relative to /api/donations (mounted via mountResourceGroup). The
|
|
3
|
+
// business logic is unchanged; only the express plumbing becomes hono:
|
|
4
|
+
// req.body → c.get('sanitizedBody'); res.status(n).json(x) → c.json(x, n).
|
|
1
5
|
import Joi from 'joi';
|
|
2
|
-
import {
|
|
6
|
+
import { Hono } from 'hono';
|
|
3
7
|
|
|
4
8
|
import { BN } from '@ocap/util';
|
|
5
|
-
import { createListParamSchema, getOrder } from '
|
|
6
|
-
import logger from '
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
9
|
+
import { createListParamSchema, getOrder } from '../../libs/api';
|
|
10
|
+
import logger from '../../libs/logger';
|
|
11
|
+
import { authenticate } from '../../middlewares/hono/security';
|
|
12
|
+
import { CheckoutSession } from '../../store/models/checkout-session';
|
|
13
|
+
import { Customer } from '../../store/models/customer';
|
|
14
|
+
import { PaymentLink } from '../../store/models/payment-link';
|
|
15
|
+
import { PaymentMethod } from '../../store/models/payment-method';
|
|
16
|
+
import { Price } from '../../store/models/price';
|
|
17
|
+
import type { DonationSettings } from '../../store/models/types';
|
|
13
18
|
import { createPaymentLink } from './payment-links';
|
|
14
19
|
import { createProductAndPrices } from './products';
|
|
15
20
|
|
|
16
|
-
const
|
|
21
|
+
const app = new Hono();
|
|
22
|
+
|
|
23
|
+
const auth = authenticate({ component: true, roles: ['owner', 'admin'] });
|
|
17
24
|
|
|
18
25
|
// FIXME: add more custom validation here for amount
|
|
19
26
|
const donationSchema = Joi.object<DonationSettings>({
|
|
@@ -44,12 +51,14 @@ const donationSchema = Joi.object<DonationSettings>({
|
|
|
44
51
|
summary: Joi.string().optional(),
|
|
45
52
|
}),
|
|
46
53
|
});
|
|
54
|
+
|
|
47
55
|
// prepare donation payment links
|
|
48
|
-
|
|
56
|
+
app.post('/', auth, async (c) => {
|
|
49
57
|
try {
|
|
50
|
-
const
|
|
58
|
+
const body = c.get('sanitizedBody') ?? {};
|
|
59
|
+
const payload = await donationSchema.validateAsync(body, { stripUnknown: true, convert: true });
|
|
51
60
|
const link = await PaymentLink.findOne({
|
|
52
|
-
where: { 'donation_settings.target': payload.target, livemode: !!
|
|
61
|
+
where: { 'donation_settings.target': payload.target, livemode: !!c.get('livemode') },
|
|
53
62
|
});
|
|
54
63
|
if (link) {
|
|
55
64
|
await link.update({
|
|
@@ -64,21 +73,20 @@ router.post('/', async (req, res) => {
|
|
|
64
73
|
},
|
|
65
74
|
});
|
|
66
75
|
logger.info('Payment link updated successfully', { linkId: link.id });
|
|
67
|
-
|
|
68
|
-
return;
|
|
76
|
+
return c.json(link.toJSON());
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
logger.info('No existing payment link found, creating new one');
|
|
72
|
-
const lookupKey = `${payload.target}-${
|
|
80
|
+
const lookupKey = `${payload.target}-${c.get('livemode') ? 'live' : 'test'}`;
|
|
73
81
|
let price = await Price.findByPkOrLookupKey(lookupKey);
|
|
74
82
|
if (!price) {
|
|
75
83
|
logger.info('No existing price found, creating new product and price');
|
|
76
84
|
const result = await createProductAndPrices({
|
|
77
85
|
type: 'service',
|
|
78
|
-
livemode: !!
|
|
86
|
+
livemode: !!c.get('livemode'),
|
|
79
87
|
name: payload.title,
|
|
80
88
|
description: payload.description,
|
|
81
|
-
currency_id:
|
|
89
|
+
currency_id: c.get('baseCurrency').id,
|
|
82
90
|
via: 'donation',
|
|
83
91
|
prices: [
|
|
84
92
|
{
|
|
@@ -101,9 +109,9 @@ router.post('/', async (req, res) => {
|
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
const result = await createPaymentLink({
|
|
104
|
-
livemode: !!
|
|
105
|
-
created_via:
|
|
106
|
-
currency_id:
|
|
112
|
+
livemode: !!c.get('livemode'),
|
|
113
|
+
created_via: c.get('user')?.via,
|
|
114
|
+
currency_id: c.get('baseCurrency').id,
|
|
107
115
|
name: payload.title,
|
|
108
116
|
submit_type: 'donate',
|
|
109
117
|
line_items: [{ price_id: price.id, quantity: 1 }],
|
|
@@ -116,23 +124,24 @@ router.post('/', async (req, res) => {
|
|
|
116
124
|
},
|
|
117
125
|
});
|
|
118
126
|
logger.info('New payment link created', { linkId: result.id });
|
|
119
|
-
|
|
127
|
+
return c.json(result);
|
|
120
128
|
} catch (err) {
|
|
121
129
|
logger.error('Failed to prepare payment link for donation', err);
|
|
122
|
-
|
|
130
|
+
return c.json({ error: (err as any).message }, 400);
|
|
123
131
|
}
|
|
124
132
|
});
|
|
125
133
|
|
|
126
134
|
// get donations by target
|
|
127
135
|
const paginationSchema = createListParamSchema<{ target: string }>({ target: Joi.string().required() }, 20);
|
|
128
|
-
|
|
136
|
+
app.get('/', auth, async (c) => {
|
|
129
137
|
try {
|
|
130
|
-
const
|
|
138
|
+
const query = c.req.query();
|
|
139
|
+
const { page, pageSize, target } = await paginationSchema.validateAsync(query, {
|
|
131
140
|
convert: true,
|
|
132
141
|
stripUnknown: true,
|
|
133
142
|
});
|
|
134
143
|
const { rows, count } = await CheckoutSession.findAndCountAll({
|
|
135
|
-
where: { payment_link_id: target, status: 'complete', livemode:
|
|
144
|
+
where: { payment_link_id: target, status: 'complete', livemode: c.get('livemode') },
|
|
136
145
|
attributes: [
|
|
137
146
|
'id',
|
|
138
147
|
'customer_id',
|
|
@@ -143,30 +152,30 @@ router.get('/', async (req, res) => {
|
|
|
143
152
|
'created_at',
|
|
144
153
|
'updated_at',
|
|
145
154
|
],
|
|
146
|
-
order: getOrder(
|
|
155
|
+
order: getOrder(query, [['created_at', 'DESC']]),
|
|
147
156
|
offset: (page - 1) * pageSize,
|
|
148
157
|
include: [{ model: Customer, as: 'customer', attributes: ['id', 'did', 'name', 'metadata'] }],
|
|
149
158
|
limit: pageSize,
|
|
150
159
|
});
|
|
151
160
|
|
|
152
|
-
const method = await PaymentMethod.findByPk(
|
|
161
|
+
const method = await PaymentMethod.findByPk(c.get('baseCurrency').payment_method_id);
|
|
153
162
|
|
|
154
163
|
const totalAmount: string = rows
|
|
155
164
|
.map((x) => x.toJSON())
|
|
156
165
|
.reduce((total, x) => total.add(new BN(x.amount_total)), new BN('0'))
|
|
157
166
|
.toString();
|
|
158
167
|
|
|
159
|
-
|
|
168
|
+
return c.json({
|
|
160
169
|
supporters: rows,
|
|
161
|
-
currency:
|
|
170
|
+
currency: c.get('baseCurrency'),
|
|
162
171
|
method,
|
|
163
172
|
total: count,
|
|
164
173
|
totalAmount,
|
|
165
174
|
paging: { page, pageSize },
|
|
166
175
|
});
|
|
167
176
|
} catch (err) {
|
|
168
|
-
|
|
177
|
+
return c.json({ error: (err as any).message, supporters: [] }, 400);
|
|
169
178
|
}
|
|
170
179
|
});
|
|
171
180
|
|
|
172
|
-
export default
|
|
181
|
+
export default app;
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of routes/entitlements.ts. Sub-app with
|
|
2
|
+
// routes relative to /api/entitlements (mounted via mountResourceGroup). The
|
|
3
|
+
// business logic is unchanged; only the express plumbing becomes hono:
|
|
4
|
+
// req.body → c.get('sanitizedBody'); res.status(n).json(x) → c.json(x, n).
|
|
5
|
+
//
|
|
1
6
|
// Cross-channel entitlement query API.
|
|
2
7
|
//
|
|
3
8
|
// Endpoints:
|
|
@@ -10,15 +15,15 @@
|
|
|
10
15
|
// - Logged-in end users (mobile demo, web SPA): `mine: true` lets them in iff
|
|
11
16
|
// their DID matches the query's customer_did — enforced in the handler.
|
|
12
17
|
|
|
13
|
-
import {
|
|
18
|
+
import { Hono } from 'hono';
|
|
14
19
|
import Joi from 'joi';
|
|
15
20
|
|
|
16
|
-
import { checkEntitlement, listEntitlements } from '
|
|
17
|
-
import logger from '
|
|
18
|
-
import { authenticate } from '
|
|
19
|
-
import { PaymentMethod } from '
|
|
21
|
+
import { checkEntitlement, listEntitlements } from '../../libs/entitlement';
|
|
22
|
+
import logger from '../../libs/logger';
|
|
23
|
+
import { authenticate } from '../../middlewares/hono/security';
|
|
24
|
+
import { PaymentMethod } from '../../store/models';
|
|
20
25
|
|
|
21
|
-
const
|
|
26
|
+
const app = new Hono();
|
|
22
27
|
// component+owner/admin for cross-blocklet calls; ensureLogin for end users —
|
|
23
28
|
// handler then enforces that non-admin users can only query their own DID.
|
|
24
29
|
const auth = authenticate<PaymentMethod>({ component: true, roles: ['owner', 'admin'], ensureLogin: true });
|
|
@@ -35,8 +40,8 @@ function canonicalDid(did: string | undefined | null): string {
|
|
|
35
40
|
return did.startsWith('did:abt:') ? did.slice('did:abt:'.length) : did;
|
|
36
41
|
}
|
|
37
42
|
|
|
38
|
-
function isSelf(
|
|
39
|
-
const a = canonicalDid(
|
|
43
|
+
function isSelf(userDid: string | undefined, customerDid: string): boolean {
|
|
44
|
+
const a = canonicalDid(userDid);
|
|
40
45
|
const b = canonicalDid(customerDid);
|
|
41
46
|
return !!a && a === b;
|
|
42
47
|
}
|
|
@@ -66,40 +71,38 @@ function parseLivemode(value: string | boolean | undefined, fallback: boolean):
|
|
|
66
71
|
return fallback;
|
|
67
72
|
}
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
app.get('/check', auth, async (c) => {
|
|
70
75
|
try {
|
|
71
|
-
const input = await checkQuerySchema.validateAsync(req.query, { stripUnknown: true });
|
|
72
|
-
if (!isAdminUser((
|
|
73
|
-
|
|
74
|
-
return;
|
|
76
|
+
const input = await checkQuerySchema.validateAsync(c.req.query(), { stripUnknown: true });
|
|
77
|
+
if (!isAdminUser(c.get('user')?.role) && !isSelf(c.get('user')?.did, input.customer_did)) {
|
|
78
|
+
return c.json({ error: 'Cannot query entitlements for other customers' }, 403);
|
|
75
79
|
}
|
|
76
|
-
const livemode = parseLivemode(input.livemode, !!
|
|
80
|
+
const livemode = parseLivemode(input.livemode, !!c.get('livemode'));
|
|
77
81
|
const result = await checkEntitlement({
|
|
78
82
|
customer_did: input.customer_did,
|
|
79
83
|
product_id: input.product_id,
|
|
80
84
|
livemode,
|
|
81
85
|
});
|
|
82
|
-
|
|
86
|
+
return c.json(result);
|
|
83
87
|
} catch (err: any) {
|
|
84
88
|
logger.error('entitlements/check failed', { error: err?.message, stack: err?.stack });
|
|
85
|
-
|
|
89
|
+
return c.json({ error: err?.message ?? 'check failed' }, 400);
|
|
86
90
|
}
|
|
87
91
|
});
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
app.get('/list', auth, async (c) => {
|
|
90
94
|
try {
|
|
91
|
-
const input = await listQuerySchema.validateAsync(req.query, { stripUnknown: true });
|
|
92
|
-
if (!isAdminUser((
|
|
93
|
-
|
|
94
|
-
return;
|
|
95
|
+
const input = await listQuerySchema.validateAsync(c.req.query(), { stripUnknown: true });
|
|
96
|
+
if (!isAdminUser(c.get('user')?.role) && !isSelf(c.get('user')?.did, input.customer_did)) {
|
|
97
|
+
return c.json({ error: 'Cannot list entitlements for other customers' }, 403);
|
|
95
98
|
}
|
|
96
|
-
const livemode = parseLivemode(input.livemode, !!
|
|
99
|
+
const livemode = parseLivemode(input.livemode, !!c.get('livemode'));
|
|
97
100
|
const list = await listEntitlements({ customer_did: input.customer_did, livemode });
|
|
98
|
-
|
|
101
|
+
return c.json({ list });
|
|
99
102
|
} catch (err: any) {
|
|
100
103
|
logger.error('entitlements/list failed', { error: err?.message, stack: err?.stack });
|
|
101
|
-
|
|
104
|
+
return c.json({ error: err?.message ?? 'list failed' }, 400);
|
|
102
105
|
}
|
|
103
106
|
});
|
|
104
107
|
|
|
105
|
-
export default
|
|
108
|
+
export default app;
|
|
@@ -1,20 +1,42 @@
|
|
|
1
|
-
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of routes/events.ts. Sub-app with
|
|
2
|
+
// routes relative to /api/events (mounted via mountResourceGroup). The
|
|
3
|
+
// business logic is unchanged; only the express plumbing becomes hono:
|
|
4
|
+
// req.body → c.get('sanitizedBody'); res.status(n).json(x) → c.json(x, n).
|
|
5
|
+
import { Hono } from 'hono';
|
|
2
6
|
import Joi from 'joi';
|
|
3
7
|
import type { WhereOptions } from 'sequelize';
|
|
4
8
|
import { Op } from 'sequelize';
|
|
5
9
|
|
|
6
|
-
import { createListParamSchema, getOrder } from '
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
import { createListParamSchema, getOrder } from '../../libs/api';
|
|
11
|
+
import { context } from '../../libs/context';
|
|
12
|
+
import { authenticate } from '../../middlewares/hono/security';
|
|
13
|
+
import { TENANT_MISMATCH, TenantError, resolveRowTenant } from '../../libs/tenant';
|
|
14
|
+
import { Event } from '../../store/models/event';
|
|
15
|
+
import { blocklet } from '../../libs/auth';
|
|
16
|
+
import logger from '../../libs/logger';
|
|
17
|
+
import { addWebhookJob } from '../../queues/webhook';
|
|
18
|
+
import { WebhookEndpoint } from '../../store/models/webhook-endpoint';
|
|
19
|
+
import { Subscription } from '../../store/models/subscription';
|
|
20
|
+
|
|
21
|
+
const app = new Hono();
|
|
16
22
|
const auth = authenticate<Event>({ component: true, roles: ['owner', 'admin'] });
|
|
17
23
|
|
|
24
|
+
// Phase 4 (W1-3): manual retry endpoints are tenant-guarded — the caller's
|
|
25
|
+
// tenant context must match the event's tenant or the request dies with 4xx
|
|
26
|
+
// before any attempt is scheduled. Exported for unit tests.
|
|
27
|
+
export function assertEventTenantAccessible(event: { instance_did?: string | null }): void {
|
|
28
|
+
const callerTenant = context.getInstanceDid(); // throws TENANT_CONTEXT_MISSING in multi mode without context
|
|
29
|
+
const eventTenant = resolveRowTenant(event);
|
|
30
|
+
if (callerTenant !== eventTenant) {
|
|
31
|
+
throw new TenantError(TENANT_MISMATCH, 'event belongs to another tenant');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function tenantErrorStatus(err: any): number | null {
|
|
36
|
+
if (err instanceof TenantError) return err.code === TENANT_MISMATCH ? 403 : 401;
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
18
40
|
const schema = createListParamSchema<{
|
|
19
41
|
type?: string;
|
|
20
42
|
object_id?: string;
|
|
@@ -22,42 +44,6 @@ const schema = createListParamSchema<{
|
|
|
22
44
|
type: Joi.string().empty(''),
|
|
23
45
|
object_id: Joi.string().empty(''),
|
|
24
46
|
});
|
|
25
|
-
router.get('/', auth, async (req, res) => {
|
|
26
|
-
const { page, pageSize, ...query } = await schema.validateAsync(req.query, { stripUnknown: true });
|
|
27
|
-
const where: WhereOptions<Event> = {};
|
|
28
|
-
|
|
29
|
-
if (query.type) {
|
|
30
|
-
where.type = query.type
|
|
31
|
-
.split(',')
|
|
32
|
-
.map((x) => x.trim())
|
|
33
|
-
.filter(Boolean);
|
|
34
|
-
}
|
|
35
|
-
if (query.object_id) {
|
|
36
|
-
where.object_id = query.object_id
|
|
37
|
-
.split(',')
|
|
38
|
-
.map((x) => x.trim())
|
|
39
|
-
.filter(Boolean);
|
|
40
|
-
}
|
|
41
|
-
if (typeof query.livemode === 'boolean') {
|
|
42
|
-
where.livemode = query.livemode;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const { rows: list, count } = await Event.findAndCountAll({
|
|
47
|
-
where,
|
|
48
|
-
attributes: { exclude: ['data', 'request'] },
|
|
49
|
-
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
50
|
-
offset: (page - 1) * pageSize,
|
|
51
|
-
limit: pageSize,
|
|
52
|
-
include: [],
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
res.json({ count, list, paging: { page, pageSize } });
|
|
56
|
-
} catch (err) {
|
|
57
|
-
logger.error(err);
|
|
58
|
-
res.json({ count: 0, list: [], paging: { page, pageSize } });
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
47
|
|
|
62
48
|
const retryWebhooksSchema = createListParamSchema<{
|
|
63
49
|
eventType?: string;
|
|
@@ -77,14 +63,17 @@ const retryWebhooksSchema = createListParamSchema<{
|
|
|
77
63
|
latestOnly: Joi.boolean().optional(),
|
|
78
64
|
});
|
|
79
65
|
|
|
80
|
-
|
|
66
|
+
// static route before /:id
|
|
67
|
+
app.get('/retry-webhooks', auth, async (c) => {
|
|
81
68
|
try {
|
|
82
69
|
const { eventType, objectType, objectId, objectIds, eventIds, subscriptionStatus, latestOnly } =
|
|
83
|
-
await retryWebhooksSchema.validateAsync(req.query, {
|
|
70
|
+
await retryWebhooksSchema.validateAsync(c.req.query(), {
|
|
84
71
|
stripUnknown: true,
|
|
85
72
|
});
|
|
86
73
|
|
|
87
|
-
|
|
74
|
+
// scope the whole batch to the caller's tenant (fail-closed in multi mode)
|
|
75
|
+
const where: WhereOptions<Event> = { livemode: c.get('livemode') };
|
|
76
|
+
(where as any).instance_did = context.getInstanceDid();
|
|
88
77
|
let targetObjectIds: string[] = [];
|
|
89
78
|
|
|
90
79
|
// Handle subscription status filter
|
|
@@ -92,13 +81,13 @@ router.get('/retry-webhooks', auth, async (req, res) => {
|
|
|
92
81
|
const subscriptions = await Subscription.findAll({
|
|
93
82
|
where: {
|
|
94
83
|
status: subscriptionStatus,
|
|
95
|
-
livemode:
|
|
84
|
+
livemode: c.get('livemode'),
|
|
96
85
|
},
|
|
97
86
|
attributes: ['id'],
|
|
98
87
|
});
|
|
99
88
|
|
|
100
89
|
if (subscriptions.length === 0) {
|
|
101
|
-
return
|
|
90
|
+
return c.json({
|
|
102
91
|
message: `No subscriptions found with status: ${subscriptionStatus}`,
|
|
103
92
|
scheduled: 0,
|
|
104
93
|
eventsProcessed: 0,
|
|
@@ -147,7 +136,7 @@ router.get('/retry-webhooks', auth, async (req, res) => {
|
|
|
147
136
|
});
|
|
148
137
|
|
|
149
138
|
if (events.length === 0) {
|
|
150
|
-
return
|
|
139
|
+
return c.json({
|
|
151
140
|
message: 'No events found matching the criteria',
|
|
152
141
|
scheduled: 0,
|
|
153
142
|
eventsProcessed: 0,
|
|
@@ -167,11 +156,11 @@ router.get('/retry-webhooks', auth, async (req, res) => {
|
|
|
167
156
|
}
|
|
168
157
|
|
|
169
158
|
const webhooks = await WebhookEndpoint.findAll({
|
|
170
|
-
where: { status: 'enabled', livemode:
|
|
159
|
+
where: { status: 'enabled', livemode: c.get('livemode'), instance_did: context.getInstanceDid() },
|
|
171
160
|
});
|
|
172
161
|
|
|
173
162
|
if (webhooks.length === 0) {
|
|
174
|
-
return
|
|
163
|
+
return c.json({
|
|
175
164
|
message: 'No enabled webhook endpoints found',
|
|
176
165
|
scheduled: 0,
|
|
177
166
|
eventsProcessed: events.length,
|
|
@@ -199,21 +188,62 @@ router.get('/retry-webhooks', auth, async (req, res) => {
|
|
|
199
188
|
criteria: { eventType, objectType, objectId, subscriptionStatus, latestOnly },
|
|
200
189
|
});
|
|
201
190
|
|
|
202
|
-
return
|
|
191
|
+
return c.json({
|
|
203
192
|
message: `Successfully scheduled ${scheduled} webhooks for retry across ${events.length} events`,
|
|
204
193
|
scheduled,
|
|
205
194
|
eventsProcessed: events.length,
|
|
206
195
|
});
|
|
207
196
|
} catch (err: any) {
|
|
197
|
+
const status = tenantErrorStatus(err);
|
|
198
|
+
if (status) {
|
|
199
|
+
return c.json({ error: err.message, code: err.code }, status as any);
|
|
200
|
+
}
|
|
208
201
|
logger.error('Failed to batch retry webhooks', err);
|
|
209
|
-
return
|
|
202
|
+
return c.json({ error: `Failed to retry webhooks: ${err.message}` }, 500);
|
|
210
203
|
}
|
|
211
204
|
});
|
|
212
205
|
|
|
213
|
-
|
|
206
|
+
app.get('/', auth, async (c) => {
|
|
207
|
+
const { page, pageSize, ...query } = await schema.validateAsync(c.req.query(), { stripUnknown: true });
|
|
208
|
+
const where: WhereOptions<Event> = {};
|
|
209
|
+
|
|
210
|
+
if (query.type) {
|
|
211
|
+
where.type = query.type
|
|
212
|
+
.split(',')
|
|
213
|
+
.map((x) => x.trim())
|
|
214
|
+
.filter(Boolean);
|
|
215
|
+
}
|
|
216
|
+
if (query.object_id) {
|
|
217
|
+
where.object_id = query.object_id
|
|
218
|
+
.split(',')
|
|
219
|
+
.map((x) => x.trim())
|
|
220
|
+
.filter(Boolean);
|
|
221
|
+
}
|
|
222
|
+
if (typeof query.livemode === 'boolean') {
|
|
223
|
+
where.livemode = query.livemode;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const { rows: list, count } = await Event.findAndCountAll({
|
|
228
|
+
where,
|
|
229
|
+
attributes: { exclude: ['data', 'request'] },
|
|
230
|
+
order: getOrder(c.req.query(), [['created_at', 'DESC']]),
|
|
231
|
+
offset: (page - 1) * pageSize,
|
|
232
|
+
limit: pageSize,
|
|
233
|
+
include: [],
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
return c.json({ count, list, paging: { page, pageSize } });
|
|
237
|
+
} catch (err) {
|
|
238
|
+
logger.error(err);
|
|
239
|
+
return c.json({ count: 0, list: [], paging: { page, pageSize } });
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
app.get('/:id', auth, async (c) => {
|
|
214
244
|
try {
|
|
215
245
|
const doc = await Event.findOne({
|
|
216
|
-
where: { id: req.
|
|
246
|
+
where: { id: c.req.param('id') },
|
|
217
247
|
include: [],
|
|
218
248
|
});
|
|
219
249
|
|
|
@@ -221,34 +251,36 @@ router.get('/:id', auth, async (req, res) => {
|
|
|
221
251
|
const requestedBy = doc.request?.requested_by || 'system';
|
|
222
252
|
const { user } = await blocklet.getUser(requestedBy as string);
|
|
223
253
|
if (user) {
|
|
224
|
-
return
|
|
254
|
+
return c.json({ ...doc.toJSON(), requestInfo: user });
|
|
225
255
|
}
|
|
226
|
-
return
|
|
256
|
+
return c.json(doc);
|
|
227
257
|
}
|
|
228
|
-
return
|
|
258
|
+
return c.json(null, 404);
|
|
229
259
|
} catch (err) {
|
|
230
260
|
logger.error(err);
|
|
231
|
-
return
|
|
261
|
+
return c.json({ error: `Failed to get event: ${(err as any).message}` }, 400);
|
|
232
262
|
}
|
|
233
263
|
});
|
|
234
264
|
|
|
235
|
-
|
|
265
|
+
app.post('/:id/retry-webhooks', auth, async (c) => {
|
|
236
266
|
try {
|
|
237
267
|
const event = await Event.findOne({
|
|
238
|
-
where: { id: req.
|
|
268
|
+
where: { id: c.req.param('id') },
|
|
239
269
|
});
|
|
240
270
|
|
|
241
271
|
if (!event) {
|
|
242
|
-
return
|
|
272
|
+
return c.json({ error: 'Event not found' }, 404);
|
|
243
273
|
}
|
|
244
274
|
|
|
275
|
+
assertEventTenantAccessible(event);
|
|
276
|
+
|
|
245
277
|
const webhooks = await WebhookEndpoint.findAll({
|
|
246
|
-
where: { status: 'enabled', livemode: event.livemode },
|
|
278
|
+
where: { status: 'enabled', livemode: event.livemode, instance_did: resolveRowTenant(event) },
|
|
247
279
|
});
|
|
248
280
|
const eventWebhooks = webhooks.filter((webhook) => webhook.enabled_events.includes(event.type));
|
|
249
281
|
|
|
250
282
|
if (eventWebhooks.length === 0) {
|
|
251
|
-
return
|
|
283
|
+
return c.json({ message: 'No enabled webhook endpoints found for this event type', scheduled: 0 });
|
|
252
284
|
}
|
|
253
285
|
|
|
254
286
|
let scheduled = 0;
|
|
@@ -262,15 +294,19 @@ router.post('/:id/retry-webhooks', auth, async (req, res) => {
|
|
|
262
294
|
}
|
|
263
295
|
}
|
|
264
296
|
|
|
265
|
-
return
|
|
297
|
+
return c.json({
|
|
266
298
|
message: `Successfully scheduled ${scheduled} webhooks for retry`,
|
|
267
299
|
scheduled,
|
|
268
300
|
total: eventWebhooks.length,
|
|
269
301
|
});
|
|
270
302
|
} catch (err: any) {
|
|
303
|
+
const status = tenantErrorStatus(err);
|
|
304
|
+
if (status) {
|
|
305
|
+
return c.json({ error: err.message, code: err.code }, status as any);
|
|
306
|
+
}
|
|
271
307
|
logger.error('Failed to retry webhooks for event', err);
|
|
272
|
-
return
|
|
308
|
+
return c.json({ error: `Failed to retry webhooks: ${err.message}` }, 500);
|
|
273
309
|
}
|
|
274
310
|
});
|
|
275
311
|
|
|
276
|
-
export default
|
|
312
|
+
export default app;
|