Skip to content
Paykit
Esc
↑↓navigate↵open⌘Jpreview
On this page

CatalogGuard

Exports `CatalogGuard`, `CatalogGuardLive`.

Source: packages/paykit/src/CatalogGuard.ts

CatalogGuard

Kind: Primitive

The guard that keeps the log honest about money. A Subscribe, ChangeTier, StartTrial or ChangePlans carries the allowances and the price it will record, because decide is pure and cannot look them up. A caller that omits the price, or sends allowances its tier does not grant, is refused with CatalogMismatch instead of writing a standing that can never be reconciled against an invoice. A plan set is judged move by move, and a cancellation’s fallback is judged like the plan it moves to.

A plan the catalog declares with custom: true is the one exception, and it is the catalogue’s choice rather than the caller’s (ADR 0041): its grants are a default, so a bespoke set is accepted when every item is one the catalog could have declared for that plan. Its price may likewise be the negotiated price the command states, because a custom plan is where a deployment opted into deals the catalog cannot enumerate (ADR 0042 §3). The credit terms are still compared exactly for a custom plan, so a bespoke deal changes what a customer may use and pay, never the pool or the rates the deployment’s catalog states.

A catalog-owning sender — Paykit.Subscribe, the webhook translator — builds the command from CatalogService and never needs this guard. It exists for the surfaces where the caller is not the catalog’s owner: HTTP, an MCP tool, a CLI.

Guarding a catalog-derived command

export class Subscribe extends Domain.Command("Subscribe", {
  target: AccountId,
  input: { tier: Schema.String, allowances: Allowances, price: Schema.optionalKey(Price) },
  events: [SubscriptionActivated],
  rejects: [PlanNotInCatalog, CurrencyMismatch, CatalogMismatch],
  middleware: [Session, CatalogGuard],
}) {}

CatalogGuardLive

Kind: Layer

The guard’s Layer: it reads the catalog the deployment validated and refuses what disagrees with it, whether the command carries one plan or a plan set.

Was this page helpful?