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,18 +1,24 @@
|
|
|
1
|
-
|
|
1
|
+
// Phase 3 (express→hono) — hono fork of routes/meter-events.ts. Sub-app with
|
|
2
|
+
// routes relative to /api/meter-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
|
+
// req.(c.get('customer_id') ?? query.customer_id) → (c.get('customer_id') ?? c.req.query('customer_id')) [SECURITY].
|
|
6
|
+
import { Hono } from 'hono';
|
|
2
7
|
import Joi from 'joi';
|
|
3
8
|
import { Op, QueryTypes, Sequelize } from 'sequelize';
|
|
4
9
|
|
|
5
10
|
import { fromTokenToUnit } from '@ocap/util';
|
|
6
|
-
import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
11
|
+
import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../../libs/api';
|
|
12
|
+
import { getInstanceDid } from '../../libs/context';
|
|
13
|
+
import logger from '../../libs/logger';
|
|
14
|
+
import { authenticate } from '../../middlewares/hono/security';
|
|
15
|
+
import { formatMetadata } from '../../libs/util';
|
|
16
|
+
import { trimDecimals } from '../../libs/math-utils';
|
|
17
|
+
import { Customer, Meter, MeterEvent, MeterEventStatus, PaymentCurrency, Subscription } from '../../store/models';
|
|
12
18
|
|
|
13
|
-
import { getCachedMeter, getCachedCurrency } from '
|
|
19
|
+
import { getCachedMeter, getCachedCurrency } from '../../libs/reference-cache';
|
|
14
20
|
|
|
15
|
-
const
|
|
21
|
+
const app = new Hono();
|
|
16
22
|
const auth = authenticate<MeterEvent>({ component: true, roles: ['owner', 'admin'] });
|
|
17
23
|
const authMine = authenticate<MeterEvent>({ component: true, roles: ['owner', 'admin'], mine: true });
|
|
18
24
|
|
|
@@ -79,9 +85,9 @@ const statsSchema = Joi.object({
|
|
|
79
85
|
granularity: Joi.string().valid('minute', 'hour', 'day').default('day'),
|
|
80
86
|
});
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
app.get('/', authMine, async (c) => {
|
|
83
89
|
try {
|
|
84
|
-
const { page, pageSize, ...query } = await listSchema.validateAsync(req.query, { stripUnknown: true });
|
|
90
|
+
const { page, pageSize, ...query } = await listSchema.validateAsync(c.req.query(), { stripUnknown: true });
|
|
85
91
|
const where = getWhereFromKvQuery(query.q);
|
|
86
92
|
|
|
87
93
|
if (typeof query.livemode === 'boolean') {
|
|
@@ -98,10 +104,13 @@ router.get('/', authMine, async (req, res) => {
|
|
|
98
104
|
}
|
|
99
105
|
}
|
|
100
106
|
|
|
101
|
-
if (query.customer_id) {
|
|
107
|
+
if (c.get('customer_id') ?? query.customer_id) {
|
|
102
108
|
where[Op.and] = where[Op.and] || [];
|
|
103
109
|
where[Op.and].push(
|
|
104
|
-
Sequelize.where(
|
|
110
|
+
Sequelize.where(
|
|
111
|
+
Sequelize.literal("json_extract(payload, '$.customer_id')"),
|
|
112
|
+
c.get('customer_id') ?? query.customer_id
|
|
113
|
+
)
|
|
105
114
|
);
|
|
106
115
|
}
|
|
107
116
|
|
|
@@ -130,20 +139,20 @@ router.get('/', authMine, async (req, res) => {
|
|
|
130
139
|
offset: (page - 1) * pageSize,
|
|
131
140
|
limit: pageSize,
|
|
132
141
|
});
|
|
133
|
-
const expanded = await MeterEvent.expand(list, !!
|
|
142
|
+
const expanded = await MeterEvent.expand(list, !!c.get('livemode'), {
|
|
134
143
|
customer: true,
|
|
135
144
|
subscription: true,
|
|
136
145
|
meter: !!query.meter_id,
|
|
137
146
|
});
|
|
138
147
|
|
|
139
|
-
|
|
148
|
+
return c.json({ count, list: expanded, paging: { page, pageSize } });
|
|
140
149
|
} catch (err) {
|
|
141
150
|
logger.error('Error listing meter events', err);
|
|
142
|
-
|
|
151
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
143
152
|
}
|
|
144
153
|
});
|
|
145
154
|
|
|
146
|
-
|
|
155
|
+
app.get('/stats', authMine, async (c) => {
|
|
147
156
|
try {
|
|
148
157
|
const {
|
|
149
158
|
meter_id: meterId,
|
|
@@ -151,11 +160,11 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
151
160
|
end,
|
|
152
161
|
customer_id: customerId,
|
|
153
162
|
granularity,
|
|
154
|
-
} = await statsSchema.validateAsync(req.query, { stripUnknown: true });
|
|
163
|
+
} = await statsSchema.validateAsync(c.req.query(), { stripUnknown: true });
|
|
155
164
|
|
|
156
165
|
const meter = await Meter.findByPk(meterId);
|
|
157
166
|
if (!meter) {
|
|
158
|
-
return
|
|
167
|
+
return c.json({ error: 'Meter not found' }, 404);
|
|
159
168
|
}
|
|
160
169
|
|
|
161
170
|
const startDate = new Date(start * 1000);
|
|
@@ -177,11 +186,14 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
177
186
|
}
|
|
178
187
|
|
|
179
188
|
// 构建查询条件
|
|
189
|
+
// 洞 G (Phase 4): raw stats read on meter_events (tenant table) — guard with
|
|
190
|
+
// instance_did so a tenant only ever aggregates its own events.
|
|
180
191
|
let whereClause =
|
|
181
|
-
'event_name = :eventName AND livemode = :livemode AND created_at >= :startDate AND created_at <= :endDate';
|
|
192
|
+
'event_name = :eventName AND livemode = :livemode AND instance_did = :instance_did AND created_at >= :startDate AND created_at <= :endDate';
|
|
182
193
|
const replacements: any = {
|
|
183
194
|
eventName: meter.event_name,
|
|
184
|
-
livemode: !!
|
|
195
|
+
livemode: !!c.get('livemode'),
|
|
196
|
+
instance_did: getInstanceDid(),
|
|
185
197
|
startDate: startDate.toISOString(),
|
|
186
198
|
endDate: endDate.toISOString(),
|
|
187
199
|
};
|
|
@@ -192,12 +204,12 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
192
204
|
}
|
|
193
205
|
|
|
194
206
|
const statsQuery = `
|
|
195
|
-
SELECT
|
|
207
|
+
SELECT
|
|
196
208
|
${dateFormat} as date,
|
|
197
209
|
${dateFormat} as timestamp,
|
|
198
210
|
COUNT(*) as event_count,
|
|
199
211
|
COALESCE(SUM(CAST(payload->>'value' AS DECIMAL)), 0) as total_value
|
|
200
|
-
FROM meter_events
|
|
212
|
+
FROM meter_events
|
|
201
213
|
WHERE ${whereClause}
|
|
202
214
|
GROUP BY ${groupBy}
|
|
203
215
|
ORDER BY ${groupBy}
|
|
@@ -205,7 +217,7 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
205
217
|
|
|
206
218
|
const { sequelize } = MeterEvent;
|
|
207
219
|
if (!sequelize) {
|
|
208
|
-
return
|
|
220
|
+
return c.json({ error: 'Database connection not available' }, 500);
|
|
209
221
|
}
|
|
210
222
|
|
|
211
223
|
const stats = await sequelize.query(statsQuery, {
|
|
@@ -213,7 +225,7 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
213
225
|
type: QueryTypes.SELECT,
|
|
214
226
|
});
|
|
215
227
|
|
|
216
|
-
return
|
|
228
|
+
return c.json({
|
|
217
229
|
count: stats.length,
|
|
218
230
|
list: stats.map((item: any) => ({
|
|
219
231
|
...item,
|
|
@@ -222,98 +234,93 @@ router.get('/stats', authMine, async (req, res) => {
|
|
|
222
234
|
});
|
|
223
235
|
} catch (err) {
|
|
224
236
|
logger.error('Error getting meter event stats', err);
|
|
225
|
-
return
|
|
237
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
226
238
|
}
|
|
227
239
|
});
|
|
228
240
|
|
|
229
|
-
|
|
241
|
+
app.post('/', auth, async (c) => {
|
|
230
242
|
const t0 = performance.now();
|
|
231
243
|
try {
|
|
232
|
-
const
|
|
244
|
+
const body = c.get('sanitizedBody') ?? {};
|
|
245
|
+
const { error } = meterEventSchema.validate(body);
|
|
233
246
|
if (error) {
|
|
234
|
-
return
|
|
247
|
+
return c.json({ error: `Meter event create request invalid: ${error.message}` }, 400);
|
|
235
248
|
}
|
|
236
249
|
|
|
237
250
|
// Phase 1: dedupe + meter + customer lookups in parallel (all independent)
|
|
238
251
|
let t1 = performance.now();
|
|
239
252
|
const [existing, meter, customer] = await Promise.all([
|
|
240
|
-
MeterEvent.isEventExists(
|
|
241
|
-
getCachedMeter(
|
|
242
|
-
Customer.findByPkOrDid(
|
|
253
|
+
MeterEvent.isEventExists(body.identifier),
|
|
254
|
+
getCachedMeter(body.event_name),
|
|
255
|
+
Customer.findByPkOrDid(body.payload.customer_id),
|
|
243
256
|
]);
|
|
244
257
|
const tPhase1 = performance.now() - t1;
|
|
245
258
|
|
|
246
259
|
if (existing) {
|
|
247
|
-
return
|
|
260
|
+
return c.json({ error: `Event with identifier "${body.identifier}" already exists` }, 400);
|
|
248
261
|
}
|
|
249
262
|
if (!meter) {
|
|
250
|
-
return
|
|
251
|
-
.status(400)
|
|
252
|
-
.json({ error: `Meter not found for event name "${req.body.event_name}"`, code: 'METER_NOT_FOUND' });
|
|
263
|
+
return c.json({ error: `Meter not found for event name "${body.event_name}"`, code: 'METER_NOT_FOUND' }, 400);
|
|
253
264
|
}
|
|
254
265
|
if (meter.status !== 'active') {
|
|
255
|
-
return
|
|
256
|
-
.status(400)
|
|
257
|
-
.json({ error: 'Meter is not active, please activate it first.', code: 'METER_NOT_ACTIVE' });
|
|
266
|
+
return c.json({ error: 'Meter is not active, please activate it first.', code: 'METER_NOT_ACTIVE' }, 400);
|
|
258
267
|
}
|
|
259
268
|
if (!customer) {
|
|
260
|
-
return
|
|
269
|
+
return c.json({ error: 'Customer not found' }, 400);
|
|
261
270
|
}
|
|
262
271
|
|
|
263
272
|
// Phase 2: currency + subscription in parallel (currency depends on meter)
|
|
264
273
|
t1 = performance.now();
|
|
265
274
|
const [paymentCurrency, subscription] = await Promise.all([
|
|
266
275
|
getCachedCurrency(meter.currency_id),
|
|
267
|
-
|
|
268
|
-
? Subscription.findByPk(req.body.payload.subscription_id)
|
|
269
|
-
: Promise.resolve(null),
|
|
276
|
+
body.payload.subscription_id ? Subscription.findByPk(body.payload.subscription_id) : Promise.resolve(null),
|
|
270
277
|
]);
|
|
271
278
|
const tPhase2 = performance.now() - t1;
|
|
272
279
|
|
|
273
280
|
if (!paymentCurrency) {
|
|
274
|
-
return
|
|
281
|
+
return c.json({ error: `Payment currency not found for meter "${meter.id}"` }, 400);
|
|
275
282
|
}
|
|
276
283
|
|
|
277
284
|
if (subscription) {
|
|
278
285
|
if (subscription.currency_id !== paymentCurrency.id) {
|
|
279
|
-
return
|
|
286
|
+
return c.json({ error: 'Subscription currency does not match meter currency' }, 400);
|
|
280
287
|
}
|
|
281
288
|
if (!subscription.isConsumesCredit()) {
|
|
282
|
-
return
|
|
289
|
+
return c.json({ error: 'Subscription does not consume credit' }, 400);
|
|
283
290
|
}
|
|
284
|
-
if (subscription.customer_id !==
|
|
285
|
-
return
|
|
291
|
+
if (subscription.customer_id !== body.payload.customer_id) {
|
|
292
|
+
return c.json({ error: 'This is not your subscription' }, 400);
|
|
286
293
|
}
|
|
287
294
|
if (subscription.isImmutable()) {
|
|
288
|
-
return
|
|
295
|
+
return c.json({ error: 'Subscription is immutable' }, 400);
|
|
289
296
|
}
|
|
290
|
-
} else if (
|
|
291
|
-
return
|
|
297
|
+
} else if (body.payload.subscription_id) {
|
|
298
|
+
return c.json({ error: `Subscription not found for meter event "${body.event_name}"` }, 400);
|
|
292
299
|
}
|
|
293
300
|
|
|
294
|
-
const timestamp =
|
|
301
|
+
const timestamp = body.timestamp || body.payload.timestamp || Math.floor(Date.now() / 1000);
|
|
295
302
|
|
|
296
|
-
const value = trimDecimals(
|
|
303
|
+
const value = trimDecimals(body.payload.value, paymentCurrency.decimal);
|
|
297
304
|
const eventData = {
|
|
298
|
-
event_name:
|
|
305
|
+
event_name: body.event_name,
|
|
299
306
|
payload: {
|
|
300
307
|
customer_id: customer.id,
|
|
301
308
|
currency_id: paymentCurrency.id,
|
|
302
309
|
decimal: paymentCurrency.decimal,
|
|
303
310
|
unit: paymentCurrency.name,
|
|
304
|
-
subscription_id:
|
|
311
|
+
subscription_id: body.payload.subscription_id,
|
|
305
312
|
value: fromTokenToUnit(value, paymentCurrency.decimal).toString(),
|
|
306
313
|
},
|
|
307
|
-
identifier:
|
|
314
|
+
identifier: body.identifier,
|
|
308
315
|
livemode: meter.livemode,
|
|
309
316
|
processed: false,
|
|
310
317
|
status: 'pending' as MeterEventStatus,
|
|
311
318
|
attempt_count: 0,
|
|
312
319
|
credit_consumed: '0',
|
|
313
320
|
credit_pending: fromTokenToUnit(value, paymentCurrency.decimal).toString(),
|
|
314
|
-
created_via:
|
|
315
|
-
metadata: formatMetadata(
|
|
316
|
-
source_data:
|
|
321
|
+
created_via: c.get('user')?.via || 'api',
|
|
322
|
+
metadata: formatMetadata(body.metadata),
|
|
323
|
+
source_data: body.source_data,
|
|
317
324
|
timestamp,
|
|
318
325
|
};
|
|
319
326
|
|
|
@@ -335,9 +342,9 @@ router.post('/', auth, async (req, res) => {
|
|
|
335
342
|
`create;dur=${tCreate.toFixed(1)}`,
|
|
336
343
|
`total;dur=${tTotal.toFixed(1)}`,
|
|
337
344
|
];
|
|
338
|
-
|
|
345
|
+
c.header('Server-Timing', timings.join(', '));
|
|
339
346
|
|
|
340
|
-
return
|
|
347
|
+
return c.json({
|
|
341
348
|
...event.toJSON(),
|
|
342
349
|
processing: {
|
|
343
350
|
queued: true,
|
|
@@ -345,42 +352,43 @@ router.post('/', auth, async (req, res) => {
|
|
|
345
352
|
},
|
|
346
353
|
});
|
|
347
354
|
} catch (err) {
|
|
348
|
-
logger.error('create meter event failed', { error: err?.message, request:
|
|
349
|
-
return
|
|
355
|
+
logger.error('create meter event failed', { error: (err as any)?.message, request: c.get('sanitizedBody') ?? {} });
|
|
356
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
350
357
|
}
|
|
351
358
|
});
|
|
352
359
|
|
|
353
|
-
|
|
360
|
+
app.get('/pending-amount', authMine, async (c) => {
|
|
354
361
|
try {
|
|
355
362
|
const params: any = {
|
|
356
|
-
livemode: !!
|
|
363
|
+
livemode: !!c.get('livemode'),
|
|
357
364
|
};
|
|
358
|
-
if (req.query
|
|
359
|
-
params.subscriptionId = req.query
|
|
365
|
+
if (c.req.query('subscription_id')) {
|
|
366
|
+
params.subscriptionId = c.req.query('subscription_id');
|
|
360
367
|
}
|
|
361
|
-
if (req.query
|
|
362
|
-
params.currencyId = req.query
|
|
368
|
+
if (c.req.query('currency_id')) {
|
|
369
|
+
params.currencyId = c.req.query('currency_id');
|
|
363
370
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
371
|
+
const rawCustomerId = c.get('customer_id') ?? c.req.query('customer_id');
|
|
372
|
+
if (rawCustomerId) {
|
|
373
|
+
if (typeof rawCustomerId !== 'string') {
|
|
374
|
+
return c.json({ error: 'Customer ID must be a string' }, 400);
|
|
367
375
|
}
|
|
368
|
-
const customer = await Customer.findByPkOrDid(
|
|
376
|
+
const customer = await Customer.findByPkOrDid(rawCustomerId);
|
|
369
377
|
if (!customer) {
|
|
370
|
-
return
|
|
378
|
+
return c.json({ error: 'Customer not found' }, 404);
|
|
371
379
|
}
|
|
372
380
|
params.customerId = customer.id;
|
|
373
381
|
}
|
|
374
382
|
const [summary] = await MeterEvent.getPendingAmounts(params);
|
|
375
|
-
return
|
|
383
|
+
return c.json(summary);
|
|
376
384
|
} catch (err) {
|
|
377
385
|
logger.error('Error getting meter event pending amount', err);
|
|
378
|
-
return
|
|
386
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
379
387
|
}
|
|
380
388
|
});
|
|
381
389
|
|
|
382
390
|
// Get overdue summary by credit currency (action-required amounts grouped by currency)
|
|
383
|
-
|
|
391
|
+
app.get('/overdue-summary', auth, async (c) => {
|
|
384
392
|
try {
|
|
385
393
|
// Query to aggregate credit_pending by currency, showing overdue amounts per credit currency
|
|
386
394
|
const results = await MeterEvent.sequelize!.query<{
|
|
@@ -389,21 +397,21 @@ router.get('/overdue-summary', auth, async (req, res) => {
|
|
|
389
397
|
customer_count: number;
|
|
390
398
|
event_count: number;
|
|
391
399
|
}>(
|
|
392
|
-
`SELECT
|
|
400
|
+
`SELECT
|
|
393
401
|
m.currency_id,
|
|
394
402
|
SUM(CAST(me.credit_pending AS DECIMAL(40,0))) as total_pending,
|
|
395
403
|
COUNT(DISTINCT json_extract(me.payload, '$.customer_id')) as customer_count,
|
|
396
404
|
COUNT(*) as event_count
|
|
397
405
|
FROM meter_events me
|
|
398
406
|
JOIN meters m ON me.event_name = m.event_name
|
|
399
|
-
WHERE me.livemode = :livemode
|
|
407
|
+
WHERE me.livemode = :livemode
|
|
400
408
|
AND me.status IN ('requires_capture', 'requires_action')
|
|
401
409
|
AND m.status = 'active'
|
|
402
410
|
GROUP BY m.currency_id
|
|
403
411
|
HAVING total_pending > 0
|
|
404
412
|
ORDER BY total_pending DESC`,
|
|
405
413
|
{
|
|
406
|
-
replacements: { livemode:
|
|
414
|
+
replacements: { livemode: c.get('livemode') ? 1 : 0 },
|
|
407
415
|
type: QueryTypes.SELECT,
|
|
408
416
|
}
|
|
409
417
|
);
|
|
@@ -412,7 +420,7 @@ router.get('/overdue-summary', auth, async (req, res) => {
|
|
|
412
420
|
const currencyIds = results.map((r) => r.currency_id);
|
|
413
421
|
const currencies =
|
|
414
422
|
currencyIds.length > 0 ? await PaymentCurrency.findAll({ where: { id: { [Op.in]: currencyIds } } }) : [];
|
|
415
|
-
const currencyMap = new Map(currencies.map((
|
|
423
|
+
const currencyMap = new Map(currencies.map((cur) => [cur.id, cur]));
|
|
416
424
|
|
|
417
425
|
// Filter out results whose currency no longer exists (e.g. deleted currency)
|
|
418
426
|
const list = results
|
|
@@ -431,26 +439,26 @@ router.get('/overdue-summary', auth, async (req, res) => {
|
|
|
431
439
|
})
|
|
432
440
|
.filter((item): item is NonNullable<typeof item> => item !== null);
|
|
433
441
|
|
|
434
|
-
return
|
|
442
|
+
return c.json({ list });
|
|
435
443
|
} catch (err) {
|
|
436
444
|
logger.error('Error getting overdue summary', err);
|
|
437
|
-
return
|
|
445
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
438
446
|
}
|
|
439
447
|
});
|
|
440
448
|
|
|
441
449
|
// Get all customers with credit overdue (action-required amount > 0), grouped by customer + currency
|
|
442
|
-
|
|
450
|
+
app.get('/overdue-customers', auth, async (c) => {
|
|
443
451
|
try {
|
|
444
|
-
const page = Math.max(1, parseInt(String(req.query
|
|
445
|
-
const pageSize = Math.min(100, Math.max(1, parseInt(String(req.query
|
|
452
|
+
const page = Math.max(1, parseInt(String(c.req.query('page') || '1'), 10));
|
|
453
|
+
const pageSize = Math.min(100, Math.max(1, parseInt(String(c.req.query('pageSize') || '20'), 10)));
|
|
446
454
|
const offset = (page - 1) * pageSize;
|
|
447
|
-
const currencyId = req.query
|
|
448
|
-
const searchQuery = req.query
|
|
455
|
+
const currencyId = c.req.query('currency_id') as string | undefined;
|
|
456
|
+
const searchQuery = c.req.query('q') as string | undefined;
|
|
449
457
|
|
|
450
458
|
// If search query provided, first find matching customer IDs
|
|
451
459
|
let customerFilter = '';
|
|
452
|
-
const replacements: any = { livemode:
|
|
453
|
-
const countReplacements: any = { livemode:
|
|
460
|
+
const replacements: any = { livemode: c.get('livemode') ? 1 : 0, limit: pageSize, offset };
|
|
461
|
+
const countReplacements: any = { livemode: c.get('livemode') ? 1 : 0 };
|
|
454
462
|
|
|
455
463
|
// Build currency filter
|
|
456
464
|
let currencyFilter = '';
|
|
@@ -473,9 +481,9 @@ router.get('/overdue-customers', auth, async (req, res) => {
|
|
|
473
481
|
},
|
|
474
482
|
attributes: ['id'],
|
|
475
483
|
});
|
|
476
|
-
const searchCustomerIds = searchCustomers.map((
|
|
484
|
+
const searchCustomerIds = searchCustomers.map((cust) => cust.id);
|
|
477
485
|
if (searchCustomerIds.length === 0) {
|
|
478
|
-
return
|
|
486
|
+
return c.json({ list: [], count: 0, paging: { page, pageSize } });
|
|
479
487
|
}
|
|
480
488
|
// Generate parameterized placeholders for customer IDs
|
|
481
489
|
const placeholders = searchCustomerIds.map((_, i) => `:searchId${i}`);
|
|
@@ -493,14 +501,14 @@ router.get('/overdue-customers', auth, async (req, res) => {
|
|
|
493
501
|
total_pending: string;
|
|
494
502
|
event_count: number;
|
|
495
503
|
}>(
|
|
496
|
-
`SELECT
|
|
504
|
+
`SELECT
|
|
497
505
|
json_extract(me.payload, '$.customer_id') as customer_id,
|
|
498
506
|
m.currency_id as currency_id,
|
|
499
507
|
SUM(CAST(me.credit_pending AS DECIMAL(40,0))) as total_pending,
|
|
500
508
|
COUNT(*) as event_count
|
|
501
509
|
FROM meter_events me
|
|
502
510
|
JOIN meters m ON me.event_name = m.event_name
|
|
503
|
-
WHERE me.livemode = :livemode
|
|
511
|
+
WHERE me.livemode = :livemode
|
|
504
512
|
AND me.status IN ('requires_capture', 'requires_action')
|
|
505
513
|
AND m.status = 'active'
|
|
506
514
|
${currencyFilter}
|
|
@@ -521,7 +529,7 @@ router.get('/overdue-customers', auth, async (req, res) => {
|
|
|
521
529
|
SELECT json_extract(me.payload, '$.customer_id') as customer_id, m.currency_id
|
|
522
530
|
FROM meter_events me
|
|
523
531
|
JOIN meters m ON me.event_name = m.event_name
|
|
524
|
-
WHERE me.livemode = :livemode
|
|
532
|
+
WHERE me.livemode = :livemode
|
|
525
533
|
AND me.status IN ('requires_capture', 'requires_action')
|
|
526
534
|
AND m.status = 'active'
|
|
527
535
|
${currencyFilter}
|
|
@@ -541,11 +549,11 @@ router.get('/overdue-customers', auth, async (req, res) => {
|
|
|
541
549
|
|
|
542
550
|
// Fetch customer and currency details
|
|
543
551
|
const customers = customerIds.length > 0 ? await Customer.findAll({ where: { id: { [Op.in]: customerIds } } }) : [];
|
|
544
|
-
const customerMap = new Map(customers.map((
|
|
552
|
+
const customerMap = new Map(customers.map((cust) => [cust.id, cust]));
|
|
545
553
|
|
|
546
|
-
const
|
|
554
|
+
const fetchedCurrencies =
|
|
547
555
|
currencyIds.length > 0 ? await PaymentCurrency.findAll({ where: { id: { [Op.in]: currencyIds } } }) : [];
|
|
548
|
-
const currencyMap = new Map(
|
|
556
|
+
const currencyMap = new Map(fetchedCurrencies.map((cur) => [cur.id, cur]));
|
|
549
557
|
|
|
550
558
|
const list = results.map((r) => ({
|
|
551
559
|
customer: customerMap.get(r.customer_id),
|
|
@@ -554,19 +562,21 @@ router.get('/overdue-customers', auth, async (req, res) => {
|
|
|
554
562
|
event_count: r.event_count,
|
|
555
563
|
}));
|
|
556
564
|
|
|
557
|
-
return
|
|
565
|
+
return c.json({ list, count, paging: { page, pageSize } });
|
|
558
566
|
} catch (err) {
|
|
559
567
|
logger.error('Error getting overdue customers', err);
|
|
560
|
-
return
|
|
568
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
561
569
|
}
|
|
562
570
|
});
|
|
563
|
-
|
|
571
|
+
|
|
572
|
+
app.get('/:id', authMine, async (c) => {
|
|
564
573
|
try {
|
|
565
|
-
|
|
566
|
-
|
|
574
|
+
const id = c.req.param('id');
|
|
575
|
+
logger.info('get meter event', { id });
|
|
576
|
+
const event = await MeterEvent.findByPk(id);
|
|
567
577
|
|
|
568
578
|
if (!event) {
|
|
569
|
-
return
|
|
579
|
+
return c.json({ error: 'Meter event not found' }, 404);
|
|
570
580
|
}
|
|
571
581
|
|
|
572
582
|
const customerId = event.getCustomerId();
|
|
@@ -574,10 +584,10 @@ router.get('/:id', authMine, async (req, res) => {
|
|
|
574
584
|
const subscription = subscriptionId ? await Subscription.findByPk(subscriptionId) : null;
|
|
575
585
|
const customer = customerId ? await Customer.findByPk(customerId) : null;
|
|
576
586
|
if (!customer) {
|
|
577
|
-
return
|
|
587
|
+
return c.json({ error: 'Customer not found' }, 404);
|
|
578
588
|
}
|
|
579
|
-
if (customer.did !==
|
|
580
|
-
return
|
|
589
|
+
if (customer.did !== c.get('user')?.did && !['owner', 'admin'].includes(c.get('user')?.role || '')) {
|
|
590
|
+
return c.json({ error: 'You are not allowed to access this resource' }, 403);
|
|
581
591
|
}
|
|
582
592
|
const meter = await Meter.getMeterByEventName(event.event_name);
|
|
583
593
|
let paymentCurrency = null;
|
|
@@ -592,11 +602,11 @@ router.get('/:id', authMine, async (req, res) => {
|
|
|
592
602
|
meter,
|
|
593
603
|
paymentCurrency,
|
|
594
604
|
};
|
|
595
|
-
return
|
|
605
|
+
return c.json(result);
|
|
596
606
|
} catch (err) {
|
|
597
607
|
logger.error('Error getting meter event', err);
|
|
598
|
-
return
|
|
608
|
+
return c.json({ error: (err as any)?.message }, 400);
|
|
599
609
|
}
|
|
600
610
|
});
|
|
601
611
|
|
|
602
|
-
export default
|
|
612
|
+
export default app;
|