refactor(billing): extract BillingQuotaService.assertCanExecute from requireQuota middleware#3749
Conversation
…requireQuota middleware (#3748) Promote-up from Trawl: extract the quota/meter enforcement logic from billing.requireQuota.js into a dedicated BillingQuotaService so the enforcement path can be shared with any caller (not just the HTTP middleware), and tested independently. - New: modules/billing/services/billing.quota.service.js Exports assertCanExecute({ orgId, organization, user, resource, action }) with full dual-mode support (legacy quota + meter mode), admin bypass, meterExempt bypass, fail-closed statuses, past_due grace period, and plan-not-configured 503 guard. - Refactor: modules/billing/middlewares/billing.requireQuota.js Now a thin wrapper: calls assertCanExecute, maps AppError status codes to HTTP responses, sets res.locals.billingDegraded on degraded mode. Behavior is unchanged — pure structural refactor. - New: modules/billing/tests/billing.quota.service.unit.tests.js Direct service-layer unit tests (bypasses / meter mode / legacy mode). - Updated: modules/billing/tests/billing.quota.unit.tests.js Adapted to mock BillingQuotaService at the service boundary instead of the middleware's former inline dependencies. All scenario coverage kept. Pure refactor. Trawl has been running this extraction in production for weeks. After merge + /update-stack, Trawl's billing.requireQuota.js becomes byte-compatible with Devkit's. All downstreams inherit the service-layer extraction on their next /update-stack.
|
Warning Review limit reached
More reviews will be available in 7 minutes and 48 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Promotes Trawl's BillingQuotaService.assertCanExecute extraction into Devkit so the quota/meter enforcement logic is reusable beyond the HTTP middleware. Behavior is intended to be byte-identical to the previous middleware: admin/meterExempt bypass, past_due grace period, fail-closed statuses, meter-mode + legacy-mode dual paths, and 503 PLAN_NOT_CONFIGURED guard. The middleware becomes a thin wrapper that maps AppError.status → HTTP responses and propagates degraded to res.locals.
Changes:
- New
BillingQuotaService.assertCanExecute(...)containing the full enforcement tree, throwingAppErrorwithstatus402/429/503 on denial billing.requireQuotamiddleware reduced to organization guard + service call +AppError→HTTP mapping- Middleware tests retargeted to mock the service boundary; new dedicated service-layer unit tests added
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
modules/billing/services/billing.quota.service.js |
New service with the extracted quota/meter enforcement logic |
modules/billing/middlewares/billing.requireQuota.js |
Reduced to guard + service call + status→HTTP mapping (degraded flag preserved) |
modules/billing/tests/billing.quota.service.unit.tests.js |
New direct service-layer unit tests covering both modes and bypass paths |
modules/billing/tests/billing.quota.unit.tests.js |
Updated to mock BillingQuotaService and assert HTTP mapping; legacy nested describe retained but no longer mode-specific |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3749 +/- ##
==========================================
+ Coverage 90.11% 90.13% +0.01%
==========================================
Files 149 150 +1
Lines 4936 4956 +20
Branches 1564 1573 +9
==========================================
+ Hits 4448 4467 +19
- Misses 383 384 +1
Partials 105 105
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
…tency - 402 catch-all in requireQuota middleware no longer surfaces err.message verbatim. The service only throws known types today (PAYMENT_PAST_DUE / METER_EXHAUSTED) which are mapped explicitly above; an unknown 402 sub-type added later would leak the message. Send a generic "Payment required" phrase instead — new sub-types must be mapped explicitly above the catch-all. - billing.quota.service.js: normalize the null-check style on the active plan lookup. Both branches treat "plan not configured" the same way; pick the !activePlan shape to match the freePlan branch above. All 1666 billing unit tests pass.
Summary
BillingQuotaService.assertCanExecuteto Devkit so every downstream benefits on their next/update-stackbilling.requireQuota.jsbecomes a thin wrapper; behavior is byte-identical to current, Trawl has been running this in prod for weeks/update-stackon Trawl,billing.requireQuota.json Trawl becomes byte-compatible with Devkit's (clean merge, no conflict)Files changed
modules/billing/services/billing.quota.service.jsassertCanExecute({ orgId, organization, user, resource, action })— full dual-mode (legacy quota + meter mode), admin/meterExempt bypass, fail-closed, past_due grace, 503 plan-not-configured guardmodules/billing/middlewares/billing.requireQuota.jsres.locals.billingDegradedmodules/billing/tests/billing.quota.service.unit.tests.jsmodules/billing/tests/billing.quota.unit.tests.jsDe-trawlify applied
free/starter/pro)Plan reference
Infra plan Task D.1:
docs/superpowers/plans/2026-05-30-trawl-devkit-perfect-alignment.mdIssue: #3748
Test plan
npm test -- --testPathPatterns="billing.quota"— all 1666 tests pass (115 suites)billing.quota.unit.tests.jsPASS (middleware HTTP mapping)billing.quota.service.unit.tests.jsPASS (service-layer direct)