Initial Commit
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
# error-codes
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the stable `GRAPHQL.*` error-code registry for `@suaveplan/api-plugin-graphql` and the `GraphQLError` class consumers catch and discriminate on. Every failure path inside the package — Zod validation at `defineGraphQLPlugin`, role enforcement in `requireRoles`, argument validation in `validateArgs`, schema lookups, and duplicate-resolver registration — throws a `GraphQLError` carrying one of these codes.
|
||||
|
||||
Upstream threw bare `Error(...)` strings; policy (CLAUDE.md rules + AGENTS.md §13) requires typed errors extending `SuaveplanError`. This file replaces every upstream `throw new Error("Authentication required")` etc. with `throw new GraphQLError(GRAPHQL_CODES.UNAUTHENTICATED, ...)` so consumers can branch on `error.code` instead of `error.message`.
|
||||
|
||||
## Features
|
||||
|
||||
- 6 stable codes registered via `defineCodes("GRAPHQL", [...])`.
|
||||
- `GraphQLError extends SuaveplanError<GraphQLErrorCode>` — `instanceof GraphQLError` narrows `code`.
|
||||
- Optional `SuaveplanErrorOptions` (`cause`, `context`, `redact`) on every constructor call.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { GraphQLError, GRAPHQL_CODES } from "@suaveplan/api-plugin-graphql";
|
||||
|
||||
try {
|
||||
plugin = defineGraphQLPlugin({ name: 1 as unknown as string, ...rest });
|
||||
} catch (e) {
|
||||
if (e instanceof GraphQLError && e.code === GRAPHQL_CODES.INVALID_INPUT) {
|
||||
console.error("invalid options", e.cause);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { GraphQLError, GRAPHQL_CODES } from "@suaveplan/api-plugin-graphql";
|
||||
|
||||
function safeAddResolver(c: ResolverComposer, t: string, f: string, fn: ResolverFn) {
|
||||
if (c.hasResolver(t, f)) {
|
||||
throw new GraphQLError(
|
||||
GRAPHQL_CODES.DUPLICATE_RESOLVER,
|
||||
`resolver already exists for ${t}.${f}`,
|
||||
{ context: { typeName: t, fieldName: f } },
|
||||
);
|
||||
}
|
||||
c.addResolver(t, f, fn);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Notes |
|
||||
|---|---|---|
|
||||
| `GRAPHQL_CODES` | const | `{ UNAUTHENTICATED, INSUFFICIENT_ROLE, VALIDATION_FAILED, INVALID_INPUT, TYPE_NOT_FOUND, DUPLICATE_RESOLVER }` — each value is the string `"GRAPHQL.<NAME>"`. |
|
||||
| `GraphQLErrorCode` | type | Union of the six string literal codes. |
|
||||
| `GraphQLError` | class | Extends `SuaveplanError<GraphQLErrorCode>`. Constructor: `(code, message, options?)`. `error.graphqlCode` mirrors `error.code`. |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`defineCodes` (from `@suaveplan/error`) returns a frozen const record whose value type is preserved through `(typeof GRAPHQL_CODES)[keyof typeof GRAPHQL_CODES]`. This means `error.code` is the literal union, not `string`.
|
||||
|
||||
The base class constructor in `@suaveplan/error` is `protected`; we widen it to `public` so callers can construct errors directly when wrapping third-party failures (e.g. mapping a foreign cause). `graphqlCode` is a strongly-typed mirror of `.code` that survives transport boundaries even if a consumer narrows on `instanceof Error` instead of `instanceof GraphQLError`.
|
||||
|
||||
Every code in `GRAPHQL_CODES` is thrown from at least one production code path; the `src/api-plugin-graphql.spec-conformance.test.ts` file pins this invariant.
|
||||
Reference in New Issue
Block a user