Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,84 @@
# `OPENAPI_UI_SCALAR.*` error-code registry
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
This module owns the stable error-code registry for the
`@suaveplan/api-openapi-ui-scalar` package. The registry is built via
`defineCodes` so every key projects to a frozen `OPENAPI_UI_SCALAR.<NAME>`
string the rest of the suite (logger, error bus, OTel attributes) can
discriminate on. `OpenapiUiScalarError` extends the shared
`SuaveplanError` base so call sites can branch on
`instanceof OpenapiUiScalarError` or — more durably — on `error.code`.
Each code maps to a single production throw site that is exercised in the
test suite by a real failure path, not a manual rethrow.
## Features
- Frozen `OPENAPI_UI_SCALAR_CODES` registry with three stable keys:
`ASSETS_MISSING`, `INVALID_OPTIONS`, `ASSET_NOT_REGISTERED`.
- Typed `OpenapiUiScalarCode` union derived from the registry values.
- `OpenapiUiScalarError` subclass carrying the typed `code` + `scalarCode`
twin so consumers can pattern-match without a runtime `as` cast.
- Cause chain + context bag honoured via the shared base — useful for
wrapping the underlying `ZodError` on `INVALID_OPTIONS`.
## Usage: Basic
```ts
import {
OPENAPI_UI_SCALAR_CODES,
OpenapiUiScalarError,
} from "@suaveplan/api-openapi-ui-scalar/error-codes";
throw new OpenapiUiScalarError(
OPENAPI_UI_SCALAR_CODES.ASSETS_MISSING,
"Scalar bundled asset is not present"
);
```
## Usage: Advanced
```ts
import {
OPENAPI_UI_SCALAR_CODES,
OpenapiUiScalarError,
} from "@suaveplan/api-openapi-ui-scalar/error-codes";
try {
parseHostConfig(input);
} catch (err) {
if (
err instanceof OpenapiUiScalarError &&
err.code === OPENAPI_UI_SCALAR_CODES.INVALID_OPTIONS
) {
// Surface the underlying ZodError issues to the operator console.
logger.error("Scalar UI host config rejected", {
cause: err.cause,
issues: err.context?.issues,
});
return;
}
throw err;
}
```
## API Reference
- `OPENAPI_UI_SCALAR_CODES` — frozen object with the three code keys.
- `OpenapiUiScalarCode` — typed union over the code values.
- `OpenapiUiScalarError` — `SuaveplanError<OpenapiUiScalarCode>` subclass.
Constructor signature: `(code, message, options?)`. `options` carries
`cause` and `context` per the shared error contract.
## Implementation Notes
The registry is intentionally closed — adding a new code requires an
OpenSpec change so the audit + dashboards (`openapi_ui_scalar.errors_total`
labels) get refreshed in lockstep. The `error-codes.test.ts` conformance
file walks every registry entry and asserts a corresponding production
throw site lives in the package, so dead codes can never accumulate.

View File

@@ -0,0 +1,42 @@
import { describe, expect, it } from "@suaveplan/testing/runner";
import {
OPENAPI_UI_SCALAR_CODES,
OpenapiUiScalarError,
} from "./error-codes.js";
describe("OPENAPI_UI_SCALAR codes", () => {
it("exposes the three stable codes", { timeout: 5000 }, () => {
expect(OPENAPI_UI_SCALAR_CODES.ASSETS_MISSING).toBe(
"OPENAPI_UI_SCALAR.ASSETS_MISSING"
);
expect(OPENAPI_UI_SCALAR_CODES.INVALID_OPTIONS).toBe(
"OPENAPI_UI_SCALAR.INVALID_OPTIONS"
);
expect(OPENAPI_UI_SCALAR_CODES.ASSET_NOT_REGISTERED).toBe(
"OPENAPI_UI_SCALAR.ASSET_NOT_REGISTERED"
);
});
it("error carries the code in both fields", { timeout: 5000 }, () => {
const err = new OpenapiUiScalarError(
OPENAPI_UI_SCALAR_CODES.ASSETS_MISSING,
"missing",
{ context: { mode: "bundled" } }
);
expect(err).toBeInstanceOf(OpenapiUiScalarError);
expect(err.code).toBe(OPENAPI_UI_SCALAR_CODES.ASSETS_MISSING);
expect(err.scalarCode).toBe(OPENAPI_UI_SCALAR_CODES.ASSETS_MISSING);
expect(err.name).toBe("OpenapiUiScalarError");
expect(err.context?.mode).toBe("bundled");
});
it("supports the cause chain on the shared base", { timeout: 5000 }, () => {
const root = new Error("root");
const err = new OpenapiUiScalarError(
OPENAPI_UI_SCALAR_CODES.INVALID_OPTIONS,
"boom",
{ cause: root }
);
expect(err.cause).toBe(root);
});
});

View File

@@ -0,0 +1,47 @@
import type { SuaveplanErrorOptions } from "@suaveplan/error";
import { defineCodes, SuaveplanError } from "@suaveplan/error";
/**
* Frozen `OPENAPI_UI_SCALAR.*` error-code registry for the Scalar UI
* adapter. Every code listed here is thrown by a production path in this
* package and verified by `error-codes.test.ts` walking the registry.
*
* - `ASSETS_MISSING` — `host.openapi.uiAssets = "bundled"` was selected
* but no bundled Scalar runtime exists under `dist/assets/`. Raised at
* handler construction so an air-gapped host fails fast at boot rather
* than at first request.
* - `INVALID_OPTIONS` — the `ScalarUiOptions` Zod schema rejected the
* caller-supplied configuration. Wrapped on top of the underlying
* `ZodError` (`.cause`) so callers can inspect the exact field failure.
* - `ASSET_NOT_REGISTERED` — internal asset lookup mis-fire for the
* bundled-asset registry; surfaced when a callsite asks for an asset
* name not present in `SCALAR_ASSETS`.
*/
export const OPENAPI_UI_SCALAR_CODES = defineCodes("OPENAPI_UI_SCALAR", [
"ASSETS_MISSING",
"INVALID_OPTIONS",
"ASSET_NOT_REGISTERED",
] as const);
/** Union of every code resolved through {@link OPENAPI_UI_SCALAR_CODES}. */
export type OpenapiUiScalarCode =
(typeof OPENAPI_UI_SCALAR_CODES)[keyof typeof OPENAPI_UI_SCALAR_CODES];
/**
* Concrete error class for the api-openapi-ui-scalar package. Extends
* {@link SuaveplanError} so callers can discriminate via
* `error instanceof OpenapiUiScalarError` or the stable `error.code`.
*/
export class OpenapiUiScalarError extends SuaveplanError<OpenapiUiScalarCode> {
public readonly scalarCode: OpenapiUiScalarCode;
public constructor(
code: OpenapiUiScalarCode,
message: string,
options?: SuaveplanErrorOptions
) {
super(code, message, options);
this.name = "OpenapiUiScalarError";
this.scalarCode = code;
}
}

View File

@@ -0,0 +1,5 @@
export {
OPENAPI_UI_SCALAR_CODES,
type OpenapiUiScalarCode,
OpenapiUiScalarError,
} from "./error-codes.js";