Files
skills/docs/api-stack/api/api-plugin-payment/src/error-codes/error-codes.md
2026-05-29 08:20:56 +01:00

3.4 KiB

error-codes

(no submodules)

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

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

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.