3.4 KiB
error-codes — SAND_PERM.* registry
(no submodules)
Purpose
This module owns the stable error-code registry for the
@suaveplan/api-sandbox-permissions package. Every deny path raised by
PermissionChecker or BudgetTracker surfaces as a
SandboxPermissionError carrying a code from SAND_PERM_CODES. The
namespace is pinned at module-import time so consumers can match either
structurally (instanceof SandboxPermissionError) or by stable string
constant (error.code === SAND_PERM_CODES.DENIED).
Pinning the registry in a leaf module that depends only on
@suaveplan/error keeps the deny-code surface tree-shakeable: a host
that only consumes the budget tracker pulls one code, not the whole
package, and avoids the OTel metric package on cold paths.
Features
SAND_PERM_CODES.DENIED("SAND_PERM.DENIED") — raised by everyPermissionChecker.check*deny return that the caller chooses to surface as a thrown error.SAND_PERM_CODES.BUDGET_EXCEEDED("SAND_PERM.BUDGET_EXCEEDED") — raised byBudgetTracker.tick()when any ofcpuPercent,memoryMb, orwallClockMsis exceeded.SandboxPermissionCodediscriminated string union.SandboxPermissionErrortyped subclass ofSuaveplanErrorwith pre-setname = "SandboxPermissionError"for stack-trace clarity.
Usage: Basic
import {
SAND_PERM_CODES,
SandboxPermissionError,
} from "@suaveplan/api-sandbox-permissions/error-codes";
try {
// call into the checker
} catch (err) {
if (err instanceof SandboxPermissionError) {
if (err.code === SAND_PERM_CODES.DENIED) {
// map to PERMISSION_DENIED inside the plugin
}
}
}
Usage: Advanced
import {
SAND_PERM_CODES,
SandboxPermissionError,
} from "@suaveplan/api-sandbox-permissions/error-codes";
function reraiseDeny(capability: string, reason: string): never {
throw new SandboxPermissionError(
SAND_PERM_CODES.DENIED,
`sandbox permission denied for capability "${capability}"`,
{ context: { capability, reason } }
);
}
The constructor signature mirrors SuaveplanError, so
{ cause, traceId, clock, context } are all supported. The
context object is what the wire boundary serialises as
details — it MUST stay redaction-safe (no paths, no hosts, no
secret names), exactly the { capability, reason } envelope
documented in the conformance spec.
API Reference
SAND_PERM_CODES: { readonly DENIED: "SAND_PERM.DENIED"; readonly BUDGET_EXCEEDED: "SAND_PERM.BUDGET_EXCEEDED" }SandboxPermissionCode = "SAND_PERM.DENIED" | "SAND_PERM.BUDGET_EXCEEDED"class SandboxPermissionError extends SuaveplanError<SandboxPermissionCode>constructor(code, message, options?)— accepts{ context, cause, traceId, clock }.
Implementation Notes
The registry uses defineCodes rather than a hand-rolled object literal
so the union type is inferred from the as const tuple of reasons. This
is the same pattern as @suaveplan/api-host's HOST_CODES /
PLUGIN_CODES etc. — every host-stack package collapses its codes to a
single defineCodes call so adding a reason is one-line and the type
flows through the rest of the package automatically.
No OTel or zod imports here on purpose — the registry must compile
even when the rest of the package is tree-shaken out. The instrument
descriptors and Zod ingestion validators live in their own
sub-modules.