Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# @suaveplan/payment-providers - Slim universal foundation for the @suaveplan/payment-provider-* sibling packages. Ships ProviderRegistry, definePaymentProvider factory, shared httpRequest/composeAbortSignal helpers, FetchLike, the ApiKeyConfig / OAuthConfig / MerchantKeyConfig / HttpOptions / ProviderResponse types, and the PAYMENT_PROVIDER_CODES + PaymentProviderError error model. Concrete Stripe / PayPal / Square / Mollie / Adyen adapters ship as separate @suaveplan/payment-provider-<name> packages that depend on this foundation.
|
||||
|
||||
Universal **foundation** for the `@suaveplan/payment-provider-*`
|
||||
sibling-package family. This package ships only the shared abstractions
|
||||
every concrete adapter needs — the `ProviderRegistry`, the
|
||||
`definePaymentProvider` factory, the `httpRequest` +
|
||||
`composeAbortSignal` HTTP helpers, the `FetchLike` type, the shared
|
||||
config shapes (`ApiKeyConfig`, `OAuthConfig`, `MerchantKeyConfig`,
|
||||
`HttpOptions`, `ProviderResponse`), and the `PAYMENT_PROVIDER_CODES`
|
||||
registry + `PaymentProviderError` class. Concrete adapters
|
||||
(Stripe, PayPal, Square, Mollie, Adyen) live in **sibling packages** so
|
||||
consumers pay only for the providers they install.
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
## Documentation tree
|
||||
|
||||
- [error-codes](./src/error-codes/error-codes.md) — Stable error registry and typed error class for `@suaveplan/payment-providers`. Every production failure path — non-ok…
|
||||
- [error-codes](./src/error-codes/error-codes.md) — Stable error registry and typed error class for `@suaveplan/payment-providers`. Every production failure path — non-ok…
|
||||
- [http](./src/http/http.md) — Universal HTTP helper used by every provider to issue typed, cancellable JSON requests. The helper is a thin wrapper ov…
|
||||
- [http](./src/http/http.md) — Universal HTTP helper used by every provider to issue typed, cancellable JSON requests. The helper is a thin wrapper ov…
|
||||
- [registry](./src/registry/registry.md) — Process-local, synchronous registry that indexes `PaymentProvider` instances (from `@suaveplan/payment`) by their `name…
|
||||
- [define](./src/registry/define.md) — Factory helper for sibling `@suaveplan/payment-provider-*` packages that want to expose a `PaymentProvider` (from `@sua…
|
||||
- [registry](./src/registry/registry.md) — Process-local, synchronous registry that indexes `PaymentProvider` instances (from `@suaveplan/payment`) by their `name…
|
||||
- [types](./src/types/provider.md) — Shared configuration interfaces and injectable seams consumed by every sibling `@suaveplan/payment-provider-*` adapter…
|
||||
- [provider](./src/types/provider.md) — Shared configuration interfaces and injectable seams consumed by every sibling `@suaveplan/payment-provider-*` adapter…
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
bun add @suaveplan/payment-providers @suaveplan/payment
|
||||
# plus one or more of:
|
||||
bun add @suaveplan/payment-provider-stripe
|
||||
bun add @suaveplan/payment-provider-paypal
|
||||
bun add @suaveplan/payment-provider-square
|
||||
bun add @suaveplan/payment-provider-mollie
|
||||
bun add @suaveplan/payment-provider-adyen
|
||||
```
|
||||
|
||||
## Quick start
|
||||
|
||||
```ts
|
||||
import { ProviderRegistry } from "@suaveplan/payment-providers";
|
||||
import { StripeProvider } from "@suaveplan/payment-provider-stripe";
|
||||
import { PaymentEngine } from "@suaveplan/payment";
|
||||
|
||||
const registry = new ProviderRegistry();
|
||||
registry.register(new StripeProvider({
|
||||
apiKey: process.env.STRIPE_SECRET_KEY ?? "",
|
||||
}));
|
||||
|
||||
const engine = new PaymentEngine({ provider: registry.get("stripe") });
|
||||
|
||||
const intent = await engine.createIntent({
|
||||
amount: { amount: 5000n, currency: "USD" },
|
||||
captureMethod: "automatic",
|
||||
});
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- **`ProviderRegistry`** — process-local, synchronous,
|
||||
insertion-ordered registry of `PaymentProvider` instances keyed by
|
||||
`name`; strict `get` with typed miss, duplicate-safe `register`,
|
||||
idempotent `unregister`, frozen `list()` snapshot
|
||||
- **`definePaymentProvider<TName>(spec)`** — factory that returns a
|
||||
frozen, literal-typed `PaymentProvider` for sibling packages that
|
||||
prefer a closure to a class
|
||||
- **`httpRequest<T>(options)`** — universal `FetchLike` wrapper with
|
||||
per-call timeout, JSON serialisation, custom-header passthrough,
|
||||
typed errors, empty-body handling, and external-`AbortSignal`
|
||||
composition
|
||||
- **`composeAbortSignal(internal, external?)`** — reusable
|
||||
abort-signal composer (extracted from `httpRequest` so sibling
|
||||
packages can compose their own out-of-band HTTP calls with
|
||||
caller-supplied cancellation)
|
||||
- **`PAYMENT_PROVIDER_CODES`** + **`PaymentProviderError`** — 6-code
|
||||
registry (`HTTP_ERROR`, `TIMEOUT`, `PARSE_ERROR`,
|
||||
`OAUTH_TOKEN_FAILURE`, `PROVIDER_NOT_REGISTERED`,
|
||||
`PROVIDER_ALREADY_REGISTERED`) with optional `provider` /
|
||||
`httpStatus` / `url` / `bodyExcerpt` discriminants
|
||||
- **Shared config shapes** — `ApiKeyConfig`, `OAuthConfig`,
|
||||
`MerchantKeyConfig`, `HttpOptions`, `ProviderResponse`,
|
||||
`ProviderCommonOptions`, plus `NowFn` / `RandomIdFn` /
|
||||
`Base64EncodeFn` injectable seams
|
||||
- **Universal tier** — zero Node, browser, React, or `node:crypto`
|
||||
imports; runs unchanged on Node, Bun, browsers, and Web Workers
|
||||
- **Tree-shakeable** — `sideEffects: false` plus per-feature subpath
|
||||
exports
|
||||
- **100% test coverage** (Istanbul) + 100% docs coverage (sibling
|
||||
`.md` per implementation file)
|
||||
|
||||
## Sibling provider packages
|
||||
|
||||
The five concrete provider adapters that used to ship in this package
|
||||
now live in dedicated sibling packages, each depending on this
|
||||
foundation:
|
||||
|
||||
- `@suaveplan/payment-provider-stripe` — `StripeProvider`
|
||||
- `@suaveplan/payment-provider-paypal` — `PayPalProvider`
|
||||
- `@suaveplan/payment-provider-square` — `SquareProvider` + the
|
||||
Square-specific `SquareConfig` type
|
||||
- `@suaveplan/payment-provider-mollie` — `MollieProvider`
|
||||
- `@suaveplan/payment-provider-adyen` — `AdyenProvider`
|
||||
|
||||
Install one or more alongside this foundation. Every sibling exports
|
||||
the same class name + `PaymentProvider`-interface contract as before
|
||||
the slim-down, so migration from a bundled import is a one-line
|
||||
package swap (see `## Migration` below).
|
||||
|
||||
## Migration
|
||||
|
||||
If you were importing a concrete provider from
|
||||
`@suaveplan/payment-providers`, switch to the matching sibling
|
||||
package. The class names are preserved verbatim:
|
||||
|
||||
```ts
|
||||
// Before
|
||||
import { StripeProvider } from "@suaveplan/payment-providers";
|
||||
|
||||
// After
|
||||
import { StripeProvider } from "@suaveplan/payment-provider-stripe";
|
||||
```
|
||||
|
||||
All shared types (`ApiKeyConfig`, `OAuthConfig`, `MerchantKeyConfig`,
|
||||
`HttpOptions`, `ProviderResponse`, `NowFn`, `RandomIdFn`,
|
||||
`Base64EncodeFn`), `httpRequest`, `composeAbortSignal`, the
|
||||
`PaymentProviderError` class, and the `PAYMENT_PROVIDER_CODES`
|
||||
registry continue to be exported from
|
||||
`@suaveplan/payment-providers` unchanged. The Square-specific
|
||||
`SquareConfig` type now ships with
|
||||
`@suaveplan/payment-provider-square`.
|
||||
|
||||
## Modules
|
||||
|
||||
- [`src/types/provider.md`](./src/types/provider.md) — `ApiKeyConfig`,
|
||||
`OAuthConfig`, `MerchantKeyConfig`, `HttpOptions`,
|
||||
`ProviderResponse`, plus `NowFn` / `RandomIdFn` / `Base64EncodeFn`
|
||||
- [`src/error-codes/error-codes.md`](./src/error-codes/error-codes.md) —
|
||||
`PAYMENT_PROVIDER_CODES`, `PaymentProviderError`, factories
|
||||
(`httpError`, `timeoutError`, `parseError`, `oauthTokenFailure`,
|
||||
`providerNotRegistered`, `providerAlreadyRegistered`)
|
||||
- [`src/http/http.md`](./src/http/http.md) — `httpRequest` +
|
||||
`composeAbortSignal` + `FetchLike`
|
||||
- [`src/registry/registry.md`](./src/registry/registry.md) —
|
||||
`ProviderRegistry`
|
||||
- [`src/registry/define.md`](./src/registry/define.md) —
|
||||
`definePaymentProvider` factory
|
||||
|
||||
## Building a custom provider
|
||||
|
||||
Sibling provider packages — and any consumer adding a non-standard
|
||||
provider — implement the `PaymentProvider` interface from
|
||||
`@suaveplan/payment` and use `httpRequest` from this foundation for
|
||||
every HTTP call:
|
||||
|
||||
```ts
|
||||
import {
|
||||
type ApiKeyConfig,
|
||||
httpRequest,
|
||||
PaymentProviderError,
|
||||
} from "@suaveplan/payment-providers";
|
||||
import type {
|
||||
CreatePaymentIntentInput,
|
||||
PaymentIntent,
|
||||
PaymentProvider,
|
||||
} from "@suaveplan/payment";
|
||||
|
||||
export class CustomProvider implements PaymentProvider {
|
||||
public readonly name = "custom";
|
||||
private readonly config: ApiKeyConfig;
|
||||
|
||||
public constructor(config: ApiKeyConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public async createIntent(
|
||||
input: CreatePaymentIntentInput
|
||||
): Promise<PaymentIntent> {
|
||||
const { data } = await httpRequest<{ id: string }>({
|
||||
method: "POST",
|
||||
url: `${this.config.baseUrl ?? "https://api.custom.com"}/intents`,
|
||||
headers: { "X-API-Key": this.config.apiKey },
|
||||
body: { amount: Number(input.amount.amount) },
|
||||
fetch: this.config.fetch,
|
||||
signal: this.config.signal,
|
||||
timeoutMs: this.config.timeoutMs,
|
||||
provider: this.name,
|
||||
});
|
||||
return mapToPaymentIntent(data);
|
||||
}
|
||||
// ...implement remaining PaymentProvider methods
|
||||
}
|
||||
|
||||
function mapToPaymentIntent(_raw: unknown): PaymentIntent {
|
||||
throw new PaymentProviderError(
|
||||
"PAYMENT_PROVIDER.PARSE_ERROR" as never,
|
||||
"implement mapping"
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- `@suaveplan/payment` — `PaymentEngine`, `WebhookVerifier`,
|
||||
`PaymentProvider` interface
|
||||
- `@suaveplan/money` — currency-aware arithmetic
|
||||
- `@suaveplan/error` — base error class + `defineCodes` registry helper
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
Reference in New Issue
Block a user