first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
# error-codes
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Stable error-code registry for `@suaveplan/api-plugin-payment`. Every failure path in the plugin raises a `PaymentPluginError` that carries one of 15 `PAYMENT_PLUGIN.*` codes. The registry gives consumers a small, well-documented enum to programmatically branch on without inspecting human-readable messages — exactly the contract every other `@suaveplan/api-plugin-*` package follows.
The module also exports the `PaymentPluginError` class, which extends `SuaveplanError<PaymentPluginErrorCode>` so `instanceof PaymentPluginError` narrows `code` to the typed enum at the call site. The class preserves the supplied code on the discriminant `pluginCode` field for compatibility with downstream error handlers that match on a package-specific property name (the auth plugin uses `authCode`, the openapi plugin uses `openapiCode` — this package uses `pluginCode`).
## Features
- 15 namespaced codes under `PAYMENT_PLUGIN.` covering input validation, ownership/anti-enumeration, provider failures, webhook signature/timestamp, idempotency conflict, state-machine, amount/currency mismatch, refund-exceeds-captured, configuration, and service-registry plumbing.
- Typed `PaymentPluginErrorContext` carrying `statusCode`, `intentId`, `ownerId`, `missing[]`, `prefix`, `currency`, `expectedCurrency` for diagnostic plumbing.
- `PaymentPluginError` discriminant class with `pluginCode` and the standard `SuaveplanError` cause-chain, `toJSON`, `toProblemJSON`, and OTel span-event hooks.
## Usage: Basic
```ts
import {
PAYMENT_PLUGIN_CODES,
PaymentPluginError,
} from "@suaveplan/api-plugin-payment";
throw new PaymentPluginError(
PAYMENT_PLUGIN_CODES.NOT_FOUND,
'Payment intent "abc" not found',
{ context: { statusCode: 404, intentId: "abc" } }
);
```
## Usage: Advanced
```ts
try {
await service.captureIntent({ id, ownerId, amount });
} catch (err) {
if (err instanceof PaymentPluginError) {
switch (err.pluginCode) {
case PAYMENT_PLUGIN_CODES.NOT_FOUND:
return c.json({ error: "not_found" }, 404);
case PAYMENT_PLUGIN_CODES.CURRENCY_MISMATCH:
case PAYMENT_PLUGIN_CODES.AMOUNT_MISMATCH:
return c.json({ error: err.pluginCode }, 422);
case PAYMENT_PLUGIN_CODES.IDEMPOTENCY_CONFLICT:
return c.json({ error: "conflict" }, 409);
}
}
throw err;
}
```
## API Reference
- `PAYMENT_PLUGIN_CODES` — `defineCodes("PAYMENT_PLUGIN", [...])` const-object.
- `PaymentPluginErrorCode` — union of the 15 `PAYMENT_PLUGIN.*` strings.
- `PaymentPluginErrorContext` — optional discriminant fields carried alongside the base `SuaveplanError` context.
- `PaymentPluginError extends SuaveplanError<PaymentPluginErrorCode>` — `pluginCode: PaymentPluginErrorCode`.
## Implementation Notes
The 15-code count matches the proposal's spec delta. Removing a code (because no production call site currently uses it) is banned by `AGENTS.md §2c` — codes are part of the public API contract and unused-looking codes get wired into call sites that didn't exist yet (e.g. `PROVIDER_NOT_CONFIGURED` covers a programmatic mis-wire pattern callers do hit during initial integration). The conformance test in `api-plugin-payment.spec-conformance.test.ts` proves every code is reachable from a non-test call site.