Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions .changeset/billing-lifecycle-mechanics.md

This file was deleted.

11 changes: 0 additions & 11 deletions .changeset/cancel-at-period-end.md

This file was deleted.

10 changes: 0 additions & 10 deletions .changeset/dodo-brand-webhooks.md

This file was deleted.

5 changes: 0 additions & 5 deletions .changeset/fake-provider-name.md

This file was deleted.

22 changes: 0 additions & 22 deletions .changeset/lemon-squeezy-adapter.md

This file was deleted.

10 changes: 0 additions & 10 deletions .changeset/platform-billing-adapters.md

This file was deleted.

13 changes: 0 additions & 13 deletions .changeset/replace-open-checkout.md

This file was deleted.

63 changes: 63 additions & 0 deletions packages/billing/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,68 @@
# @codelitdev/billing

## 0.4.0

### Minor Changes

- 7b4a9ad: The engine now owns the lifecycle mechanics that products re-implemented (ADR 0011).

- `runReconciliationBatch` first queues stuck checkouts, interrupted plan changes, and subscriptions not reconciled recently. Thresholds are set with `createBilling({ reconciliation })`; pass `discover: false` to skip.
- A cancellation scheduled for the period end stops counting as paid once `paidThroughAt` passes. `commercialState` re-checks the clock, `runDeadlineBatch` releases the subscription and queues a reconciliation, and `startCheckout` releases a lapsed entitlement itself.
- `commercialState(entityId, { transaction })` reads inside the caller's transaction; the Drizzle store locks the rows it reads.
- `cancel`, `resumeCancellation`, and `startPlanChange` read the subscription back from the provider, so read models update before the webhook arrives.
- `billing.store` is internal.

**Product changes for this release**

- Remove product sweeps that query billing tables to queue reconciliation, and product expiry checks for paid access.
- Decide paid access from `commercialState`, inside your transaction when you reserve quota, instead of copying it into product tables or reading billing tables.
- Stop reading or writing billing state through `billing.store`.
- Custom `BillingStore` implementations must add `listUnreconciledSubscriptions`, `listStuckCreatingCheckouts`, `listStuckPlanChanges`, and `runInTransaction`.
- 7b4a9ad: Cancelling a subscription now keeps it active until the end of the paid period (ADR 0010). Previously the Dodo adapter ended it immediately, so the customer lost the time they had paid for. `commercialState` reports `cancelAtPeriodEnd: true` and `paidThroughAt` while a cancellation is scheduled, and the new `resumeCancellation` clears it. While a worker is sending a retried cancellation, `resumeCancellation` fails with a retryable `operation_conflicted`, so the cancellation cannot land after the resume.

**Product changes for this release**

- Show the end date from `commercialState().paidThroughAt` when `cancelAtPeriodEnd` is true, and offer to resume.
- Resume with `billing.resumeCancellation({ grant, entity, payer })`, using a `cancellation` grant. Do not start a new checkout while the subscription is still active.
- Custom provider adapters must implement `resumeSubscription`, and `cancelSubscription` must schedule the cancellation at period end.
- 7b4a9ad: `createDodoBillingProvider` accepts an optional `brandId` (ADR 0009). When products share one Dodo business, Dodo sends every event to every webhook endpoint. With `brandId` set, a verified webhook whose `brand_id` names another brand is stored as `ignored` instead of being processed and quarantined. Webhooks without a `brand_id` are processed as before.

**Product changes for this release**

- Create the product's Dodo products under its own Dodo brand.
- Pass that brand's ID as `brandId`, for example from a `DODO_BRAND_ID` environment variable.
- 7b4a9ad: Add a Lemon Squeezy provider adapter and subscription adoption (ADR 0014).

- `@codelitdev/billing/providers/lemonsqueezy` exports `createLemonSqueezyBillingProvider({ apiKey, storeId, webhookSecrets })`. Catalog offers use Lemon Squeezy variant IDs. Webhooks from other stores are stored as `ignored`. A checkout offers only the chosen variant, so the buyer cannot switch plans on the Lemon Squeezy page.
- `adoptProviderSubscription` (engine and `createOperations`) takes over a subscription created outside the engine, such as one started with the provider before the product used this package. The subscription's product must be in the active catalog revision.
- `commercialState` reports the `provider` holding the paid subscription.
- `resumeCancellation` accepts a subscription whose status is `cancelled` while its cancellation is only scheduled, which is how Lemon Squeezy reports it until the period ends.
- Providers can declare `checkoutAssignsCustomer`. For those, the first subscription from a payer's checkout moves the payer's customer record to the customer the provider chose. Lemon Squeezy declares it, because its checkout can create a new customer.
- Providers can declare `intervalChangesBillImmediately`. For those, `startPlanChange` with `do_not_bill` to another billing interval fails with `plan_change_not_supported` before the provider is called. Lemon Squeezy declares it, because such a change restarts and bills the period.
- Providers can declare `immediatePlanChangesOnly`. For those, `startPlanChange` with `effectiveAt: "next_billing_date"` fails with `plan_change_not_supported` before an attempt is created. Lemon Squeezy declares it.
- Plan changes back to an offer used before on the same subscription no longer fail with a database unique-key error. Each attempt now has its own idempotency key.
- Requesting a catalog revision number that another provider already uses now fails with `catalog_revision_used_by_another_provider` instead of a database unique-key error.

**Product changes for this release**

- To switch to Lemon Squeezy, compose its adapter, set `checkoutProvider: "lemonsqueezy"`, use variant IDs in the catalog, and mount its webhook at `/webhooks/billing/lemonsqueezy`.
- Turn off plan changes in the Lemon Squeezy store's customer portal settings. The engine quarantines a plan change it did not start.
- Adopt existing provider subscriptions once with `adoptProviderSubscription` after the catalog is verified.
- Code that builds `CommercialBillingState` objects, such as test fixtures, must add `provider`.
- 7b4a9ad: A payer can switch offers while a checkout is open.

- `startCheckout` for another offer, such as yearly after monthly, now replaces the payer's own open checkout instead of failing with `checkout_pending` until it expires. The old checkout becomes `abandoned`. If it is paid anyway, it becomes `conflicted`; it grants access when nothing else does, and otherwise the second subscription is quarantined. Another payer's open checkout still returns `checkout_pending`.
- An expired checkout for another offer or payer is no longer reopened for the new request.
- `CreateCheckoutInput` gains an optional `expiresAt`. The Lemon Squeezy adapter sends it as the checkout's `expires_at`, so the old page stops working when the attempt expires. Dodo checkout sessions take no expiry.

**Product changes for this release**

- None required. A product that showed a message for `checkout_pending` when a person switched intervals can keep it for the other-payer case.

### Patch Changes

- 7b4a9ad: `FakeBillingProvider` takes an optional `provider` name, so tests can compose two providers. A new test covers serving subscriptions on one provider after checkout moves to another.

## 0.3.0

No changes in this release.
Expand Down
2 changes: 1 addition & 1 deletion packages/billing/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/billing",
"version": "0.3.0",
"version": "0.4.0",
"description": "Provider-neutral billing engine for CodeLit products",
"author": "CodeLit",
"type": "module",
Expand Down
4 changes: 4 additions & 0 deletions packages/design-system/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# @codelitdev/design-system

## 0.4.0

No changes in this release.

## 0.3.0

No changes in this release.
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/design-system",
"version": "0.3.0",
"version": "0.4.0",
"description": "Shared CodeLit design tokens, Tailwind preset, and React primitives for CourseLit, MediaLit, SendLit, and FrontLit.",
"license": "Apache-2.0",
"author": "CodeLit",
Expand Down
7 changes: 7 additions & 0 deletions packages/mcp-server-kit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @codelitdev/mcp-server-kit

## 0.4.0

### Patch Changes

- Updated dependencies [7b4a9ad]
- @codelitdev/platform@0.4.0

## 0.3.0

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/mcp-server-kit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/mcp-server-kit",
"version": "0.3.0",
"version": "0.4.0",
"description": "MCP transport, session, auth hooks, and error mapping for CodeLit products",
"author": "CodeLit",
"type": "module",
Expand Down Expand Up @@ -37,7 +37,7 @@
"zod": "^3.25.76"
},
"peerDependencies": {
"@codelitdev/platform": ">=0.3.0"
"@codelitdev/platform": ">=0.4.0"
},
"devDependencies": {
"@codelitdev/platform": "workspace:*",
Expand Down
4 changes: 4 additions & 0 deletions packages/oauth-server-kit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# @codelitdev/oauth-server-kit

## 0.4.0

No changes in this release.

## 0.3.0

No changes in this release.
Expand Down
2 changes: 1 addition & 1 deletion packages/oauth-server-kit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/oauth-server-kit",
"version": "0.3.0",
"version": "0.4.0",
"description": "Lean Better Auth OAuth authentication framework for web, mobile, REST, and MCP surfaces.",
"author": "CodeLit",
"license": "MIT",
Expand Down
4 changes: 4 additions & 0 deletions packages/observability/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# @codelitdev/observability

## 0.4.0

No changes in this release.

## 0.3.0

No changes in this release.
Expand Down
2 changes: 1 addition & 1 deletion packages/observability/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/observability",
"version": "0.3.0",
"version": "0.4.0",
"description": "Provider-neutral logging and optional telemetry for CodeLit products",
"author": "CodeLit",
"type": "module",
Expand Down
4 changes: 4 additions & 0 deletions packages/platform-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# @codelitdev/platform-cli

## 0.4.0

No changes in this release.

## 0.3.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/platform-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/platform-cli",
"version": "0.3.0",
"version": "0.4.0",
"description": "Create, check, and sync CodeLit Platform products",
"author": "CodeLit",
"type": "module",
Expand Down
16 changes: 8 additions & 8 deletions packages/platform-cli/src/preset.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,42 @@
},
"packages": {
"@codelitdev/platform": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.0 <2",
"minimumSecure": "0.1.0-alpha.0"
},
"@codelitdev/observability": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.0 <2",
"minimumSecure": "0.1.0-alpha.0"
},
"@codelitdev/mcp-server-kit": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.0 <2",
"minimumSecure": "0.1.0-alpha.0"
},
"@codelitdev/platform-conformance": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.0 <2",
"minimumSecure": "0.1.0-alpha.0"
},
"@codelitdev/platform-cli": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.0 <2",
"minimumSecure": "0.1.0-alpha.0"
},
"@codelitdev/billing": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.4 <1",
"minimumSecure": "0.1.0-alpha.4"
},
"@codelitdev/oauth-server-kit": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.2 <1",
"minimumSecure": "0.1.0-alpha.2"
},
"@codelitdev/design-system": {
"recommended": "0.3.0",
"recommended": "0.4.0",
"supported": ">=0.1.0-alpha.7 <1",
"minimumSecure": "0.1.0-alpha.7"
}
Expand Down
7 changes: 7 additions & 0 deletions packages/platform-conformance/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @codelitdev/platform-conformance

## 0.4.0

### Patch Changes

- Updated dependencies [7b4a9ad]
- @codelitdev/platform@0.4.0

## 0.3.0

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/platform-conformance/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codelitdev/platform-conformance",
"version": "0.3.0",
"version": "0.4.0",
"description": "Shared HTTP conformance suites for CodeLit Platform products",
"author": "CodeLit",
"type": "module",
Expand Down Expand Up @@ -37,7 +37,7 @@
"tag": "latest"
},
"peerDependencies": {
"@codelitdev/platform": ">=0.3.0"
"@codelitdev/platform": ">=0.4.0"
},
"devDependencies": {
"@codelitdev/platform": "workspace:*",
Expand Down
Loading
Loading