first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user