framework
NestJS
Connect portable Playstack capabilities to dependency injection, guards, decorators, request context, workers, and lifecycle hooks.
Synchronize subscription state, project purchased access into stable grants, and enforce capabilities without scattering plan-name checks through application code.
available
Keep a rebuildable local projection of provider-owned subscription state through idempotent webhooks and reconciliation.
available
Translate billing, registration, licence, or staff sources into independently replaceable boolean and numeric grants.
available
Resolve user or account grants behind NestJS guards while keeping authentication and entitlement policy separate.
available
Project full trial access and a smaller read-only grace set with immutable per-account eligibility.
available
Inspect current state and revision history, surface scheduled changes, and reconcile from provider truth.
framework
Connect portable Playstack capabilities to dependency injection, guards, decorators, request context, workers, and lifecycle hooks.
integration
Persist Playstack capabilities through explicit application-owned Prisma clients, transactions, and managed schema fragments.
integration
Create hosted subscription and one-time checkout, then reconcile verified Stripe events into separate billing and payment projections.
Billing answers what an account bought. Entitlements answer what a subject may use now. Keeping that boundary explicit means application routes ask for packages.pro or projects.maximum, not whether a subscription happens to be named pro.
import { defineEntitlements } from '@playstack/entitlements'
export const entitlements = defineEntitlements({
'packages.plus': { kind: 'boolean' },
'packages.pro': { kind: 'boolean' },
'projects.maximum': { kind: 'number' },
})The billing projection can replace only the grants sourced from one subscription. Manual access, registration benefits, and future licence grants remain isolated and survive an unrelated billing update.
Checkout redirects do not grant access. The billing service consumes verified provider events, projects their latest object state idempotently, and then replaces the matching entitlement source.
await billing.consumeWebhook(verifiedEvent)
const access = await entitlementService.resolve({
type: 'account',
id: request.account.id,
})
access.require('packages.pro')Reconciliation uses the same path, so replaying current subscription state should be a no-op rather than a second implementation.
Each provider event carries its immutable ID and occurrence time. Exact retries and stale deliveries cannot overwrite newer state, while accepted projections append revision history. Invoice payment, payment failure, cancellation, resumption, scheduled plan changes, and trial-ending events are normalized for notification and audit consumers.
Billing requires an explicit entitlement consistency mode. A shared database
can project grants on the billing transaction; separate stores use durable,
idempotent eventual projection. resolveMany() and snapshot() support account
settings and administration views without one database read per entitlement.