Skip to content

feat(express-context): add shared BillingClient abstraction#1289

Merged
pyramation merged 1 commit into
mainfrom
feat/express-context-billing-client
Jun 13, 2026
Merged

feat(express-context): add shared BillingClient abstraction#1289
pyramation merged 1 commit into
mainfrom
feat/express-context-billing-client

Conversation

@pyramation

Copy link
Copy Markdown
Contributor

Summary

Extracts billing operations (checkQuota, recordUsage, logInference) into a shared BillingClient in @constructive-io/express-context, eliminating duplication between agentic-server and graphile-llm.

Before: Both packages implemented identical SQL calls for billing quota checks and usage recording independently.

After: Single source of truth via ctx.useBilling():

// In any Express handler or Graphile plugin:
const billing = await ctx.useBilling();
if (billing) {
  const allowed = await billing.checkQuota('text-embedding-3-small');
  // ... do work ...
  await billing.recordUsage('text-embedding-3-small', tokenCount, metadata);
  await billing.logInference({ model, inputTokens, outputTokens, ... });
}

Key design decisions:

  • useBilling() is lazy + cached per request — only resolves billing/inferenceLog loaders on first call, returns same instance on subsequent calls
  • Returns null if billing_module not provisioned or no entity_id in JWT (graceful no-op)
  • graphile-llm adapts Graphile's 2-arg withPgClient(pgSettings, fn) to the 1-arg pattern via billingClientFromCtx() helper
  • agentic-server/src/billing.ts deleted entirely — router calls ctx.useBilling() directly

Relates to constructive-io/constructive-planning#1054

Link to Devin session: https://app.devin.ai/sessions/4a9f098c74fb4cb6a9b6868fcff321db
Requested by: @pyramation

- Add billing-client.ts with BillingClient interface (checkQuota, recordUsage, logInference)
- Add useBilling() to ConstructiveContext (lazy, cached per request)
- Refactor agentic-server to use ctx.useBilling() instead of local billing.ts
- Delete agentic-server/src/billing.ts (replaced by shared client)
- Refactor graphile-llm metering to delegate to shared BillingClient via adapter
- Both packages now share the same billing SQL logic from express-context

Closes constructive-io/constructive-planning#1054
@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@pyramation pyramation merged commit c9f7fe7 into main Jun 13, 2026
35 checks passed
@pyramation pyramation deleted the feat/express-context-billing-client branch June 13, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant