@wopr-network/platform-core 0.1.0
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/biome.json +61 -0
- package/dist/admin/admin-audit-log-repository.d.ts +33 -0
- package/dist/admin/admin-audit-log-repository.js +102 -0
- package/dist/admin/audit-log.d.ts +49 -0
- package/dist/admin/audit-log.js +63 -0
- package/dist/admin/index.d.ts +6 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/role-store.d.ts +37 -0
- package/dist/admin/role-store.js +106 -0
- package/dist/auth/api-key-repository.d.ts +11 -0
- package/dist/auth/api-key-repository.js +33 -0
- package/dist/auth/api-key-repository.test.d.ts +1 -0
- package/dist/auth/api-key-repository.test.js +46 -0
- package/dist/auth/auth.test.d.ts +1 -0
- package/dist/auth/auth.test.js +140 -0
- package/dist/auth/better-auth.d.ts +42 -0
- package/dist/auth/better-auth.js +196 -0
- package/dist/auth/index.d.ts +186 -0
- package/dist/auth/index.js +422 -0
- package/dist/auth/login-history-repository.d.ts +14 -0
- package/dist/auth/login-history-repository.js +15 -0
- package/dist/auth/login-history-repository.test.d.ts +1 -0
- package/dist/auth/login-history-repository.test.js +47 -0
- package/dist/auth/middleware.d.ts +55 -0
- package/dist/auth/middleware.js +101 -0
- package/dist/auth/middleware.test.d.ts +1 -0
- package/dist/auth/middleware.test.js +213 -0
- package/dist/auth/scoped-tokens.test.d.ts +1 -0
- package/dist/auth/scoped-tokens.test.js +306 -0
- package/dist/auth/tenant-access.test.d.ts +1 -0
- package/dist/auth/tenant-access.test.js +62 -0
- package/dist/auth/user-creator.d.ts +9 -0
- package/dist/auth/user-creator.js +47 -0
- package/dist/auth/user-creator.test.d.ts +1 -0
- package/dist/auth/user-creator.test.js +78 -0
- package/dist/auth/user-role-repository.d.ts +31 -0
- package/dist/auth/user-role-repository.js +53 -0
- package/dist/auth/user-role-repository.test.d.ts +1 -0
- package/dist/auth/user-role-repository.test.js +122 -0
- package/dist/billing/drizzle-webhook-seen-repository.d.ts +10 -0
- package/dist/billing/drizzle-webhook-seen-repository.js +28 -0
- package/dist/billing/index.d.ts +7 -0
- package/dist/billing/index.js +7 -0
- package/dist/billing/payment-processor.d.ts +127 -0
- package/dist/billing/payment-processor.js +8 -0
- package/dist/billing/payment-processor.test.d.ts +1 -0
- package/dist/billing/payment-processor.test.js +71 -0
- package/dist/billing/payram/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/payram/cents-credits-boundary.test.js +75 -0
- package/dist/billing/payram/charge-store.d.ts +41 -0
- package/dist/billing/payram/charge-store.js +72 -0
- package/dist/billing/payram/charge-store.test.d.ts +1 -0
- package/dist/billing/payram/charge-store.test.js +64 -0
- package/dist/billing/payram/checkout.d.ts +15 -0
- package/dist/billing/payram/checkout.js +24 -0
- package/dist/billing/payram/checkout.test.d.ts +1 -0
- package/dist/billing/payram/checkout.test.js +74 -0
- package/dist/billing/payram/client.d.ts +7 -0
- package/dist/billing/payram/client.js +15 -0
- package/dist/billing/payram/client.test.d.ts +1 -0
- package/dist/billing/payram/client.test.js +52 -0
- package/dist/billing/payram/index.d.ts +8 -0
- package/dist/billing/payram/index.js +4 -0
- package/dist/billing/payram/types.d.ts +40 -0
- package/dist/billing/payram/types.js +1 -0
- package/dist/billing/payram/webhook.d.ts +19 -0
- package/dist/billing/payram/webhook.js +67 -0
- package/dist/billing/payram/webhook.test.d.ts +7 -0
- package/dist/billing/payram/webhook.test.js +248 -0
- package/dist/billing/stripe/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/stripe/cents-credits-boundary.test.js +62 -0
- package/dist/billing/stripe/checkout.d.ts +20 -0
- package/dist/billing/stripe/checkout.js +63 -0
- package/dist/billing/stripe/checkout.test.d.ts +1 -0
- package/dist/billing/stripe/checkout.test.js +148 -0
- package/dist/billing/stripe/client.d.ts +14 -0
- package/dist/billing/stripe/client.js +33 -0
- package/dist/billing/stripe/client.test.d.ts +1 -0
- package/dist/billing/stripe/client.test.js +58 -0
- package/dist/billing/stripe/credit-prices.d.ts +63 -0
- package/dist/billing/stripe/credit-prices.js +81 -0
- package/dist/billing/stripe/credit-prices.test.d.ts +1 -0
- package/dist/billing/stripe/credit-prices.test.js +87 -0
- package/dist/billing/stripe/index.d.ts +14 -0
- package/dist/billing/stripe/index.js +8 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.js +40 -0
- package/dist/billing/stripe/payment-methods.d.ts +25 -0
- package/dist/billing/stripe/payment-methods.js +53 -0
- package/dist/billing/stripe/payment-methods.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods.test.js +122 -0
- package/dist/billing/stripe/portal.d.ts +10 -0
- package/dist/billing/stripe/portal.js +16 -0
- package/dist/billing/stripe/portal.test.d.ts +1 -0
- package/dist/billing/stripe/portal.test.js +48 -0
- package/dist/billing/stripe/setup-intent.d.ts +16 -0
- package/dist/billing/stripe/setup-intent.js +22 -0
- package/dist/billing/stripe/setup-intent.test.d.ts +1 -0
- package/dist/billing/stripe/setup-intent.test.js +58 -0
- package/dist/billing/stripe/stripe-payment-processor.d.ts +49 -0
- package/dist/billing/stripe/stripe-payment-processor.js +166 -0
- package/dist/billing/stripe/stripe-payment-processor.test.d.ts +1 -0
- package/dist/billing/stripe/stripe-payment-processor.test.js +413 -0
- package/dist/billing/stripe/tenant-store.d.ts +56 -0
- package/dist/billing/stripe/tenant-store.js +119 -0
- package/dist/billing/stripe/tenant-store.test.d.ts +1 -0
- package/dist/billing/stripe/tenant-store.test.js +97 -0
- package/dist/billing/stripe/types.d.ts +49 -0
- package/dist/billing/stripe/types.js +1 -0
- package/dist/billing/webhook-seen-repository.d.ts +14 -0
- package/dist/billing/webhook-seen-repository.js +13 -0
- package/dist/config/billing-env.test.d.ts +1 -0
- package/dist/config/billing-env.test.js +48 -0
- package/dist/config/index.d.ts +46 -0
- package/dist/config/index.js +38 -0
- package/dist/config/logger.d.ts +2 -0
- package/dist/config/logger.js +11 -0
- package/dist/config/provider-endpoints.d.ts +6 -0
- package/dist/config/provider-endpoints.js +12 -0
- package/dist/credits/auto-topup-charge.d.ts +27 -0
- package/dist/credits/auto-topup-charge.js +139 -0
- package/dist/credits/auto-topup-charge.test.d.ts +1 -0
- package/dist/credits/auto-topup-charge.test.js +242 -0
- package/dist/credits/auto-topup-event-log-repository.d.ts +16 -0
- package/dist/credits/auto-topup-event-log-repository.js +18 -0
- package/dist/credits/auto-topup-event-log-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-event-log-repository.test.js +83 -0
- package/dist/credits/auto-topup-schedule.d.ts +27 -0
- package/dist/credits/auto-topup-schedule.js +66 -0
- package/dist/credits/auto-topup-schedule.test.d.ts +1 -0
- package/dist/credits/auto-topup-schedule.test.js +145 -0
- package/dist/credits/auto-topup-settings-repository.d.ts +54 -0
- package/dist/credits/auto-topup-settings-repository.js +184 -0
- package/dist/credits/auto-topup-settings-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-settings-repository.test.js +104 -0
- package/dist/credits/auto-topup-usage.d.ts +22 -0
- package/dist/credits/auto-topup-usage.js +56 -0
- package/dist/credits/auto-topup-usage.test.d.ts +1 -0
- package/dist/credits/auto-topup-usage.test.js +181 -0
- package/dist/credits/credit-expiry-cron.d.ts +19 -0
- package/dist/credits/credit-expiry-cron.js +50 -0
- package/dist/credits/credit-expiry-cron.test.d.ts +1 -0
- package/dist/credits/credit-expiry-cron.test.js +67 -0
- package/dist/credits/credit-ledger-extra.test.d.ts +1 -0
- package/dist/credits/credit-ledger-extra.test.js +40 -0
- package/dist/credits/credit-ledger.bench.d.ts +1 -0
- package/dist/credits/credit-ledger.bench.js +33 -0
- package/dist/credits/credit-ledger.d.ts +130 -0
- package/dist/credits/credit-ledger.js +293 -0
- package/dist/credits/credit-ledger.test.d.ts +4 -0
- package/dist/credits/credit-ledger.test.js +203 -0
- package/dist/credits/credit-transaction-repository.d.ts +17 -0
- package/dist/credits/credit-transaction-repository.js +35 -0
- package/dist/credits/credit-transaction-repository.test.d.ts +1 -0
- package/dist/credits/credit-transaction-repository.test.js +232 -0
- package/dist/credits/credit.d.ts +75 -0
- package/dist/credits/credit.js +139 -0
- package/dist/credits/credit.test.d.ts +1 -0
- package/dist/credits/credit.test.js +196 -0
- package/dist/credits/dividend-cron.d.ts +29 -0
- package/dist/credits/dividend-cron.js +88 -0
- package/dist/credits/dividend-cron.test.d.ts +1 -0
- package/dist/credits/dividend-cron.test.js +128 -0
- package/dist/credits/dividend-repository.d.ts +29 -0
- package/dist/credits/dividend-repository.js +126 -0
- package/dist/credits/dividend-repository.test.d.ts +1 -0
- package/dist/credits/dividend-repository.test.js +176 -0
- package/dist/credits/index.d.ts +9 -0
- package/dist/credits/index.js +5 -0
- package/dist/credits/repository-types.d.ts +29 -0
- package/dist/credits/repository-types.js +1 -0
- package/dist/credits/signup-grant.d.ts +12 -0
- package/dist/credits/signup-grant.js +35 -0
- package/dist/credits/signup-grant.test.d.ts +1 -0
- package/dist/credits/signup-grant.test.js +51 -0
- package/dist/credits/tenant-customer-repository.d.ts +30 -0
- package/dist/credits/tenant-customer-repository.js +5 -0
- package/dist/db/auth-user-repository.d.ts +46 -0
- package/dist/db/auth-user-repository.js +90 -0
- package/dist/db/credit-column.d.ts +27 -0
- package/dist/db/credit-column.js +13 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.js +8 -0
- package/dist/db/schema/account-deletion-requests.d.ts +203 -0
- package/dist/db/schema/account-deletion-requests.js +36 -0
- package/dist/db/schema/account-export-requests.d.ts +148 -0
- package/dist/db/schema/account-export-requests.js +19 -0
- package/dist/db/schema/admin-audit.d.ts +194 -0
- package/dist/db/schema/admin-audit.js +21 -0
- package/dist/db/schema/admin-users.d.ts +177 -0
- package/dist/db/schema/admin-users.js +23 -0
- package/dist/db/schema/affiliate-fraud.d.ts +160 -0
- package/dist/db/schema/affiliate-fraud.js +18 -0
- package/dist/db/schema/affiliate.d.ts +277 -0
- package/dist/db/schema/affiliate.js +32 -0
- package/dist/db/schema/coupon-codes.d.ts +143 -0
- package/dist/db/schema/coupon-codes.js +17 -0
- package/dist/db/schema/credit-auto-topup-settings.d.ts +232 -0
- package/dist/db/schema/credit-auto-topup-settings.js +27 -0
- package/dist/db/schema/credit-auto-topup.d.ts +130 -0
- package/dist/db/schema/credit-auto-topup.js +21 -0
- package/dist/db/schema/credits.d.ts +283 -0
- package/dist/db/schema/credits.js +38 -0
- package/dist/db/schema/dividend-distributions.d.ts +130 -0
- package/dist/db/schema/dividend-distributions.js +19 -0
- package/dist/db/schema/email-notifications.d.ts +99 -0
- package/dist/db/schema/email-notifications.js +21 -0
- package/dist/db/schema/index.d.ts +33 -0
- package/dist/db/schema/index.js +33 -0
- package/dist/db/schema/meter-events.d.ts +599 -0
- package/dist/db/schema/meter-events.js +55 -0
- package/dist/db/schema/notification-preferences.d.ts +165 -0
- package/dist/db/schema/notification-preferences.js +18 -0
- package/dist/db/schema/notification-queue.d.ts +236 -0
- package/dist/db/schema/notification-queue.js +40 -0
- package/dist/db/schema/org-memberships.d.ts +63 -0
- package/dist/db/schema/org-memberships.js +15 -0
- package/dist/db/schema/organization-members.d.ts +235 -0
- package/dist/db/schema/organization-members.js +27 -0
- package/dist/db/schema/payram.d.ts +164 -0
- package/dist/db/schema/payram.js +21 -0
- package/dist/db/schema/platform-api-keys.d.ts +143 -0
- package/dist/db/schema/platform-api-keys.js +20 -0
- package/dist/db/schema/promotion-redemptions.d.ts +143 -0
- package/dist/db/schema/promotion-redemptions.js +18 -0
- package/dist/db/schema/promotions.d.ts +445 -0
- package/dist/db/schema/promotions.js +48 -0
- package/dist/db/schema/provider-credentials.d.ts +201 -0
- package/dist/db/schema/provider-credentials.js +36 -0
- package/dist/db/schema/rate-limit-entries.d.ts +75 -0
- package/dist/db/schema/rate-limit-entries.js +7 -0
- package/dist/db/schema/secret-audit-log.d.ts +109 -0
- package/dist/db/schema/secret-audit-log.js +15 -0
- package/dist/db/schema/session-usage.d.ts +194 -0
- package/dist/db/schema/session-usage.js +19 -0
- package/dist/db/schema/spending-limits.d.ts +92 -0
- package/dist/db/schema/spending-limits.js +8 -0
- package/dist/db/schema/tenant-addons.d.ts +58 -0
- package/dist/db/schema/tenant-addons.js +9 -0
- package/dist/db/schema/tenant-api-keys.d.ts +131 -0
- package/dist/db/schema/tenant-api-keys.js +21 -0
- package/dist/db/schema/tenant-capability-settings.d.ts +79 -0
- package/dist/db/schema/tenant-capability-settings.js +12 -0
- package/dist/db/schema/tenant-customers.d.ts +303 -0
- package/dist/db/schema/tenant-customers.js +25 -0
- package/dist/db/schema/tenants.d.ts +126 -0
- package/dist/db/schema/tenants.js +18 -0
- package/dist/db/schema/user-roles.d.ts +98 -0
- package/dist/db/schema/user-roles.js +18 -0
- package/dist/db/schema/webhook-seen-events.d.ts +58 -0
- package/dist/db/schema/webhook-seen-events.js +9 -0
- package/dist/email/billing-emails.d.ts +51 -0
- package/dist/email/billing-emails.js +163 -0
- package/dist/email/billing-emails.test.d.ts +1 -0
- package/dist/email/billing-emails.test.js +162 -0
- package/dist/email/client.d.ts +51 -0
- package/dist/email/client.js +102 -0
- package/dist/email/client.test.d.ts +1 -0
- package/dist/email/client.test.js +120 -0
- package/dist/email/drizzle-billing-email-repository.d.ts +21 -0
- package/dist/email/drizzle-billing-email-repository.js +36 -0
- package/dist/email/drizzle-billing-email-repository.test.d.ts +1 -0
- package/dist/email/drizzle-billing-email-repository.test.js +42 -0
- package/dist/email/index.d.ts +33 -0
- package/dist/email/index.js +22 -0
- package/dist/email/notification-preferences-store.d.ts +12 -0
- package/dist/email/notification-preferences-store.js +82 -0
- package/dist/email/notification-preferences-store.test.d.ts +1 -0
- package/dist/email/notification-preferences-store.test.js +86 -0
- package/dist/email/notification-queue-store.d.ts +25 -0
- package/dist/email/notification-queue-store.js +97 -0
- package/dist/email/notification-queue-store.test.d.ts +1 -0
- package/dist/email/notification-queue-store.test.js +177 -0
- package/dist/email/notification-repository-types.d.ts +70 -0
- package/dist/email/notification-repository-types.js +6 -0
- package/dist/email/notification-service.d.ts +41 -0
- package/dist/email/notification-service.js +196 -0
- package/dist/email/notification-service.test.d.ts +1 -0
- package/dist/email/notification-service.test.js +160 -0
- package/dist/email/notification-templates.d.ts +18 -0
- package/dist/email/notification-templates.js +574 -0
- package/dist/email/notification-templates.test.d.ts +1 -0
- package/dist/email/notification-templates.test.js +238 -0
- package/dist/email/notification-worker.d.ts +24 -0
- package/dist/email/notification-worker.js +109 -0
- package/dist/email/notification-worker.test.d.ts +1 -0
- package/dist/email/notification-worker.test.js +153 -0
- package/dist/email/require-verified.d.ts +25 -0
- package/dist/email/require-verified.js +52 -0
- package/dist/email/require-verified.test.d.ts +1 -0
- package/dist/email/require-verified.test.js +62 -0
- package/dist/email/resend-adapter.d.ts +47 -0
- package/dist/email/resend-adapter.js +137 -0
- package/dist/email/resend-adapter.test.d.ts +1 -0
- package/dist/email/resend-adapter.test.js +190 -0
- package/dist/email/templates.d.ts +22 -0
- package/dist/email/templates.js +359 -0
- package/dist/email/templates.test.d.ts +1 -0
- package/dist/email/templates.test.js +170 -0
- package/dist/email/verification.d.ts +42 -0
- package/dist/email/verification.js +83 -0
- package/dist/email/verification.test.d.ts +1 -0
- package/dist/email/verification.test.js +141 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +23 -0
- package/dist/metering/aggregator.d.ts +54 -0
- package/dist/metering/aggregator.js +123 -0
- package/dist/metering/aggregator.test.d.ts +1 -0
- package/dist/metering/aggregator.test.js +179 -0
- package/dist/metering/dlq.d.ts +31 -0
- package/dist/metering/dlq.js +82 -0
- package/dist/metering/dlq.test.d.ts +1 -0
- package/dist/metering/dlq.test.js +117 -0
- package/dist/metering/drizzle-usage-summary-repository.d.ts +67 -0
- package/dist/metering/drizzle-usage-summary-repository.js +98 -0
- package/dist/metering/emitter.d.ts +66 -0
- package/dist/metering/emitter.js +185 -0
- package/dist/metering/emitter.test.d.ts +1 -0
- package/dist/metering/emitter.test.js +171 -0
- package/dist/metering/index.d.ts +11 -0
- package/dist/metering/index.js +5 -0
- package/dist/metering/load-test.bench.d.ts +1 -0
- package/dist/metering/load-test.bench.js +103 -0
- package/dist/metering/meter-event-repository.d.ts +33 -0
- package/dist/metering/meter-event-repository.js +58 -0
- package/dist/metering/meter-repositories.test.d.ts +1 -0
- package/dist/metering/meter-repositories.test.js +419 -0
- package/dist/metering/metering.test.d.ts +1 -0
- package/dist/metering/metering.test.js +1046 -0
- package/dist/metering/reconciliation-cron.d.ts +37 -0
- package/dist/metering/reconciliation-cron.js +85 -0
- package/dist/metering/reconciliation-cron.test.d.ts +1 -0
- package/dist/metering/reconciliation-cron.test.js +162 -0
- package/dist/metering/reconciliation-repository.d.ts +27 -0
- package/dist/metering/reconciliation-repository.js +43 -0
- package/dist/metering/reconciliation-repository.test.d.ts +1 -0
- package/dist/metering/reconciliation-repository.test.js +160 -0
- package/dist/metering/types.d.ts +88 -0
- package/dist/metering/types.js +1 -0
- package/dist/metering/wal.d.ts +49 -0
- package/dist/metering/wal.js +124 -0
- package/dist/metering/wal.test.d.ts +1 -0
- package/dist/metering/wal.test.js +175 -0
- package/dist/middleware/csrf.d.ts +24 -0
- package/dist/middleware/csrf.js +80 -0
- package/dist/middleware/csrf.test.d.ts +1 -0
- package/dist/middleware/csrf.test.js +152 -0
- package/dist/middleware/drizzle-rate-limit-repository.d.ts +9 -0
- package/dist/middleware/drizzle-rate-limit-repository.js +52 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.d.ts +1 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.js +74 -0
- package/dist/middleware/get-client-ip.d.ts +22 -0
- package/dist/middleware/get-client-ip.js +51 -0
- package/dist/middleware/get-client-ip.test.d.ts +1 -0
- package/dist/middleware/get-client-ip.test.js +40 -0
- package/dist/middleware/index.d.ts +5 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/rate-limit-repository.d.ts +19 -0
- package/dist/middleware/rate-limit-repository.js +1 -0
- package/dist/middleware/rate-limit.d.ts +57 -0
- package/dist/middleware/rate-limit.js +109 -0
- package/dist/middleware/rate-limit.test.d.ts +1 -0
- package/dist/middleware/rate-limit.test.js +247 -0
- package/dist/security/credential-vault/audit-repository.d.ts +27 -0
- package/dist/security/credential-vault/audit-repository.js +42 -0
- package/dist/security/credential-vault/audit-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/audit-repository.test.js +78 -0
- package/dist/security/credential-vault/credential-repository.d.ts +94 -0
- package/dist/security/credential-vault/credential-repository.js +145 -0
- package/dist/security/credential-vault/credential-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/credential-repository.test.js +206 -0
- package/dist/security/credential-vault/index.d.ts +12 -0
- package/dist/security/credential-vault/index.js +6 -0
- package/dist/security/credential-vault/key-rotation.d.ts +18 -0
- package/dist/security/credential-vault/key-rotation.js +52 -0
- package/dist/security/credential-vault/key-rotation.test.d.ts +1 -0
- package/dist/security/credential-vault/key-rotation.test.js +95 -0
- package/dist/security/credential-vault/migrate-plaintext.d.ts +15 -0
- package/dist/security/credential-vault/migrate-plaintext.js +80 -0
- package/dist/security/credential-vault/migrate-plaintext.test.d.ts +1 -0
- package/dist/security/credential-vault/migrate-plaintext.test.js +111 -0
- package/dist/security/credential-vault/migration-check.d.ts +15 -0
- package/dist/security/credential-vault/migration-check.js +71 -0
- package/dist/security/credential-vault/migration-check.test.d.ts +1 -0
- package/dist/security/credential-vault/migration-check.test.js +457 -0
- package/dist/security/credential-vault/store.d.ts +106 -0
- package/dist/security/credential-vault/store.js +181 -0
- package/dist/security/credential-vault/store.test.d.ts +1 -0
- package/dist/security/credential-vault/store.test.js +482 -0
- package/dist/security/encryption.d.ts +22 -0
- package/dist/security/encryption.js +53 -0
- package/dist/security/encryption.test.d.ts +1 -0
- package/dist/security/encryption.test.js +95 -0
- package/dist/security/host-validation.d.ts +11 -0
- package/dist/security/host-validation.js +108 -0
- package/dist/security/host-validation.test.d.ts +1 -0
- package/dist/security/host-validation.test.js +106 -0
- package/dist/security/index.d.ts +11 -0
- package/dist/security/index.js +11 -0
- package/dist/security/key-audit.d.ts +16 -0
- package/dist/security/key-audit.js +35 -0
- package/dist/security/key-audit.test.d.ts +1 -0
- package/dist/security/key-audit.test.js +50 -0
- package/dist/security/key-injection.d.ts +28 -0
- package/dist/security/key-injection.js +57 -0
- package/dist/security/key-injection.test.d.ts +1 -0
- package/dist/security/key-injection.test.js +97 -0
- package/dist/security/key-validation.d.ts +16 -0
- package/dist/security/key-validation.js +78 -0
- package/dist/security/key-validation.test.d.ts +1 -0
- package/dist/security/key-validation.test.js +87 -0
- package/dist/security/redirect-allowlist.d.ts +6 -0
- package/dist/security/redirect-allowlist.js +36 -0
- package/dist/security/redirect-allowlist.test.d.ts +1 -0
- package/dist/security/redirect-allowlist.test.js +55 -0
- package/dist/security/tenant-keys/capability-settings-store.d.ts +22 -0
- package/dist/security/tenant-keys/capability-settings-store.js +33 -0
- package/dist/security/tenant-keys/capability-settings-store.test.d.ts +1 -0
- package/dist/security/tenant-keys/capability-settings-store.test.js +77 -0
- package/dist/security/tenant-keys/index.d.ts +10 -0
- package/dist/security/tenant-keys/index.js +5 -0
- package/dist/security/tenant-keys/key-resolution-repository.d.ts +15 -0
- package/dist/security/tenant-keys/key-resolution-repository.js +18 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.js +72 -0
- package/dist/security/tenant-keys/key-resolution.d.ts +39 -0
- package/dist/security/tenant-keys/key-resolution.js +59 -0
- package/dist/security/tenant-keys/key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution.test.js +97 -0
- package/dist/security/tenant-keys/org-key-resolution.d.ts +30 -0
- package/dist/security/tenant-keys/org-key-resolution.js +50 -0
- package/dist/security/tenant-keys/org-key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/org-key-resolution.test.js +103 -0
- package/dist/security/tenant-keys/tenant-key-repository.d.ts +36 -0
- package/dist/security/tenant-keys/tenant-key-repository.js +96 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.js +114 -0
- package/dist/security/types.d.ts +35 -0
- package/dist/security/types.js +15 -0
- package/dist/tenancy/drizzle-org-repository.d.ts +40 -0
- package/dist/tenancy/drizzle-org-repository.js +126 -0
- package/dist/tenancy/index.d.ts +6 -0
- package/dist/tenancy/index.js +3 -0
- package/dist/tenancy/org-member-repository.d.ts +57 -0
- package/dist/tenancy/org-member-repository.js +99 -0
- package/dist/tenancy/org-repository.test.d.ts +1 -0
- package/dist/tenancy/org-repository.test.js +143 -0
- package/dist/tenancy/org-service.d.ts +70 -0
- package/dist/tenancy/org-service.js +223 -0
- package/dist/tenancy/org-service.test.d.ts +1 -0
- package/dist/tenancy/org-service.test.js +550 -0
- package/dist/test/db.d.ts +33 -0
- package/dist/test/db.js +65 -0
- package/dist/trpc/index.d.ts +1 -0
- package/dist/trpc/index.js +1 -0
- package/dist/trpc/init.d.ts +49 -0
- package/dist/trpc/init.js +108 -0
- package/dist/trpc/init.test.d.ts +1 -0
- package/dist/trpc/init.test.js +154 -0
- package/drizzle/migrations/0000_slippery_mandrill.sql +559 -0
- package/drizzle/migrations/meta/0000_snapshot.json +4374 -0
- package/drizzle/migrations/meta/_journal.json +13 -0
- package/drizzle.config.ts +41 -0
- package/package.json +64 -0
- package/src/admin/admin-audit-log-repository.ts +135 -0
- package/src/admin/audit-log.ts +111 -0
- package/src/admin/index.ts +6 -0
- package/src/admin/role-store.ts +134 -0
- package/src/auth/api-key-repository.test.ts +63 -0
- package/src/auth/api-key-repository.ts +46 -0
- package/src/auth/auth.test.ts +166 -0
- package/src/auth/better-auth.ts +216 -0
- package/src/auth/index.ts +520 -0
- package/src/auth/login-history-repository.test.ts +54 -0
- package/src/auth/login-history-repository.ts +28 -0
- package/src/auth/middleware.test.ts +264 -0
- package/src/auth/middleware.ts +117 -0
- package/src/auth/scoped-tokens.test.ts +362 -0
- package/src/auth/tenant-access.test.ts +69 -0
- package/src/auth/user-creator.test.ts +98 -0
- package/src/auth/user-creator.ts +54 -0
- package/src/auth/user-role-repository.test.ts +149 -0
- package/src/auth/user-role-repository.ts +67 -0
- package/src/billing/drizzle-webhook-seen-repository.ts +34 -0
- package/src/billing/index.ts +22 -0
- package/src/billing/payment-processor.test.ts +93 -0
- package/src/billing/payment-processor.ts +150 -0
- package/src/billing/payram/cents-credits-boundary.test.ts +84 -0
- package/src/billing/payram/charge-store.test.ts +84 -0
- package/src/billing/payram/charge-store.ts +109 -0
- package/src/billing/payram/checkout.test.ts +99 -0
- package/src/billing/payram/checkout.ts +40 -0
- package/src/billing/payram/client.test.ts +62 -0
- package/src/billing/payram/client.ts +21 -0
- package/src/billing/payram/index.ts +14 -0
- package/src/billing/payram/types.ts +44 -0
- package/src/billing/payram/webhook.test.ts +318 -0
- package/src/billing/payram/webhook.ts +97 -0
- package/src/billing/stripe/cents-credits-boundary.test.ts +70 -0
- package/src/billing/stripe/checkout.test.ts +186 -0
- package/src/billing/stripe/checkout.ts +82 -0
- package/src/billing/stripe/client.test.ts +64 -0
- package/src/billing/stripe/client.ts +39 -0
- package/src/billing/stripe/credit-prices.test.ts +114 -0
- package/src/billing/stripe/credit-prices.ts +113 -0
- package/src/billing/stripe/index.ts +14 -0
- package/src/billing/stripe/payment-methods-detach-all.test.ts +53 -0
- package/src/billing/stripe/payment-methods.test.ts +157 -0
- package/src/billing/stripe/payment-methods.ts +76 -0
- package/src/billing/stripe/portal.test.ts +63 -0
- package/src/billing/stripe/portal.ts +25 -0
- package/src/billing/stripe/setup-intent.test.ts +78 -0
- package/src/billing/stripe/setup-intent.ts +34 -0
- package/src/billing/stripe/stripe-payment-processor.test.ts +517 -0
- package/src/billing/stripe/stripe-payment-processor.ts +255 -0
- package/src/billing/stripe/tenant-store.test.ts +124 -0
- package/src/billing/stripe/tenant-store.ts +151 -0
- package/src/billing/stripe/types.ts +53 -0
- package/src/billing/webhook-seen-repository.ts +24 -0
- package/src/config/billing-env.test.ts +54 -0
- package/src/config/index.ts +44 -0
- package/src/config/logger.ts +12 -0
- package/src/config/provider-endpoints.ts +14 -0
- package/src/credits/auto-topup-charge.test.ts +292 -0
- package/src/credits/auto-topup-charge.ts +171 -0
- package/src/credits/auto-topup-event-log-repository.test.ts +99 -0
- package/src/credits/auto-topup-event-log-repository.ts +30 -0
- package/src/credits/auto-topup-schedule.test.ts +179 -0
- package/src/credits/auto-topup-schedule.ts +93 -0
- package/src/credits/auto-topup-settings-repository.test.ts +123 -0
- package/src/credits/auto-topup-settings-repository.ts +245 -0
- package/src/credits/auto-topup-usage.test.ts +220 -0
- package/src/credits/auto-topup-usage.ts +68 -0
- package/src/credits/credit-expiry-cron.test.ts +125 -0
- package/src/credits/credit-expiry-cron.ts +76 -0
- package/src/credits/credit-ledger-extra.test.ts +57 -0
- package/src/credits/credit-ledger.bench.ts +56 -0
- package/src/credits/credit-ledger.test.ts +276 -0
- package/src/credits/credit-ledger.ts +450 -0
- package/src/credits/credit-transaction-repository.test.ts +274 -0
- package/src/credits/credit-transaction-repository.ts +62 -0
- package/src/credits/credit.test.ts +234 -0
- package/src/credits/credit.ts +160 -0
- package/src/credits/dividend-cron.test.ts +158 -0
- package/src/credits/dividend-cron.ts +127 -0
- package/src/credits/dividend-repository.test.ts +223 -0
- package/src/credits/dividend-repository.ts +182 -0
- package/src/credits/index.ts +25 -0
- package/src/credits/repository-types.ts +33 -0
- package/src/credits/signup-grant.test.ts +63 -0
- package/src/credits/signup-grant.ts +44 -0
- package/src/credits/tenant-customer-repository.ts +28 -0
- package/src/db/auth-user-repository.ts +124 -0
- package/src/db/credit-column.ts +17 -0
- package/src/db/index.ts +21 -0
- package/src/db/schema/account-deletion-requests.ts +41 -0
- package/src/db/schema/account-export-requests.ts +24 -0
- package/src/db/schema/admin-audit.ts +26 -0
- package/src/db/schema/admin-users.ts +31 -0
- package/src/db/schema/affiliate-fraud.ts +23 -0
- package/src/db/schema/affiliate.ts +38 -0
- package/src/db/schema/coupon-codes.ts +22 -0
- package/src/db/schema/credit-auto-topup-settings.ts +32 -0
- package/src/db/schema/credit-auto-topup.ts +26 -0
- package/src/db/schema/credits.ts +44 -0
- package/src/db/schema/dividend-distributions.ts +24 -0
- package/src/db/schema/email-notifications.ts +26 -0
- package/src/db/schema/index.ts +33 -0
- package/src/db/schema/meter-events.ts +70 -0
- package/src/db/schema/notification-preferences.ts +19 -0
- package/src/db/schema/notification-queue.ts +45 -0
- package/src/db/schema/org-memberships.ts +20 -0
- package/src/db/schema/organization-members.ts +37 -0
- package/src/db/schema/payram.ts +26 -0
- package/src/db/schema/platform-api-keys.ts +25 -0
- package/src/db/schema/promotion-redemptions.ts +23 -0
- package/src/db/schema/promotions.ts +57 -0
- package/src/db/schema/provider-credentials.ts +41 -0
- package/src/db/schema/rate-limit-entries.ts +12 -0
- package/src/db/schema/secret-audit-log.ts +20 -0
- package/src/db/schema/session-usage.ts +24 -0
- package/src/db/schema/spending-limits.ts +9 -0
- package/src/db/schema/tenant-addons.ts +14 -0
- package/src/db/schema/tenant-api-keys.ts +26 -0
- package/src/db/schema/tenant-capability-settings.ts +17 -0
- package/src/db/schema/tenant-customers.ts +35 -0
- package/src/db/schema/tenants.ts +23 -0
- package/src/db/schema/user-roles.ts +23 -0
- package/src/db/schema/webhook-seen-events.ts +14 -0
- package/src/email/billing-emails.test.ts +198 -0
- package/src/email/billing-emails.ts +211 -0
- package/src/email/client.test.ts +149 -0
- package/src/email/client.ts +137 -0
- package/src/email/drizzle-billing-email-repository.test.ts +52 -0
- package/src/email/drizzle-billing-email-repository.ts +59 -0
- package/src/email/index.ts +57 -0
- package/src/email/notification-preferences-store.test.ts +102 -0
- package/src/email/notification-preferences-store.ts +90 -0
- package/src/email/notification-queue-store.test.ts +215 -0
- package/src/email/notification-queue-store.ts +127 -0
- package/src/email/notification-repository-types.ts +101 -0
- package/src/email/notification-service.test.ts +178 -0
- package/src/email/notification-service.ts +265 -0
- package/src/email/notification-templates.test.ts +261 -0
- package/src/email/notification-templates.ts +727 -0
- package/src/email/notification-worker.test.ts +189 -0
- package/src/email/notification-worker.ts +133 -0
- package/src/email/require-verified.ts +65 -0
- package/src/email/resend-adapter.test.ts +253 -0
- package/src/email/resend-adapter.ts +157 -0
- package/src/email/templates.test.ts +217 -0
- package/src/email/templates.ts +469 -0
- package/src/email/verification.test.ts +185 -0
- package/src/email/verification.ts +110 -0
- package/src/index.ts +51 -0
- package/src/metering/aggregator.test.ts +239 -0
- package/src/metering/aggregator.ts +160 -0
- package/src/metering/dlq.test.ts +134 -0
- package/src/metering/dlq.ts +102 -0
- package/src/metering/drizzle-usage-summary-repository.ts +167 -0
- package/src/metering/emitter.test.ts +202 -0
- package/src/metering/emitter.ts +227 -0
- package/src/metering/index.ts +21 -0
- package/src/metering/load-test.bench.ts +130 -0
- package/src/metering/meter-event-repository.ts +87 -0
- package/src/metering/meter-repositories.test.ts +491 -0
- package/src/metering/metering.test.ts +1317 -0
- package/src/metering/reconciliation-cron.test.ts +202 -0
- package/src/metering/reconciliation-cron.ts +134 -0
- package/src/metering/reconciliation-repository.test.ts +196 -0
- package/src/metering/reconciliation-repository.ts +83 -0
- package/src/metering/types.ts +93 -0
- package/src/metering/wal.test.ts +222 -0
- package/src/metering/wal.ts +139 -0
- package/src/middleware/csrf.test.ts +178 -0
- package/src/middleware/csrf.ts +101 -0
- package/src/middleware/drizzle-rate-limit-repository.test.ts +97 -0
- package/src/middleware/drizzle-rate-limit-repository.ts +57 -0
- package/src/middleware/get-client-ip.test.ts +49 -0
- package/src/middleware/get-client-ip.ts +62 -0
- package/src/middleware/index.ts +12 -0
- package/src/middleware/rate-limit-repository.ts +22 -0
- package/src/middleware/rate-limit.test.ts +338 -0
- package/src/middleware/rate-limit.ts +169 -0
- package/src/security/credential-vault/audit-repository.test.ts +91 -0
- package/src/security/credential-vault/audit-repository.ts +64 -0
- package/src/security/credential-vault/credential-repository.test.ts +264 -0
- package/src/security/credential-vault/credential-repository.ts +233 -0
- package/src/security/credential-vault/index.ts +26 -0
- package/src/security/credential-vault/key-rotation.test.ts +139 -0
- package/src/security/credential-vault/key-rotation.ts +70 -0
- package/src/security/credential-vault/migrate-plaintext.test.ts +138 -0
- package/src/security/credential-vault/migrate-plaintext.ts +101 -0
- package/src/security/credential-vault/migration-check.test.ts +533 -0
- package/src/security/credential-vault/migration-check.ts +88 -0
- package/src/security/credential-vault/store.test.ts +569 -0
- package/src/security/credential-vault/store.ts +284 -0
- package/src/security/encryption.test.ts +114 -0
- package/src/security/encryption.ts +65 -0
- package/src/security/host-validation.test.ts +136 -0
- package/src/security/host-validation.ts +116 -0
- package/src/security/index.ts +59 -0
- package/src/security/key-audit.test.ts +57 -0
- package/src/security/key-audit.ts +45 -0
- package/src/security/key-injection.test.ts +131 -0
- package/src/security/key-injection.ts +71 -0
- package/src/security/key-validation.test.ts +111 -0
- package/src/security/key-validation.ts +84 -0
- package/src/security/redirect-allowlist.test.ts +70 -0
- package/src/security/redirect-allowlist.ts +35 -0
- package/src/security/tenant-keys/capability-settings-store.test.ts +98 -0
- package/src/security/tenant-keys/capability-settings-store.ts +53 -0
- package/src/security/tenant-keys/index.ts +10 -0
- package/src/security/tenant-keys/key-resolution-repository.test.ts +95 -0
- package/src/security/tenant-keys/key-resolution-repository.ts +31 -0
- package/src/security/tenant-keys/key-resolution.test.ts +173 -0
- package/src/security/tenant-keys/key-resolution.ts +87 -0
- package/src/security/tenant-keys/org-key-resolution.test.ts +217 -0
- package/src/security/tenant-keys/org-key-resolution.ts +76 -0
- package/src/security/tenant-keys/tenant-key-repository.test.ts +143 -0
- package/src/security/tenant-keys/tenant-key-repository.ts +130 -0
- package/src/security/types.ts +43 -0
- package/src/tenancy/drizzle-org-repository.ts +169 -0
- package/src/tenancy/index.ts +6 -0
- package/src/tenancy/org-member-repository.ts +159 -0
- package/src/tenancy/org-repository.test.ts +172 -0
- package/src/tenancy/org-service.test.ts +634 -0
- package/src/tenancy/org-service.ts +290 -0
- package/src/test/db.ts +97 -0
- package/src/trpc/index.ts +11 -0
- package/src/trpc/init.test.ts +196 -0
- package/src/trpc/init.ts +138 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { Credit } from "../credits/credit.js";
|
|
6
|
+
import { MeterDLQ } from "./dlq.js";
|
|
7
|
+
describe("MeterDLQ", () => {
|
|
8
|
+
let tmpDir;
|
|
9
|
+
let dlqPath;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tmpDir = path.join(os.tmpdir(), `wopr-dlq-test-${Date.now()}`);
|
|
12
|
+
dlqPath = path.join(tmpDir, "meter-dlq.jsonl");
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
if (existsSync(tmpDir)) {
|
|
16
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
it("creates the directory when it does not exist", () => {
|
|
20
|
+
// tmpDir doesn't exist yet — constructor should create it
|
|
21
|
+
expect(existsSync(tmpDir)).toBe(false);
|
|
22
|
+
new MeterDLQ(dlqPath);
|
|
23
|
+
expect(existsSync(tmpDir)).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it("does not throw when directory already exists", () => {
|
|
26
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
27
|
+
expect(() => new MeterDLQ(dlqPath)).not.toThrow();
|
|
28
|
+
});
|
|
29
|
+
it("readAll returns empty array when DLQ file does not exist", () => {
|
|
30
|
+
new MeterDLQ(dlqPath);
|
|
31
|
+
expect(existsSync(dlqPath)).toBe(false);
|
|
32
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
33
|
+
expect(dlq.readAll()).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
it("readAll returns empty array when DLQ file is empty", () => {
|
|
36
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
37
|
+
writeFileSync(dlqPath, "");
|
|
38
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
39
|
+
expect(dlq.readAll()).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
it("readAll returns empty array when DLQ file contains only whitespace", () => {
|
|
42
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
43
|
+
writeFileSync(dlqPath, "\n\n \n");
|
|
44
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
45
|
+
expect(dlq.readAll()).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
it("append writes a DLQ entry and readAll returns it", () => {
|
|
48
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
49
|
+
const event = {
|
|
50
|
+
id: "evt-1",
|
|
51
|
+
tenant: "tenant-1",
|
|
52
|
+
capability: "tts",
|
|
53
|
+
provider: "elevenlabs",
|
|
54
|
+
cost: Credit.fromDollars(0.01),
|
|
55
|
+
charge: Credit.fromDollars(0.02),
|
|
56
|
+
timestamp: Date.now(),
|
|
57
|
+
};
|
|
58
|
+
dlq.append(event, "Stripe API 500", 3);
|
|
59
|
+
const entries = dlq.readAll();
|
|
60
|
+
expect(entries).toHaveLength(1);
|
|
61
|
+
expect(entries[0].id).toBe("evt-1");
|
|
62
|
+
expect(entries[0].dlq_error).toBe("Stripe API 500");
|
|
63
|
+
expect(entries[0].dlq_retries).toBe(3);
|
|
64
|
+
});
|
|
65
|
+
it("count returns 0 for empty DLQ", () => {
|
|
66
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
67
|
+
expect(dlq.count()).toBe(0);
|
|
68
|
+
});
|
|
69
|
+
it("count returns correct count after appending", () => {
|
|
70
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
71
|
+
const event = {
|
|
72
|
+
id: "evt-1",
|
|
73
|
+
tenant: "t1",
|
|
74
|
+
capability: "tts",
|
|
75
|
+
provider: "elevenlabs",
|
|
76
|
+
cost: Credit.fromDollars(0.01),
|
|
77
|
+
charge: Credit.fromDollars(0.02),
|
|
78
|
+
timestamp: Date.now(),
|
|
79
|
+
};
|
|
80
|
+
dlq.append(event, "err", 1);
|
|
81
|
+
dlq.append({ ...event, id: "evt-2" }, "err2", 2);
|
|
82
|
+
expect(dlq.count()).toBe(2);
|
|
83
|
+
});
|
|
84
|
+
it("count counts malformed lines (no JSON parsing)", () => {
|
|
85
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
86
|
+
const goodLine = JSON.stringify({ id: "evt-1", dlq_error: "e", dlq_retries: 1, dlq_timestamp: 0 });
|
|
87
|
+
writeFileSync(dlqPath, `${goodLine}\nnot-valid-json\n`);
|
|
88
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
89
|
+
// count should return 2 (line count), not 1 (parsed count)
|
|
90
|
+
// This verifies count() does NOT use JSON.parse
|
|
91
|
+
expect(dlq.count()).toBe(2);
|
|
92
|
+
});
|
|
93
|
+
it("count returns correct count when file has no trailing newline", () => {
|
|
94
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
95
|
+
const line1 = JSON.stringify({ id: "evt-1", dlq_error: "e", dlq_retries: 1, dlq_timestamp: 0 });
|
|
96
|
+
const line2 = JSON.stringify({ id: "evt-2", dlq_error: "e", dlq_retries: 1, dlq_timestamp: 0 });
|
|
97
|
+
// Write two entries with no trailing newline
|
|
98
|
+
writeFileSync(dlqPath, `${line1}\n${line2}`);
|
|
99
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
100
|
+
expect(dlq.count()).toBe(2);
|
|
101
|
+
});
|
|
102
|
+
it("count returns 0 when file is deleted between calls (ENOENT)", () => {
|
|
103
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
104
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
105
|
+
// File doesn't exist at all — should not throw, return 0
|
|
106
|
+
expect(dlq.count()).toBe(0);
|
|
107
|
+
});
|
|
108
|
+
it("readAll skips malformed lines", () => {
|
|
109
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
110
|
+
const goodLine = JSON.stringify({ id: "evt-1", dlq_error: "e", dlq_retries: 1, dlq_timestamp: 0 });
|
|
111
|
+
writeFileSync(dlqPath, `${goodLine}\nnot-valid-json\n`);
|
|
112
|
+
const dlq = new MeterDLQ(dlqPath);
|
|
113
|
+
const entries = dlq.readAll();
|
|
114
|
+
expect(entries).toHaveLength(1);
|
|
115
|
+
expect(entries[0].id).toBe("evt-1");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { PlatformDb } from "../db/index.js";
|
|
2
|
+
import type { UsageSummary } from "./types.js";
|
|
3
|
+
export interface AggregatedWindowRow {
|
|
4
|
+
tenant: string;
|
|
5
|
+
capability: string;
|
|
6
|
+
provider: string;
|
|
7
|
+
eventCount: number;
|
|
8
|
+
totalCost: number;
|
|
9
|
+
totalCharge: number;
|
|
10
|
+
totalDuration: number;
|
|
11
|
+
}
|
|
12
|
+
export interface UsageSummaryInsert {
|
|
13
|
+
id: string;
|
|
14
|
+
tenant: string;
|
|
15
|
+
capability: string;
|
|
16
|
+
provider: string;
|
|
17
|
+
eventCount: number;
|
|
18
|
+
totalCost: number;
|
|
19
|
+
totalCharge: number;
|
|
20
|
+
totalDuration: number;
|
|
21
|
+
windowStart: number;
|
|
22
|
+
windowEnd: number;
|
|
23
|
+
}
|
|
24
|
+
export interface IUsageSummaryRepository {
|
|
25
|
+
/** Get the maximum windowEnd across all usage summaries. Returns 0 if none. */
|
|
26
|
+
getLastWindowEnd(): Promise<number>;
|
|
27
|
+
/** Get the earliest meter event timestamp before the given time. Returns null if none. */
|
|
28
|
+
getEarliestEventTimestamp(before: number): Promise<number | null>;
|
|
29
|
+
/** Get aggregated event groups for a time window [start, end). */
|
|
30
|
+
getAggregatedEvents(windowStart: number, windowEnd: number): Promise<AggregatedWindowRow[]>;
|
|
31
|
+
/** Insert a single usage summary row. */
|
|
32
|
+
insertSummary(values: UsageSummaryInsert): Promise<void>;
|
|
33
|
+
/** Insert multiple usage summary rows in a transaction. */
|
|
34
|
+
insertSummariesBatch(rows: UsageSummaryInsert[]): Promise<void>;
|
|
35
|
+
/** Query usage summaries for a tenant within a time range. */
|
|
36
|
+
querySummaries(tenant: string, opts?: {
|
|
37
|
+
since?: number;
|
|
38
|
+
until?: number;
|
|
39
|
+
limit?: number;
|
|
40
|
+
}): Promise<UsageSummary[]>;
|
|
41
|
+
/** Get a tenant's total usage since a given time. */
|
|
42
|
+
getTenantTotal(tenant: string, since: number): Promise<{
|
|
43
|
+
totalCost: number;
|
|
44
|
+
totalCharge: number;
|
|
45
|
+
eventCount: number;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
export declare class DrizzleUsageSummaryRepository implements IUsageSummaryRepository {
|
|
49
|
+
private readonly db;
|
|
50
|
+
constructor(db: PlatformDb);
|
|
51
|
+
getLastWindowEnd(): Promise<number>;
|
|
52
|
+
getEarliestEventTimestamp(before: number): Promise<number | null>;
|
|
53
|
+
getAggregatedEvents(windowStart: number, windowEnd: number): Promise<AggregatedWindowRow[]>;
|
|
54
|
+
insertSummary(values: UsageSummaryInsert): Promise<void>;
|
|
55
|
+
insertSummariesBatch(rows: UsageSummaryInsert[]): Promise<void>;
|
|
56
|
+
querySummaries(tenant: string, opts?: {
|
|
57
|
+
since?: number;
|
|
58
|
+
until?: number;
|
|
59
|
+
limit?: number;
|
|
60
|
+
}): Promise<UsageSummary[]>;
|
|
61
|
+
getTenantTotal(tenant: string, since: number): Promise<{
|
|
62
|
+
totalCost: number;
|
|
63
|
+
totalCharge: number;
|
|
64
|
+
eventCount: number;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
export { DrizzleUsageSummaryRepository as UsageSummaryRepository };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { and, count, desc, eq, gte, lt, lte, max, min, sql, sum } from "drizzle-orm";
|
|
2
|
+
import { meterEvents, usageSummaries } from "../db/schema/meter-events.js";
|
|
3
|
+
export class DrizzleUsageSummaryRepository {
|
|
4
|
+
db;
|
|
5
|
+
constructor(db) {
|
|
6
|
+
this.db = db;
|
|
7
|
+
}
|
|
8
|
+
async getLastWindowEnd() {
|
|
9
|
+
const row = (await this.db.select({ lastEnd: max(usageSummaries.windowEnd) }).from(usageSummaries))[0];
|
|
10
|
+
return row?.lastEnd ?? 0;
|
|
11
|
+
}
|
|
12
|
+
async getEarliestEventTimestamp(before) {
|
|
13
|
+
const row = (await this.db
|
|
14
|
+
.select({ ts: min(meterEvents.timestamp) })
|
|
15
|
+
.from(meterEvents)
|
|
16
|
+
.where(lt(meterEvents.timestamp, before)))[0];
|
|
17
|
+
return row?.ts ?? null;
|
|
18
|
+
}
|
|
19
|
+
async getAggregatedEvents(windowStart, windowEnd) {
|
|
20
|
+
const rows = await this.db
|
|
21
|
+
.select({
|
|
22
|
+
tenant: meterEvents.tenant,
|
|
23
|
+
capability: meterEvents.capability,
|
|
24
|
+
provider: meterEvents.provider,
|
|
25
|
+
eventCount: count(),
|
|
26
|
+
totalCost: sum(meterEvents.cost),
|
|
27
|
+
totalCharge: sum(meterEvents.charge),
|
|
28
|
+
totalDuration: sql `COALESCE(SUM(${meterEvents.duration}), 0)`,
|
|
29
|
+
})
|
|
30
|
+
.from(meterEvents)
|
|
31
|
+
.where(and(gte(meterEvents.timestamp, windowStart), lt(meterEvents.timestamp, windowEnd)))
|
|
32
|
+
.groupBy(meterEvents.tenant, meterEvents.capability, meterEvents.provider);
|
|
33
|
+
return rows.map((r) => ({
|
|
34
|
+
tenant: r.tenant,
|
|
35
|
+
capability: r.capability,
|
|
36
|
+
provider: r.provider,
|
|
37
|
+
eventCount: r.eventCount,
|
|
38
|
+
totalCost: Number(r.totalCost),
|
|
39
|
+
totalCharge: Number(r.totalCharge),
|
|
40
|
+
totalDuration: Number(r.totalDuration),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
async insertSummary(values) {
|
|
44
|
+
await this.db.insert(usageSummaries).values(values);
|
|
45
|
+
}
|
|
46
|
+
async insertSummariesBatch(rows) {
|
|
47
|
+
if (rows.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const CHUNK_SIZE = 1000; // safe limit: each row has ~10 columns, 1000*10 < 65535 param limit
|
|
50
|
+
await this.db.transaction(async (tx) => {
|
|
51
|
+
for (let i = 0; i < rows.length; i += CHUNK_SIZE) {
|
|
52
|
+
await tx.insert(usageSummaries).values(rows.slice(i, i + CHUNK_SIZE));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async querySummaries(tenant, opts = {}) {
|
|
57
|
+
const conditions = [eq(usageSummaries.tenant, tenant)];
|
|
58
|
+
if (opts.since != null) {
|
|
59
|
+
conditions.push(gte(usageSummaries.windowStart, opts.since));
|
|
60
|
+
}
|
|
61
|
+
if (opts.until != null) {
|
|
62
|
+
conditions.push(lte(usageSummaries.windowEnd, opts.until));
|
|
63
|
+
}
|
|
64
|
+
const limit = Math.min(Math.max(1, opts.limit ?? 100), 1000);
|
|
65
|
+
return this.db
|
|
66
|
+
.select({
|
|
67
|
+
tenant: usageSummaries.tenant,
|
|
68
|
+
capability: usageSummaries.capability,
|
|
69
|
+
provider: usageSummaries.provider,
|
|
70
|
+
event_count: usageSummaries.eventCount,
|
|
71
|
+
total_cost: usageSummaries.totalCost,
|
|
72
|
+
total_charge: usageSummaries.totalCharge,
|
|
73
|
+
total_duration: usageSummaries.totalDuration,
|
|
74
|
+
window_start: usageSummaries.windowStart,
|
|
75
|
+
window_end: usageSummaries.windowEnd,
|
|
76
|
+
})
|
|
77
|
+
.from(usageSummaries)
|
|
78
|
+
.where(and(...conditions))
|
|
79
|
+
.orderBy(desc(usageSummaries.windowStart))
|
|
80
|
+
.limit(limit);
|
|
81
|
+
}
|
|
82
|
+
async getTenantTotal(tenant, since) {
|
|
83
|
+
const row = (await this.db
|
|
84
|
+
.select({
|
|
85
|
+
totalCost: sql `COALESCE(SUM(${usageSummaries.totalCost}), 0)`,
|
|
86
|
+
totalCharge: sql `COALESCE(SUM(${usageSummaries.totalCharge}), 0)`,
|
|
87
|
+
eventCount: sql `COALESCE(SUM(${usageSummaries.eventCount}), 0)`,
|
|
88
|
+
})
|
|
89
|
+
.from(usageSummaries)
|
|
90
|
+
.where(and(eq(usageSummaries.tenant, tenant), gte(usageSummaries.windowStart, since))))[0];
|
|
91
|
+
return {
|
|
92
|
+
totalCost: Number(row?.totalCost ?? 0),
|
|
93
|
+
totalCharge: Number(row?.totalCharge ?? 0),
|
|
94
|
+
eventCount: Number(row?.eventCount ?? 0),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export { DrizzleUsageSummaryRepository as UsageSummaryRepository };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { IMeterEventRepository } from "./meter-event-repository.js";
|
|
2
|
+
import type { MeterEvent, MeterEventRow } from "./types.js";
|
|
3
|
+
export interface IMeterEmitter {
|
|
4
|
+
emit(event: MeterEvent): void;
|
|
5
|
+
flush(): Promise<number>;
|
|
6
|
+
readonly pending: number;
|
|
7
|
+
close(): void;
|
|
8
|
+
queryEvents(tenant: string, limit?: number): Promise<MeterEventRow[]>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Fire-and-forget meter event emitter with fail-closed durability.
|
|
12
|
+
*
|
|
13
|
+
* Buffers events in memory and flushes them to the database in batches,
|
|
14
|
+
* ensuring zero latency impact on the observed API calls.
|
|
15
|
+
*
|
|
16
|
+
* FAIL-CLOSED POLICY:
|
|
17
|
+
* - Events are written to WAL (write-ahead log) on disk BEFORE buffering
|
|
18
|
+
* - If flush fails, events are retried up to MAX_RETRIES times
|
|
19
|
+
* - After MAX_RETRIES, events move to DLQ (dead-letter queue) for manual recovery
|
|
20
|
+
* - On startup, unflushed WAL events are replayed idempotently
|
|
21
|
+
*/
|
|
22
|
+
export declare class DrizzleMeterEmitter implements IMeterEmitter {
|
|
23
|
+
private readonly repo;
|
|
24
|
+
private buffer;
|
|
25
|
+
private flushTimer;
|
|
26
|
+
private readonly flushIntervalMs;
|
|
27
|
+
private readonly batchSize;
|
|
28
|
+
private readonly maxRetries;
|
|
29
|
+
private closed;
|
|
30
|
+
private readonly wal;
|
|
31
|
+
private readonly dlq;
|
|
32
|
+
private readonly retryCount;
|
|
33
|
+
/** Resolves when the initial WAL replay has completed. */
|
|
34
|
+
readonly ready: Promise<void>;
|
|
35
|
+
constructor(repo: IMeterEventRepository, opts?: {
|
|
36
|
+
flushIntervalMs?: number;
|
|
37
|
+
batchSize?: number;
|
|
38
|
+
walPath?: string;
|
|
39
|
+
dlqPath?: string;
|
|
40
|
+
maxRetries?: number;
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Replay unflushed events from the WAL on startup.
|
|
44
|
+
* Idempotent: skips events already in the database.
|
|
45
|
+
* Returns a promise that resolves when the replay is complete.
|
|
46
|
+
*/
|
|
47
|
+
private replayWAL;
|
|
48
|
+
/**
|
|
49
|
+
* Reconstitute Credit fields on WAL events after JSON deserialization.
|
|
50
|
+
* Credit.toJSON() serializes to a raw number, so after JSON.parse the
|
|
51
|
+
* cost/charge fields are plain numbers — convert them back to Credit.
|
|
52
|
+
*/
|
|
53
|
+
private reconstituteCreditFields;
|
|
54
|
+
private replayWALAsync;
|
|
55
|
+
/** Emit a meter event. Non-blocking -- buffers in memory after WAL write. */
|
|
56
|
+
emit(event: MeterEvent): void;
|
|
57
|
+
/** Flush buffered events to the database with retry and DLQ logic. */
|
|
58
|
+
flush(): Promise<number>;
|
|
59
|
+
/** Number of events currently buffered. */
|
|
60
|
+
get pending(): number;
|
|
61
|
+
/** Stop the flush timer and flush remaining events. */
|
|
62
|
+
close(): void;
|
|
63
|
+
/** Query persisted events (for testing / diagnostics). */
|
|
64
|
+
queryEvents(tenant: string, limit?: number): Promise<MeterEventRow[]>;
|
|
65
|
+
}
|
|
66
|
+
export { DrizzleMeterEmitter as MeterEmitter };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { config } from "../config/index.js";
|
|
2
|
+
import { Credit } from "../credits/credit.js";
|
|
3
|
+
import { MeterDLQ } from "./dlq.js";
|
|
4
|
+
import { MeterWAL } from "./wal.js";
|
|
5
|
+
const DEFAULT_WAL_PATH = process.env.METER_WAL_PATH ?? "./data/meter-wal.jsonl";
|
|
6
|
+
const DEFAULT_DLQ_PATH = process.env.METER_DLQ_PATH ?? "./data/meter-dlq.jsonl";
|
|
7
|
+
const DEFAULT_MAX_RETRIES = config.billing.meterMaxRetries;
|
|
8
|
+
/**
|
|
9
|
+
* Fire-and-forget meter event emitter with fail-closed durability.
|
|
10
|
+
*
|
|
11
|
+
* Buffers events in memory and flushes them to the database in batches,
|
|
12
|
+
* ensuring zero latency impact on the observed API calls.
|
|
13
|
+
*
|
|
14
|
+
* FAIL-CLOSED POLICY:
|
|
15
|
+
* - Events are written to WAL (write-ahead log) on disk BEFORE buffering
|
|
16
|
+
* - If flush fails, events are retried up to MAX_RETRIES times
|
|
17
|
+
* - After MAX_RETRIES, events move to DLQ (dead-letter queue) for manual recovery
|
|
18
|
+
* - On startup, unflushed WAL events are replayed idempotently
|
|
19
|
+
*/
|
|
20
|
+
export class DrizzleMeterEmitter {
|
|
21
|
+
repo;
|
|
22
|
+
buffer = [];
|
|
23
|
+
flushTimer = null;
|
|
24
|
+
flushIntervalMs;
|
|
25
|
+
batchSize;
|
|
26
|
+
maxRetries;
|
|
27
|
+
closed = false;
|
|
28
|
+
wal;
|
|
29
|
+
dlq;
|
|
30
|
+
retryCount = new Map();
|
|
31
|
+
/** Resolves when the initial WAL replay has completed. */
|
|
32
|
+
ready;
|
|
33
|
+
constructor(repo, opts = {}) {
|
|
34
|
+
this.repo = repo;
|
|
35
|
+
this.flushIntervalMs = opts.flushIntervalMs ?? 1000;
|
|
36
|
+
this.batchSize = opts.batchSize ?? 100;
|
|
37
|
+
this.maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
38
|
+
this.wal = new MeterWAL(opts.walPath ?? DEFAULT_WAL_PATH);
|
|
39
|
+
this.dlq = new MeterDLQ(opts.dlqPath ?? DEFAULT_DLQ_PATH);
|
|
40
|
+
// Replay any unflushed WAL events from a previous session.
|
|
41
|
+
this.ready = this.replayWAL();
|
|
42
|
+
this.flushTimer = setInterval(() => this.flush(), this.flushIntervalMs);
|
|
43
|
+
// Do not keep the process alive just for metering flushes.
|
|
44
|
+
if (this.flushTimer.unref) {
|
|
45
|
+
this.flushTimer.unref();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Replay unflushed events from the WAL on startup.
|
|
50
|
+
* Idempotent: skips events already in the database.
|
|
51
|
+
* Returns a promise that resolves when the replay is complete.
|
|
52
|
+
*/
|
|
53
|
+
async replayWAL() {
|
|
54
|
+
const walEvents = this.wal.readAll();
|
|
55
|
+
if (walEvents.length === 0)
|
|
56
|
+
return;
|
|
57
|
+
await this.replayWALAsync(walEvents);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Reconstitute Credit fields on WAL events after JSON deserialization.
|
|
61
|
+
* Credit.toJSON() serializes to a raw number, so after JSON.parse the
|
|
62
|
+
* cost/charge fields are plain numbers — convert them back to Credit.
|
|
63
|
+
*/
|
|
64
|
+
reconstituteCreditFields(events) {
|
|
65
|
+
return events.map((e) => ({
|
|
66
|
+
...e,
|
|
67
|
+
cost: e.cost instanceof Credit ? e.cost : Credit.fromRaw(e.cost),
|
|
68
|
+
charge: e.charge instanceof Credit ? e.charge : Credit.fromRaw(e.charge),
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
async replayWALAsync(walEvents) {
|
|
72
|
+
// Reconstitute Credit objects from raw numbers after JSON deserialization.
|
|
73
|
+
walEvents = this.reconstituteCreditFields(walEvents);
|
|
74
|
+
// Check which events are already in the database.
|
|
75
|
+
const existingIds = new Set();
|
|
76
|
+
for (const e of walEvents) {
|
|
77
|
+
if (await this.repo.existsById(e.id)) {
|
|
78
|
+
existingIds.add(e.id);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Replay only new events.
|
|
82
|
+
const toReplay = walEvents.filter((e) => !existingIds.has(e.id));
|
|
83
|
+
if (toReplay.length > 0) {
|
|
84
|
+
this.buffer.push(...toReplay);
|
|
85
|
+
const flushed = await this.flush();
|
|
86
|
+
if (flushed === 0) {
|
|
87
|
+
// Flush failed -- events remain in WAL and buffer for retry.
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Remove already-persisted events from WAL (idempotent cleanup).
|
|
92
|
+
if (existingIds.size > 0) {
|
|
93
|
+
await this.wal.remove(existingIds);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Emit a meter event. Non-blocking -- buffers in memory after WAL write. */
|
|
97
|
+
emit(event) {
|
|
98
|
+
if (this.closed)
|
|
99
|
+
return;
|
|
100
|
+
// FAIL-CLOSED: Write to WAL first, then buffer.
|
|
101
|
+
// append() is synchronous (appendFileSync), so the WAL write completes
|
|
102
|
+
// before buffer.push() — crash safety is guaranteed.
|
|
103
|
+
const eventWithId = this.wal.append(event);
|
|
104
|
+
this.buffer.push(eventWithId);
|
|
105
|
+
if (this.buffer.length >= this.batchSize) {
|
|
106
|
+
void this.flush();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Flush buffered events to the database with retry and DLQ logic. */
|
|
110
|
+
async flush() {
|
|
111
|
+
if (this.buffer.length === 0)
|
|
112
|
+
return 0;
|
|
113
|
+
const batch = this.buffer.splice(0);
|
|
114
|
+
try {
|
|
115
|
+
await this.repo.insertBatch(batch.map((e) => ({
|
|
116
|
+
id: e.id,
|
|
117
|
+
tenant: e.tenant,
|
|
118
|
+
cost: e.cost.toRaw(),
|
|
119
|
+
charge: e.charge.toRaw(),
|
|
120
|
+
capability: e.capability,
|
|
121
|
+
provider: e.provider,
|
|
122
|
+
timestamp: e.timestamp,
|
|
123
|
+
sessionId: e.sessionId ?? null,
|
|
124
|
+
duration: e.duration ?? null,
|
|
125
|
+
usageUnits: e.usage?.units ?? null,
|
|
126
|
+
usageUnitType: e.usage?.unitType ?? null,
|
|
127
|
+
tier: e.tier ?? null,
|
|
128
|
+
metadata: e.metadata ? JSON.stringify(e.metadata) : null,
|
|
129
|
+
})));
|
|
130
|
+
// Success: remove from WAL and reset retry counters.
|
|
131
|
+
const flushedIds = new Set(batch.map((e) => e.id));
|
|
132
|
+
await this.wal.remove(flushedIds);
|
|
133
|
+
for (const id of flushedIds) {
|
|
134
|
+
this.retryCount.delete(id);
|
|
135
|
+
}
|
|
136
|
+
return batch.length;
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
// Failure: track retries and move to DLQ if max exceeded.
|
|
140
|
+
const toRetry = [];
|
|
141
|
+
const toDLQ = [];
|
|
142
|
+
for (const event of batch) {
|
|
143
|
+
const retries = (this.retryCount.get(event.id) ?? 0) + 1;
|
|
144
|
+
this.retryCount.set(event.id, retries);
|
|
145
|
+
if (retries >= this.maxRetries) {
|
|
146
|
+
// Max retries exceeded -- move to DLQ.
|
|
147
|
+
toDLQ.push(event);
|
|
148
|
+
this.dlq.append(event, String(error), retries);
|
|
149
|
+
this.retryCount.delete(event.id);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Retry on next flush.
|
|
153
|
+
toRetry.push(event);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Remove DLQ events from WAL (they're now in DLQ).
|
|
157
|
+
if (toDLQ.length > 0) {
|
|
158
|
+
const dlqIds = new Set(toDLQ.map((e) => e.id));
|
|
159
|
+
await this.wal.remove(dlqIds);
|
|
160
|
+
}
|
|
161
|
+
// Re-add retry events to buffer.
|
|
162
|
+
this.buffer.unshift(...toRetry);
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** Number of events currently buffered. */
|
|
167
|
+
get pending() {
|
|
168
|
+
return this.buffer.length;
|
|
169
|
+
}
|
|
170
|
+
/** Stop the flush timer and flush remaining events. */
|
|
171
|
+
close() {
|
|
172
|
+
this.closed = true;
|
|
173
|
+
if (this.flushTimer) {
|
|
174
|
+
clearInterval(this.flushTimer);
|
|
175
|
+
this.flushTimer = null;
|
|
176
|
+
}
|
|
177
|
+
void this.flush();
|
|
178
|
+
}
|
|
179
|
+
/** Query persisted events (for testing / diagnostics). */
|
|
180
|
+
async queryEvents(tenant, limit = 50) {
|
|
181
|
+
return this.repo.queryByTenant(tenant, limit);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Backward-compat alias.
|
|
185
|
+
export { DrizzleMeterEmitter as MeterEmitter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|