Skip to content

addon-stack/addon-pay

Repository files navigation

AddonPay

AddonPay is a pnpm and Nx monorepo for public packages that connect products to the AddonPay service.

Packages

packages/
├── addon-pay            # single public facade; Addon Bone-first entry point
└── @addon-pay/
    ├── client           # control-plane API client
    ├── extension        # extension transport and messaging
    ├── react            # React UI adapter
    └── sdk              # client runtime SDK

addon-pay is the package that most extension developers install and import. It provides the Addon Bone-first facade and composes the scoped implementation packages. The root package does not own platform, UI, browser, messaging, or low-level API-transport implementations.

Architecture

One facade, scoped implementations

The only unscoped package is addon-pay. Every implementation package is published under @addon-pay/*. This keeps the normal developer experience short without making the facade the home for every implementation.

addon-pay                                      public facade and Addon Bone-first experience
├── @addon-pay/sdk                             platform-neutral runtime SDK and AddonPay API access
├── @addon-pay/react                           React UI adapters
├── @addon-pay/extension                       non-Addon-Bone extension transport and messaging
├── @addon-pay/client                          server-only API client for service configuration
└── @addon-pay/{vite,rspack}-plugin            standalone build-tool integrations, when needed

The names above describe the intended public surface; packages are introduced only when their implementation begins.

@addon-pay/sdk is the source of truth for runtime data and operations: state, entitlements, offerings, paywall data, and checkout actions. UI adapters render and invoke that SDK; they do not create parallel paywall models, API clients, or payment rules. There is no public @addon-pay/paywall package unless a future capability gives it a separate, non-duplicative responsibility.

Addon Bone: the default experience

The facade is designed first for Addon Bone. One configuration call installs the AddonPay plugin, service, and messaging binding for the extension:

// adnbn.config.ts
import addonPay from "addon-pay/plugin";
import {defineConfig} from "adnbn";

export default defineConfig({
    plugins: [addonPay("addon-id")],
});

Application code then always uses the same facade, without manually passing a client between contexts:

import addonPay from "addon-pay";

const canDownload = await addonPay.can("download_video");
import {Paywall} from "addon-pay/react";

export function Upgrade() {
    return <Paywall />;
}

The configured Addon Bone plugin provides the service and message proxy. addon-pay exposes the resulting runtime facade; the actual SDK client and framework integration remain scoped implementation details.

Other platforms

The same facade can be used without Addon Bone, but it must be explicitly configured with an appropriate platform transport. For a plain browser extension, that transport and the background-to-context messaging bridge belong to @addon-pay/extension. The facade may provide a short configuration API, but it must not embed browser messaging itself.

Framework UI adapters are optional. A project that only uses the runtime API imports addon-pay; a React project imports addon-pay/react. Future framework adapters follow the same scoped-package and facade-subpath model. Their framework dependencies remain peer dependencies of their scoped adapters.

The control-plane API is intentionally separate from the facade. @addon-pay/client is for server, CI, and dashboard tooling that configures products, plans, entitlements, and other service resources. It must never be bundled into an extension or receive extension-facing credentials.

Development

pnpm install
pnpm format:check
pnpm check
pnpm release:dry-run

Use Conventional Commits. The commit-msg hook and CI validate the format. Nx Release creates independent package releases: feat creates a minor release and fix creates a patch release. While a package is below 1.0.0, a breaking change also creates the next minor release, so 0.1.0 becomes 0.2.0, not 1.0.0.

Release model

Conventional Commits merge into main through pull requests and accumulate until a maintainer starts the Release workflow manually from main in GitHub Actions. The workflow validates the workspace, runs nx release, creates the version commit and tags, writes per-package GitHub Releases, and publishes only changed release packages. It writes to GitHub through the repository-only addon-stack-addon-pay-release GitHub App, while npm Trusted Publishing supplies short-lived OIDC credentials for publishing with provenance.

Always start the workflow from main; it rejects any other branch. Nx Release considers all unreleased Conventional Commits since the previous package tag, so several fixes can be published together in one patch release and a feat in the same package produces one minor release.

First publication for a new package

Each new public package needs one manual bootstrap publication at 0.0.1 with npm 2FA. Commit the package scaffold, create its matching baseline tag, and configure npm Trusted Publisher for addon-stack/addon-pay and .github/workflows/release.yml. Afterwards, do not manually change versions, create release tags, or publish that package. Nx Release and the GitHub Actions workflow are the release authority.

About

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Contributors