refactor(msg-bus): prefer explicit enum on AsyncAPI error
This commit is contained in:
@@ -1,14 +0,0 @@
|
||||
enum RtErrorCode {
|
||||
MINUS_32001 = -32001,
|
||||
MINUS_32002 = -32002,
|
||||
MINUS_32003 = -32003,
|
||||
MINUS_32004 = -32004,
|
||||
MINUS_32005 = -32005,
|
||||
MINUS_32006 = -32006,
|
||||
MINUS_32007 = -32007,
|
||||
MINUS_32603 = -32603,
|
||||
MINUS_32600 = -32600,
|
||||
MINUS_32601 = -32601,
|
||||
MINUS_32602 = -32602
|
||||
}
|
||||
export type { RtErrorCode as default };
|
||||
@@ -1,9 +1,8 @@
|
||||
import type RtErrorCode from './RtErrorCode';
|
||||
import type RtErrorMessage from './RtErrorMessage';
|
||||
// AUTO-GENERATED — do not edit by hand.
|
||||
// Regenerate with `just asyncapi-ts`.
|
||||
interface RtErrorObject {
|
||||
code: RtErrorCode;
|
||||
code: number;
|
||||
data?: unknown;
|
||||
message: RtErrorMessage;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
// Named constants for JSON-RPC 2.0 error codes emitted on the message-bus
|
||||
// WebSocket wire. Mirrors `application/ports/message_bus_ports.rs::error_code`
|
||||
// on the server — the Rust module is the source of truth.
|
||||
//
|
||||
// Hand-written, deliberately not generated: Modelina projects a JSON-Schema
|
||||
// `enum` of numeric values into a TS enum with mangled member names
|
||||
// (`MINUS_32001 = -32001`), which reads worse than no enum at all. The wire
|
||||
// type is just `number`; readable name-to-code lookup lives here.
|
||||
//
|
||||
// Values are frozen across releases — a new denial cause gets a new value,
|
||||
// never repurposes an existing one. Adding a code: bump the Rust module and
|
||||
// this file in the same commit; the wire spec's description text is a
|
||||
// derivative of the Rust constants (see `generate-asyncapi.rs`).
|
||||
|
||||
/**
|
||||
* Application-defined codes live in the JSON-RPC 2.0 server-defined range
|
||||
* `-32099..-32000`; standard envelope codes live in `-32700..-32600`.
|
||||
*/
|
||||
export const RtErrorCode = {
|
||||
// ── Application-defined (subscribe / edit path denials) ─────────────
|
||||
/** Resource-scoped topic, caller lacks Read on the resource (or the
|
||||
* resource does not exist — the two outcomes are indistinguishable to
|
||||
* the caller by design, to preserve anti-enumeration). */
|
||||
NO_READ: -32001,
|
||||
/** Resource-scoped topic requires Share, caller has Read but not Share.
|
||||
* Applies to `file:{id}:shares` (Phase B). */
|
||||
NO_SHARE: -32002,
|
||||
/** Resource-scoped topic requires Comment (`file:{id}:comments`, Phase B). */
|
||||
NO_COMMENT: -32003,
|
||||
/** Identity-scoped mismatch, OR unknown/malformed topic. Same wire code
|
||||
* regardless of whether the target exists — anti-enum. */
|
||||
TOPIC_FORBIDDEN: -32004,
|
||||
/** Per-connection subscription cap hit. */
|
||||
SUB_LIMIT: -32005,
|
||||
/** Subscribe-frame token bucket exhausted. */
|
||||
RATE_LIMITED: -32006,
|
||||
/** CRDT edit frame from a caller without Edit on the doc. Emitted as an
|
||||
* `rt.write_denied` notification (not tied to a request id). */
|
||||
NO_EDIT: -32007,
|
||||
|
||||
// ── JSON-RPC 2.0 standard envelope codes ────────────────────────────
|
||||
/** Server-side failure the client should retry. */
|
||||
INTERNAL_ERROR: -32603,
|
||||
/** Malformed JSON-RPC envelope (missing `method`, wrong `jsonrpc` version). */
|
||||
INVALID_REQUEST: -32600,
|
||||
/** Method outside the `rt.*` allow-list. */
|
||||
METHOD_NOT_FOUND: -32601,
|
||||
/** Method known but `params` shape wrong (missing `topic`, unparseable). */
|
||||
INVALID_PARAMS: -32602
|
||||
} as const satisfies Record<string, number>;
|
||||
|
||||
/** Union of every named code's numeric value. Narrows a bare `number` on
|
||||
* `RtErrorObject.code` to the eleven known literals for exhaustive
|
||||
* `switch` blocks. */
|
||||
export type RtErrorCodeValue = (typeof RtErrorCode)[keyof typeof RtErrorCode];
|
||||
@@ -473,10 +473,30 @@ fn rpc_error_object_schema() -> Value {
|
||||
}
|
||||
|
||||
fn rpc_error_code_schema() -> Value {
|
||||
json!({
|
||||
"type": "integer",
|
||||
"description": "Stable integer error code. Values are frozen across releases — a new denial cause gets a new value, never repurposes an existing one.",
|
||||
"enum": [
|
||||
// Kept as plain `integer` — Modelina projects a JSON-Schema `enum` of
|
||||
// numeric values into a TS enum with mangled member names
|
||||
// (`MINUS_32001 = -32001`), which is worse than no enum at all. The
|
||||
// Rust `error_code` module is the source of truth for named
|
||||
// constants; the FE mirrors it in `frontend/src/lib/message-bus/
|
||||
// error-codes.ts` (hand-written, 11 lines, sits alongside the
|
||||
// generated DTOs). Description enumerates the full set inline so the
|
||||
// AsyncAPI spec is still self-documenting.
|
||||
let full_description = format!(
|
||||
"Stable integer error code. Values are frozen across releases — a \
|
||||
new denial cause gets a new value, never repurposes an existing \
|
||||
one. Application-defined codes ({}..={}):\n\
|
||||
· {} NO_READ — resource-scoped topic, caller lacks Read (or \
|
||||
resource doesn't exist — indistinguishable by design)\n\
|
||||
· {} NO_SHARE — resource requires Share, caller has Read but not Share\n\
|
||||
· {} NO_COMMENT — resource requires Comment\n\
|
||||
· {} TOPIC_FORBIDDEN — identity-scoped mismatch or unknown/malformed topic\n\
|
||||
· {} SUB_LIMIT — per-connection subscription cap hit\n\
|
||||
· {} RATE_LIMITED — subscribe-frame token bucket exhausted\n\
|
||||
· {} NO_EDIT — CRDT edit frame from a caller without Edit\n\
|
||||
Standard JSON-RPC 2.0 codes:\n\
|
||||
· {} INTERNAL_ERROR · {} INVALID_REQUEST · {} METHOD_NOT_FOUND · {} INVALID_PARAMS",
|
||||
-32099,
|
||||
-32000,
|
||||
error_code::NO_READ,
|
||||
error_code::NO_SHARE,
|
||||
error_code::NO_COMMENT,
|
||||
@@ -488,7 +508,10 @@ fn rpc_error_code_schema() -> Value {
|
||||
error_code::INVALID_REQUEST,
|
||||
error_code::METHOD_NOT_FOUND,
|
||||
error_code::INVALID_PARAMS,
|
||||
],
|
||||
);
|
||||
json!({
|
||||
"type": "integer",
|
||||
"description": full_description,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user