@lunora/errors 1.0.0-alpha.5 → 1.0.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +103 -80
- package/dist/index.d.ts +103 -80
- package/dist/index.mjs +4 -4
- package/dist/packem_shared/{ERROR_CATALOG-pJvm6SQP.mjs → ERROR_CATALOG-0x-vRYNm.mjs} +29 -1
- package/dist/packem_shared/{LunoraError-Cdb2-Hda.mjs → LunoraError-B_Fjp5jb.mjs} +1 -1
- package/dist/packem_shared/{invariant-HhlkSkbP.mjs → invariant-BngUFrZs.mjs} +1 -1
- package/dist/packem_shared/{toErrorBody-BXvKCSrv.mjs → toErrorBody-CKa-c46O.mjs} +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The central Lunora error catalog — the single source of truth mapping a
|
|
3
|
-
* machine-readable `code` to its transport `status`, a short human `title`, and
|
|
4
|
-
* (where useful) an actionable Markdown `hint` plus a `docsUrl`.
|
|
5
|
-
*
|
|
6
|
-
* This table is consumed everywhere an error is surfaced: the runtime/DO wire
|
|
7
|
-
* mappers (status), the client SDK (code discrimination), the CLI renderer and
|
|
8
|
-
* the Vite overlay (hint), and the Studio UI (title + hint + docs link). It also
|
|
9
|
-
* absorbs the former `@lunora/codegen` "solutions" table (see {@link MESSAGE_SOLUTIONS})
|
|
10
|
-
* so codegen build-time errors — which are thrown as plain messages into
|
|
11
|
-
* generated code and lose their class identity before a consumer sees them —
|
|
12
|
-
* keep their message-matched hints.
|
|
13
|
-
*/
|
|
2
|
+
* The central Lunora error catalog — the single source of truth mapping a
|
|
3
|
+
* machine-readable `code` to its transport `status`, a short human `title`, and
|
|
4
|
+
* (where useful) an actionable Markdown `hint` plus a `docsUrl`.
|
|
5
|
+
*
|
|
6
|
+
* This table is consumed everywhere an error is surfaced: the runtime/DO wire
|
|
7
|
+
* mappers (status), the client SDK (code discrimination), the CLI renderer and
|
|
8
|
+
* the Vite overlay (hint), and the Studio UI (title + hint + docs link). It also
|
|
9
|
+
* absorbs the former `@lunora/codegen` "solutions" table (see {@link MESSAGE_SOLUTIONS})
|
|
10
|
+
* so codegen build-time errors — which are thrown as plain messages into
|
|
11
|
+
* generated code and lose their class identity before a consumer sees them —
|
|
12
|
+
* keep their message-matched hints.
|
|
13
|
+
*/
|
|
14
14
|
/** Markdown hint: a single string or an array of lines. Shape matches `@visulima/error`'s `hint`. */
|
|
15
|
-
type ErrorHint = string | string
|
|
15
|
+
type ErrorHint = string | ReadonlyArray<string>;
|
|
16
16
|
/** A catalog entry: the fixed metadata for one error `code`. */
|
|
17
17
|
interface ErrorCatalogEntry {
|
|
18
18
|
/** Optional URL to deeper docs for this error. */
|
|
@@ -20,11 +20,11 @@ interface ErrorCatalogEntry {
|
|
|
20
20
|
/** Optional actionable fix, authored as Markdown (rendered by CLI/overlay/Studio). */
|
|
21
21
|
hint?: ErrorHint;
|
|
22
22
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
* When `true`, this code's `message` must NOT cross the wire — an internal
|
|
24
|
+
* failure or unhandled invariant may carry SQL fragments, file paths, or
|
|
25
|
+
* internal identifiers. The transport mappers emit a generic message for
|
|
26
|
+
* these (and log the real one server-side). See {@link isInternalCode}.
|
|
27
|
+
*/
|
|
28
28
|
internal?: boolean;
|
|
29
29
|
/** HTTP/RPC status this code maps to on the wire. */
|
|
30
30
|
status: number;
|
|
@@ -32,10 +32,10 @@ interface ErrorCatalogEntry {
|
|
|
32
32
|
title: string;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Every well-known Lunora error code. Domain packages may throw additional
|
|
36
|
-
* codes (passing an explicit `status`); those are added here as their package is
|
|
37
|
-
* migrated. The keys of this object form the {@link LunoraErrorCode} union.
|
|
38
|
-
*/
|
|
35
|
+
* Every well-known Lunora error code. Domain packages may throw additional
|
|
36
|
+
* codes (passing an explicit `status`); those are added here as their package is
|
|
37
|
+
* migrated. The keys of this object form the {@link LunoraErrorCode} union.
|
|
38
|
+
*/
|
|
39
39
|
declare const ERROR_CATALOG: {
|
|
40
40
|
readonly BAD_REQUEST: {
|
|
41
41
|
readonly status: 400;
|
|
@@ -78,7 +78,8 @@ declare const ERROR_CATALOG: {
|
|
|
78
78
|
readonly NOT_IMPLEMENTED: {
|
|
79
79
|
readonly status: 501;
|
|
80
80
|
readonly title: "Not implemented";
|
|
81
|
-
};
|
|
81
|
+
};
|
|
82
|
+
/** RPC/REST dispatch codes emitted by the runtime + Durable Object router. */
|
|
82
83
|
readonly FUNCTION_NOT_FOUND: {
|
|
83
84
|
readonly status: 404;
|
|
84
85
|
readonly title: "Function not found";
|
|
@@ -90,7 +91,8 @@ declare const ERROR_CATALOG: {
|
|
|
90
91
|
readonly PAYLOAD_TOO_LARGE: {
|
|
91
92
|
readonly status: 413;
|
|
92
93
|
readonly title: "Payload too large";
|
|
93
|
-
};
|
|
94
|
+
};
|
|
95
|
+
/** Free-form internal failure — redacted to a generic message on the wire. */
|
|
94
96
|
readonly INTERNAL: {
|
|
95
97
|
readonly internal: true;
|
|
96
98
|
readonly status: 500;
|
|
@@ -153,7 +155,8 @@ declare const ERROR_CATALOG: {
|
|
|
153
155
|
readonly OFFLINE_IDENTITY_CHANGED: {
|
|
154
156
|
readonly status: 409;
|
|
155
157
|
readonly title: "Offline identity changed";
|
|
156
|
-
};
|
|
158
|
+
};
|
|
159
|
+
/** Package-specific codes. Build-time-only — never cross the RPC wire, so deliberately not `internal`. */
|
|
157
160
|
readonly CODEGEN_DIAGNOSTIC: {
|
|
158
161
|
readonly status: 500;
|
|
159
162
|
readonly title: "Codegen diagnostic";
|
|
@@ -176,11 +179,31 @@ declare const ERROR_CATALOG: {
|
|
|
176
179
|
readonly title: "Auth headers missing";
|
|
177
180
|
};
|
|
178
181
|
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
* Signup rejected by `@lunora/auth`'s email-domain gate — a disposable/throwaway
|
|
183
|
+
* provider (or a caller deny-list hit). Client-safe: the message names only the
|
|
184
|
+
* offending domain class, never a secret, so it is echoed rather than redacted.
|
|
185
|
+
*/
|
|
186
|
+
readonly EMAIL_DOMAIN_BLOCKED: {
|
|
187
|
+
readonly hint: readonly ["This address's domain is on the disposable/throwaway blocklist (or your configured deny-list).", "", "Sign up with a permanent mailbox. To tune the policy, pass `blockDisposable` / `allowDomains` / `denyDomains` to `emailGate(...)` (`@lunora/auth/email-guard`)."];
|
|
188
|
+
readonly status: 400;
|
|
189
|
+
readonly title: "Email domain not allowed";
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Opt-in MX verification (`@lunora/auth/email-guard`, `mx: true`) found no mail
|
|
193
|
+
* exchanger for the address's domain, so mail to it would never deliver.
|
|
194
|
+
* Client-safe: names only the domain, no secret.
|
|
195
|
+
*/
|
|
196
|
+
readonly EMAIL_UNDELIVERABLE: {
|
|
197
|
+
readonly hint: readonly ["The address's domain publishes no MX (or fallback A/AAAA) records, so it can't receive mail.", "", "Check for a typo in the domain. MX verification is opt-in (`mx: true`) and needs DNS — leave it off on the edge path if DNS is unavailable."];
|
|
198
|
+
readonly status: 400;
|
|
199
|
+
readonly title: "Email domain cannot receive mail";
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Upstream Cloudflare API failures surfaced from an action. The message
|
|
203
|
+
* carries the upstream response body (Cloudflare's own error text — trusted
|
|
204
|
+
* infra, not user input), so it is echoed rather than redacted. `status`
|
|
205
|
+
* here is a fallback; each throw passes the actual upstream HTTP status.
|
|
206
|
+
*/
|
|
184
207
|
readonly ANALYTICS_SQL_ERROR: {
|
|
185
208
|
readonly status: 502;
|
|
186
209
|
readonly title: "Analytics Engine SQL API error";
|
|
@@ -197,21 +220,21 @@ declare const ERROR_CATALOG: {
|
|
|
197
220
|
/** A well-known Lunora error code (a key of {@link ERROR_CATALOG}). */
|
|
198
221
|
type LunoraErrorCode = keyof typeof ERROR_CATALOG;
|
|
199
222
|
/**
|
|
200
|
-
* True when `code` is an internal/redacted code — an internal failure or
|
|
201
|
-
* unhandled invariant whose `message` must NOT cross the wire (it may carry SQL
|
|
202
|
-
* fragments, file paths, or internal identifiers). Derived from the catalog's
|
|
203
|
-
* `internal` flag so the redaction posture stays in one place (the table).
|
|
204
|
-
* Throwing a `LunoraError` with any non-internal code is the author's vouch that
|
|
205
|
-
* its message is client-safe; an unknown/unregistered code is treated as safe.
|
|
206
|
-
*/
|
|
223
|
+
* True when `code` is an internal/redacted code — an internal failure or
|
|
224
|
+
* unhandled invariant whose `message` must NOT cross the wire (it may carry SQL
|
|
225
|
+
* fragments, file paths, or internal identifiers). Derived from the catalog's
|
|
226
|
+
* `internal` flag so the redaction posture stays in one place (the table).
|
|
227
|
+
* Throwing a `LunoraError` with any non-internal code is the author's vouch that
|
|
228
|
+
* its message is client-safe; an unknown/unregistered code is treated as safe.
|
|
229
|
+
*/
|
|
207
230
|
declare const isInternalCode: (code: string) => boolean;
|
|
208
231
|
/**
|
|
209
|
-
* A message-matched solution for errors that reach a consumer without a `code`
|
|
210
|
-
* — chiefly `@lunora/codegen` build errors, which are thrown as plain messages
|
|
211
|
-
* into generated code (and flattened to `{ message }` by the Vite overlay), so
|
|
212
|
-
* the message text is the only stable join key. Ordered most- to least-specific;
|
|
213
|
-
* the first matching rule wins.
|
|
214
|
-
*/
|
|
232
|
+
* A message-matched solution for errors that reach a consumer without a `code`
|
|
233
|
+
* — chiefly `@lunora/codegen` build errors, which are thrown as plain messages
|
|
234
|
+
* into generated code (and flattened to `{ message }` by the Vite overlay), so
|
|
235
|
+
* the message text is the only stable join key. Ordered most- to least-specific;
|
|
236
|
+
* the first matching rule wins.
|
|
237
|
+
*/
|
|
215
238
|
interface Solution {
|
|
216
239
|
/** Markdown body shown under the header. */
|
|
217
240
|
body: string;
|
|
@@ -226,27 +249,27 @@ interface SolutionRule extends Solution {
|
|
|
226
249
|
test: (message: string) => boolean;
|
|
227
250
|
}
|
|
228
251
|
/**
|
|
229
|
-
* Message-matched solutions (migrated verbatim from the former
|
|
230
|
-
* `@lunora/codegen` solutions table). Re-exported by `@lunora/codegen` as
|
|
231
|
-
* `LUNORA_SOLUTION_RULES` for backward compatibility.
|
|
232
|
-
*/
|
|
252
|
+
* Message-matched solutions (migrated verbatim from the former
|
|
253
|
+
* `@lunora/codegen` solutions table). Re-exported by `@lunora/codegen` as
|
|
254
|
+
* `LUNORA_SOLUTION_RULES` for backward compatibility.
|
|
255
|
+
*/
|
|
233
256
|
declare const MESSAGE_SOLUTIONS: ReadonlyArray<SolutionRule>;
|
|
234
257
|
/**
|
|
235
|
-
* Flatten a Markdown hint to plain text for a terminal / non-Markdown surface:
|
|
236
|
-
* drop code-fence markers and strip inline `**bold**` / `` `code` `` emphasis.
|
|
237
|
-
* Shared by the CLI renderer and the Studio `ErrorAlert` so the two can't drift.
|
|
238
|
-
*/
|
|
258
|
+
* Flatten a Markdown hint to plain text for a terminal / non-Markdown surface:
|
|
259
|
+
* drop code-fence markers and strip inline `**bold**` / `` `code` `` emphasis.
|
|
260
|
+
* Shared by the CLI renderer and the Studio `ErrorAlert` so the two can't drift.
|
|
261
|
+
*/
|
|
239
262
|
declare const flattenHint: (hint: ErrorHint) => string;
|
|
240
263
|
/**
|
|
241
|
-
* Find the first message-matched {@link Solution} for `message`, or `undefined`
|
|
242
|
-
* if none recognize it. Re-exported by `@lunora/codegen` as `findLunoraSolution`.
|
|
243
|
-
*/
|
|
264
|
+
* Find the first message-matched {@link Solution} for `message`, or `undefined`
|
|
265
|
+
* if none recognize it. Re-exported by `@lunora/codegen` as `findLunoraSolution`.
|
|
266
|
+
*/
|
|
244
267
|
declare const findSolutionByMessage: (message: string) => Solution | undefined;
|
|
245
268
|
/**
|
|
246
|
-
* Resolve an actionable hint for an error: prefer a hint carried on the error
|
|
247
|
-
* (or its `code`'s catalog entry), then fall back to a message match. Returns
|
|
248
|
-
* `undefined` when nothing recognizes it.
|
|
249
|
-
*/
|
|
269
|
+
* Resolve an actionable hint for an error: prefer a hint carried on the error
|
|
270
|
+
* (or its `code`'s catalog entry), then fall back to a message match. Returns
|
|
271
|
+
* `undefined` when nothing recognizes it.
|
|
272
|
+
*/
|
|
250
273
|
declare const resolveHint: (input: {
|
|
251
274
|
code?: string;
|
|
252
275
|
hint?: ErrorHint;
|
|
@@ -278,16 +301,16 @@ interface LunoraErrorOptions {
|
|
|
278
301
|
title?: string;
|
|
279
302
|
}
|
|
280
303
|
/**
|
|
281
|
-
* A code string: a well-known {@link LunoraErrorCode} (with autocomplete) or any
|
|
282
|
-
* package-specific code not yet in the catalog.
|
|
283
|
-
*/
|
|
304
|
+
* A code string: a well-known {@link LunoraErrorCode} (with autocomplete) or any
|
|
305
|
+
* package-specific code not yet in the catalog.
|
|
306
|
+
*/
|
|
284
307
|
type LunoraErrorCodeInput = LunoraErrorCode | (string & {});
|
|
285
308
|
declare class LunoraError extends Error {
|
|
286
309
|
/**
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
310
|
+
* Discriminator recognised by `@visulima/error`'s `renderError`/`isVisulimaError`
|
|
311
|
+
* (`error.type === "VisulimaError"`), so a `LunoraError` renders like a native
|
|
312
|
+
* `VisulimaError` — hint and all.
|
|
313
|
+
*/
|
|
291
314
|
readonly type = "VisulimaError";
|
|
292
315
|
/** Actionable fix (Markdown), rendered by the CLI/overlay/Studio. */
|
|
293
316
|
readonly hint: ErrorHint | undefined;
|
|
@@ -316,11 +339,11 @@ interface LunoraErrorLike extends Error {
|
|
|
316
339
|
type: "VisulimaError";
|
|
317
340
|
}
|
|
318
341
|
/**
|
|
319
|
-
* True when `error` carries the Lunora transport shape (string `code` + numeric
|
|
320
|
-
* `status` + the `VisulimaError` brand). The `type` brand is what distinguishes
|
|
321
|
-
* a real `LunoraError` (or its wire-decoded twin) from a foreign error that
|
|
322
|
-
* happens to carry `code`/`status` — see plan 119 for the full rationale.
|
|
323
|
-
*/
|
|
342
|
+
* True when `error` carries the Lunora transport shape (string `code` + numeric
|
|
343
|
+
* `status` + the `VisulimaError` brand). The `type` brand is what distinguishes
|
|
344
|
+
* a real `LunoraError` (or its wire-decoded twin) from a foreign error that
|
|
345
|
+
* happens to carry `code`/`status` — see plan 119 for the full rationale.
|
|
346
|
+
*/
|
|
324
347
|
declare const isLunoraError: (error: unknown) => error is LunoraErrorLike;
|
|
325
348
|
/** Throw an `INTERNAL` {@link LunoraError} when `condition` is falsy. */
|
|
326
349
|
declare const invariant: (condition: unknown, message: string) => asserts condition;
|
|
@@ -336,9 +359,9 @@ interface ErrorBody {
|
|
|
336
359
|
}
|
|
337
360
|
interface ToErrorBodyOptions {
|
|
338
361
|
/**
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
362
|
+
* Wire-encode a `LunoraError`'s structured `data` for the client (so a
|
|
363
|
+
* `bigint`/`bytes` inside it survives). Omit to drop `data` from the body.
|
|
364
|
+
*/
|
|
342
365
|
encodeData?: (data: unknown) => unknown;
|
|
343
366
|
/** Code for an unrecognized (non-`LunoraError`) throw. Default `"INTERNAL"`. */
|
|
344
367
|
fallbackCode?: string;
|
|
@@ -353,12 +376,12 @@ interface ToErrorBodyResult {
|
|
|
353
376
|
status: number;
|
|
354
377
|
}
|
|
355
378
|
/**
|
|
356
|
-
* Turn a thrown value into an {@link ErrorBody} + status, applying the redaction
|
|
357
|
-
* invariant. A `LunoraError` with a non-internal code is echoed with its
|
|
358
|
-
* `message`, resolved `hint`, `docsUrl`, and (when `encodeData` is given) its
|
|
359
|
-
* `data`. An internal-coded `LunoraError` keeps its `code`/`status` but its
|
|
360
|
-
* message is replaced with `redactedMessage`. Anything else becomes a generic
|
|
361
|
-
* `fallbackCode`/500. When `redacted` is `true`, log the raw error server-side.
|
|
362
|
-
*/
|
|
379
|
+
* Turn a thrown value into an {@link ErrorBody} + status, applying the redaction
|
|
380
|
+
* invariant. A `LunoraError` with a non-internal code is echoed with its
|
|
381
|
+
* `message`, resolved `hint`, `docsUrl`, and (when `encodeData` is given) its
|
|
382
|
+
* `data`. An internal-coded `LunoraError` keeps its `code`/`status` but its
|
|
383
|
+
* message is replaced with `redactedMessage`. Anything else becomes a generic
|
|
384
|
+
* `fallbackCode`/500. When `redacted` is `true`, log the raw error server-side.
|
|
385
|
+
*/
|
|
363
386
|
declare const toErrorBody: (error: unknown, options?: ToErrorBodyOptions) => ToErrorBodyResult;
|
|
364
387
|
export { ERROR_CATALOG, type ErrorBody, type ErrorCatalogEntry, type ErrorHint, type ErrorLocation, LunoraError, type LunoraErrorCode, type LunoraErrorCodeInput, type LunoraErrorLike, type LunoraErrorOptions, MESSAGE_SOLUTIONS, type Solution, type SolutionRule, type ToErrorBodyOptions, type ToErrorBodyResult, findSolutionByMessage, flattenHint, invariant, isInternalCode, isLunoraError, resolveHint, toErrorBody, unreachable };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The central Lunora error catalog — the single source of truth mapping a
|
|
3
|
-
* machine-readable `code` to its transport `status`, a short human `title`, and
|
|
4
|
-
* (where useful) an actionable Markdown `hint` plus a `docsUrl`.
|
|
5
|
-
*
|
|
6
|
-
* This table is consumed everywhere an error is surfaced: the runtime/DO wire
|
|
7
|
-
* mappers (status), the client SDK (code discrimination), the CLI renderer and
|
|
8
|
-
* the Vite overlay (hint), and the Studio UI (title + hint + docs link). It also
|
|
9
|
-
* absorbs the former `@lunora/codegen` "solutions" table (see {@link MESSAGE_SOLUTIONS})
|
|
10
|
-
* so codegen build-time errors — which are thrown as plain messages into
|
|
11
|
-
* generated code and lose their class identity before a consumer sees them —
|
|
12
|
-
* keep their message-matched hints.
|
|
13
|
-
*/
|
|
2
|
+
* The central Lunora error catalog — the single source of truth mapping a
|
|
3
|
+
* machine-readable `code` to its transport `status`, a short human `title`, and
|
|
4
|
+
* (where useful) an actionable Markdown `hint` plus a `docsUrl`.
|
|
5
|
+
*
|
|
6
|
+
* This table is consumed everywhere an error is surfaced: the runtime/DO wire
|
|
7
|
+
* mappers (status), the client SDK (code discrimination), the CLI renderer and
|
|
8
|
+
* the Vite overlay (hint), and the Studio UI (title + hint + docs link). It also
|
|
9
|
+
* absorbs the former `@lunora/codegen` "solutions" table (see {@link MESSAGE_SOLUTIONS})
|
|
10
|
+
* so codegen build-time errors — which are thrown as plain messages into
|
|
11
|
+
* generated code and lose their class identity before a consumer sees them —
|
|
12
|
+
* keep their message-matched hints.
|
|
13
|
+
*/
|
|
14
14
|
/** Markdown hint: a single string or an array of lines. Shape matches `@visulima/error`'s `hint`. */
|
|
15
|
-
type ErrorHint = string | string
|
|
15
|
+
type ErrorHint = string | ReadonlyArray<string>;
|
|
16
16
|
/** A catalog entry: the fixed metadata for one error `code`. */
|
|
17
17
|
interface ErrorCatalogEntry {
|
|
18
18
|
/** Optional URL to deeper docs for this error. */
|
|
@@ -20,11 +20,11 @@ interface ErrorCatalogEntry {
|
|
|
20
20
|
/** Optional actionable fix, authored as Markdown (rendered by CLI/overlay/Studio). */
|
|
21
21
|
hint?: ErrorHint;
|
|
22
22
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
* When `true`, this code's `message` must NOT cross the wire — an internal
|
|
24
|
+
* failure or unhandled invariant may carry SQL fragments, file paths, or
|
|
25
|
+
* internal identifiers. The transport mappers emit a generic message for
|
|
26
|
+
* these (and log the real one server-side). See {@link isInternalCode}.
|
|
27
|
+
*/
|
|
28
28
|
internal?: boolean;
|
|
29
29
|
/** HTTP/RPC status this code maps to on the wire. */
|
|
30
30
|
status: number;
|
|
@@ -32,10 +32,10 @@ interface ErrorCatalogEntry {
|
|
|
32
32
|
title: string;
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
|
-
* Every well-known Lunora error code. Domain packages may throw additional
|
|
36
|
-
* codes (passing an explicit `status`); those are added here as their package is
|
|
37
|
-
* migrated. The keys of this object form the {@link LunoraErrorCode} union.
|
|
38
|
-
*/
|
|
35
|
+
* Every well-known Lunora error code. Domain packages may throw additional
|
|
36
|
+
* codes (passing an explicit `status`); those are added here as their package is
|
|
37
|
+
* migrated. The keys of this object form the {@link LunoraErrorCode} union.
|
|
38
|
+
*/
|
|
39
39
|
declare const ERROR_CATALOG: {
|
|
40
40
|
readonly BAD_REQUEST: {
|
|
41
41
|
readonly status: 400;
|
|
@@ -78,7 +78,8 @@ declare const ERROR_CATALOG: {
|
|
|
78
78
|
readonly NOT_IMPLEMENTED: {
|
|
79
79
|
readonly status: 501;
|
|
80
80
|
readonly title: "Not implemented";
|
|
81
|
-
};
|
|
81
|
+
};
|
|
82
|
+
/** RPC/REST dispatch codes emitted by the runtime + Durable Object router. */
|
|
82
83
|
readonly FUNCTION_NOT_FOUND: {
|
|
83
84
|
readonly status: 404;
|
|
84
85
|
readonly title: "Function not found";
|
|
@@ -90,7 +91,8 @@ declare const ERROR_CATALOG: {
|
|
|
90
91
|
readonly PAYLOAD_TOO_LARGE: {
|
|
91
92
|
readonly status: 413;
|
|
92
93
|
readonly title: "Payload too large";
|
|
93
|
-
};
|
|
94
|
+
};
|
|
95
|
+
/** Free-form internal failure — redacted to a generic message on the wire. */
|
|
94
96
|
readonly INTERNAL: {
|
|
95
97
|
readonly internal: true;
|
|
96
98
|
readonly status: 500;
|
|
@@ -153,7 +155,8 @@ declare const ERROR_CATALOG: {
|
|
|
153
155
|
readonly OFFLINE_IDENTITY_CHANGED: {
|
|
154
156
|
readonly status: 409;
|
|
155
157
|
readonly title: "Offline identity changed";
|
|
156
|
-
};
|
|
158
|
+
};
|
|
159
|
+
/** Package-specific codes. Build-time-only — never cross the RPC wire, so deliberately not `internal`. */
|
|
157
160
|
readonly CODEGEN_DIAGNOSTIC: {
|
|
158
161
|
readonly status: 500;
|
|
159
162
|
readonly title: "Codegen diagnostic";
|
|
@@ -176,11 +179,31 @@ declare const ERROR_CATALOG: {
|
|
|
176
179
|
readonly title: "Auth headers missing";
|
|
177
180
|
};
|
|
178
181
|
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
* Signup rejected by `@lunora/auth`'s email-domain gate — a disposable/throwaway
|
|
183
|
+
* provider (or a caller deny-list hit). Client-safe: the message names only the
|
|
184
|
+
* offending domain class, never a secret, so it is echoed rather than redacted.
|
|
185
|
+
*/
|
|
186
|
+
readonly EMAIL_DOMAIN_BLOCKED: {
|
|
187
|
+
readonly hint: readonly ["This address's domain is on the disposable/throwaway blocklist (or your configured deny-list).", "", "Sign up with a permanent mailbox. To tune the policy, pass `blockDisposable` / `allowDomains` / `denyDomains` to `emailGate(...)` (`@lunora/auth/email-guard`)."];
|
|
188
|
+
readonly status: 400;
|
|
189
|
+
readonly title: "Email domain not allowed";
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Opt-in MX verification (`@lunora/auth/email-guard`, `mx: true`) found no mail
|
|
193
|
+
* exchanger for the address's domain, so mail to it would never deliver.
|
|
194
|
+
* Client-safe: names only the domain, no secret.
|
|
195
|
+
*/
|
|
196
|
+
readonly EMAIL_UNDELIVERABLE: {
|
|
197
|
+
readonly hint: readonly ["The address's domain publishes no MX (or fallback A/AAAA) records, so it can't receive mail.", "", "Check for a typo in the domain. MX verification is opt-in (`mx: true`) and needs DNS — leave it off on the edge path if DNS is unavailable."];
|
|
198
|
+
readonly status: 400;
|
|
199
|
+
readonly title: "Email domain cannot receive mail";
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Upstream Cloudflare API failures surfaced from an action. The message
|
|
203
|
+
* carries the upstream response body (Cloudflare's own error text — trusted
|
|
204
|
+
* infra, not user input), so it is echoed rather than redacted. `status`
|
|
205
|
+
* here is a fallback; each throw passes the actual upstream HTTP status.
|
|
206
|
+
*/
|
|
184
207
|
readonly ANALYTICS_SQL_ERROR: {
|
|
185
208
|
readonly status: 502;
|
|
186
209
|
readonly title: "Analytics Engine SQL API error";
|
|
@@ -197,21 +220,21 @@ declare const ERROR_CATALOG: {
|
|
|
197
220
|
/** A well-known Lunora error code (a key of {@link ERROR_CATALOG}). */
|
|
198
221
|
type LunoraErrorCode = keyof typeof ERROR_CATALOG;
|
|
199
222
|
/**
|
|
200
|
-
* True when `code` is an internal/redacted code — an internal failure or
|
|
201
|
-
* unhandled invariant whose `message` must NOT cross the wire (it may carry SQL
|
|
202
|
-
* fragments, file paths, or internal identifiers). Derived from the catalog's
|
|
203
|
-
* `internal` flag so the redaction posture stays in one place (the table).
|
|
204
|
-
* Throwing a `LunoraError` with any non-internal code is the author's vouch that
|
|
205
|
-
* its message is client-safe; an unknown/unregistered code is treated as safe.
|
|
206
|
-
*/
|
|
223
|
+
* True when `code` is an internal/redacted code — an internal failure or
|
|
224
|
+
* unhandled invariant whose `message` must NOT cross the wire (it may carry SQL
|
|
225
|
+
* fragments, file paths, or internal identifiers). Derived from the catalog's
|
|
226
|
+
* `internal` flag so the redaction posture stays in one place (the table).
|
|
227
|
+
* Throwing a `LunoraError` with any non-internal code is the author's vouch that
|
|
228
|
+
* its message is client-safe; an unknown/unregistered code is treated as safe.
|
|
229
|
+
*/
|
|
207
230
|
declare const isInternalCode: (code: string) => boolean;
|
|
208
231
|
/**
|
|
209
|
-
* A message-matched solution for errors that reach a consumer without a `code`
|
|
210
|
-
* — chiefly `@lunora/codegen` build errors, which are thrown as plain messages
|
|
211
|
-
* into generated code (and flattened to `{ message }` by the Vite overlay), so
|
|
212
|
-
* the message text is the only stable join key. Ordered most- to least-specific;
|
|
213
|
-
* the first matching rule wins.
|
|
214
|
-
*/
|
|
232
|
+
* A message-matched solution for errors that reach a consumer without a `code`
|
|
233
|
+
* — chiefly `@lunora/codegen` build errors, which are thrown as plain messages
|
|
234
|
+
* into generated code (and flattened to `{ message }` by the Vite overlay), so
|
|
235
|
+
* the message text is the only stable join key. Ordered most- to least-specific;
|
|
236
|
+
* the first matching rule wins.
|
|
237
|
+
*/
|
|
215
238
|
interface Solution {
|
|
216
239
|
/** Markdown body shown under the header. */
|
|
217
240
|
body: string;
|
|
@@ -226,27 +249,27 @@ interface SolutionRule extends Solution {
|
|
|
226
249
|
test: (message: string) => boolean;
|
|
227
250
|
}
|
|
228
251
|
/**
|
|
229
|
-
* Message-matched solutions (migrated verbatim from the former
|
|
230
|
-
* `@lunora/codegen` solutions table). Re-exported by `@lunora/codegen` as
|
|
231
|
-
* `LUNORA_SOLUTION_RULES` for backward compatibility.
|
|
232
|
-
*/
|
|
252
|
+
* Message-matched solutions (migrated verbatim from the former
|
|
253
|
+
* `@lunora/codegen` solutions table). Re-exported by `@lunora/codegen` as
|
|
254
|
+
* `LUNORA_SOLUTION_RULES` for backward compatibility.
|
|
255
|
+
*/
|
|
233
256
|
declare const MESSAGE_SOLUTIONS: ReadonlyArray<SolutionRule>;
|
|
234
257
|
/**
|
|
235
|
-
* Flatten a Markdown hint to plain text for a terminal / non-Markdown surface:
|
|
236
|
-
* drop code-fence markers and strip inline `**bold**` / `` `code` `` emphasis.
|
|
237
|
-
* Shared by the CLI renderer and the Studio `ErrorAlert` so the two can't drift.
|
|
238
|
-
*/
|
|
258
|
+
* Flatten a Markdown hint to plain text for a terminal / non-Markdown surface:
|
|
259
|
+
* drop code-fence markers and strip inline `**bold**` / `` `code` `` emphasis.
|
|
260
|
+
* Shared by the CLI renderer and the Studio `ErrorAlert` so the two can't drift.
|
|
261
|
+
*/
|
|
239
262
|
declare const flattenHint: (hint: ErrorHint) => string;
|
|
240
263
|
/**
|
|
241
|
-
* Find the first message-matched {@link Solution} for `message`, or `undefined`
|
|
242
|
-
* if none recognize it. Re-exported by `@lunora/codegen` as `findLunoraSolution`.
|
|
243
|
-
*/
|
|
264
|
+
* Find the first message-matched {@link Solution} for `message`, or `undefined`
|
|
265
|
+
* if none recognize it. Re-exported by `@lunora/codegen` as `findLunoraSolution`.
|
|
266
|
+
*/
|
|
244
267
|
declare const findSolutionByMessage: (message: string) => Solution | undefined;
|
|
245
268
|
/**
|
|
246
|
-
* Resolve an actionable hint for an error: prefer a hint carried on the error
|
|
247
|
-
* (or its `code`'s catalog entry), then fall back to a message match. Returns
|
|
248
|
-
* `undefined` when nothing recognizes it.
|
|
249
|
-
*/
|
|
269
|
+
* Resolve an actionable hint for an error: prefer a hint carried on the error
|
|
270
|
+
* (or its `code`'s catalog entry), then fall back to a message match. Returns
|
|
271
|
+
* `undefined` when nothing recognizes it.
|
|
272
|
+
*/
|
|
250
273
|
declare const resolveHint: (input: {
|
|
251
274
|
code?: string;
|
|
252
275
|
hint?: ErrorHint;
|
|
@@ -278,16 +301,16 @@ interface LunoraErrorOptions {
|
|
|
278
301
|
title?: string;
|
|
279
302
|
}
|
|
280
303
|
/**
|
|
281
|
-
* A code string: a well-known {@link LunoraErrorCode} (with autocomplete) or any
|
|
282
|
-
* package-specific code not yet in the catalog.
|
|
283
|
-
*/
|
|
304
|
+
* A code string: a well-known {@link LunoraErrorCode} (with autocomplete) or any
|
|
305
|
+
* package-specific code not yet in the catalog.
|
|
306
|
+
*/
|
|
284
307
|
type LunoraErrorCodeInput = LunoraErrorCode | (string & {});
|
|
285
308
|
declare class LunoraError extends Error {
|
|
286
309
|
/**
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
310
|
+
* Discriminator recognised by `@visulima/error`'s `renderError`/`isVisulimaError`
|
|
311
|
+
* (`error.type === "VisulimaError"`), so a `LunoraError` renders like a native
|
|
312
|
+
* `VisulimaError` — hint and all.
|
|
313
|
+
*/
|
|
291
314
|
readonly type = "VisulimaError";
|
|
292
315
|
/** Actionable fix (Markdown), rendered by the CLI/overlay/Studio. */
|
|
293
316
|
readonly hint: ErrorHint | undefined;
|
|
@@ -316,11 +339,11 @@ interface LunoraErrorLike extends Error {
|
|
|
316
339
|
type: "VisulimaError";
|
|
317
340
|
}
|
|
318
341
|
/**
|
|
319
|
-
* True when `error` carries the Lunora transport shape (string `code` + numeric
|
|
320
|
-
* `status` + the `VisulimaError` brand). The `type` brand is what distinguishes
|
|
321
|
-
* a real `LunoraError` (or its wire-decoded twin) from a foreign error that
|
|
322
|
-
* happens to carry `code`/`status` — see plan 119 for the full rationale.
|
|
323
|
-
*/
|
|
342
|
+
* True when `error` carries the Lunora transport shape (string `code` + numeric
|
|
343
|
+
* `status` + the `VisulimaError` brand). The `type` brand is what distinguishes
|
|
344
|
+
* a real `LunoraError` (or its wire-decoded twin) from a foreign error that
|
|
345
|
+
* happens to carry `code`/`status` — see plan 119 for the full rationale.
|
|
346
|
+
*/
|
|
324
347
|
declare const isLunoraError: (error: unknown) => error is LunoraErrorLike;
|
|
325
348
|
/** Throw an `INTERNAL` {@link LunoraError} when `condition` is falsy. */
|
|
326
349
|
declare const invariant: (condition: unknown, message: string) => asserts condition;
|
|
@@ -336,9 +359,9 @@ interface ErrorBody {
|
|
|
336
359
|
}
|
|
337
360
|
interface ToErrorBodyOptions {
|
|
338
361
|
/**
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
362
|
+
* Wire-encode a `LunoraError`'s structured `data` for the client (so a
|
|
363
|
+
* `bigint`/`bytes` inside it survives). Omit to drop `data` from the body.
|
|
364
|
+
*/
|
|
342
365
|
encodeData?: (data: unknown) => unknown;
|
|
343
366
|
/** Code for an unrecognized (non-`LunoraError`) throw. Default `"INTERNAL"`. */
|
|
344
367
|
fallbackCode?: string;
|
|
@@ -353,12 +376,12 @@ interface ToErrorBodyResult {
|
|
|
353
376
|
status: number;
|
|
354
377
|
}
|
|
355
378
|
/**
|
|
356
|
-
* Turn a thrown value into an {@link ErrorBody} + status, applying the redaction
|
|
357
|
-
* invariant. A `LunoraError` with a non-internal code is echoed with its
|
|
358
|
-
* `message`, resolved `hint`, `docsUrl`, and (when `encodeData` is given) its
|
|
359
|
-
* `data`. An internal-coded `LunoraError` keeps its `code`/`status` but its
|
|
360
|
-
* message is replaced with `redactedMessage`. Anything else becomes a generic
|
|
361
|
-
* `fallbackCode`/500. When `redacted` is `true`, log the raw error server-side.
|
|
362
|
-
*/
|
|
379
|
+
* Turn a thrown value into an {@link ErrorBody} + status, applying the redaction
|
|
380
|
+
* invariant. A `LunoraError` with a non-internal code is echoed with its
|
|
381
|
+
* `message`, resolved `hint`, `docsUrl`, and (when `encodeData` is given) its
|
|
382
|
+
* `data`. An internal-coded `LunoraError` keeps its `code`/`status` but its
|
|
383
|
+
* message is replaced with `redactedMessage`. Anything else becomes a generic
|
|
384
|
+
* `fallbackCode`/500. When `redacted` is `true`, log the raw error server-side.
|
|
385
|
+
*/
|
|
363
386
|
declare const toErrorBody: (error: unknown, options?: ToErrorBodyOptions) => ToErrorBodyResult;
|
|
364
387
|
export { ERROR_CATALOG, type ErrorBody, type ErrorCatalogEntry, type ErrorHint, type ErrorLocation, LunoraError, type LunoraErrorCode, type LunoraErrorCodeInput, type LunoraErrorLike, type LunoraErrorOptions, MESSAGE_SOLUTIONS, type Solution, type SolutionRule, type ToErrorBodyOptions, type ToErrorBodyResult, findSolutionByMessage, flattenHint, invariant, isInternalCode, isLunoraError, resolveHint, toErrorBody, unreachable };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { LunoraError } from './packem_shared/LunoraError-
|
|
2
|
-
export { ERROR_CATALOG, MESSAGE_SOLUTIONS, findSolutionByMessage, flattenHint, isInternalCode, resolveHint } from './packem_shared/ERROR_CATALOG-
|
|
1
|
+
export { LunoraError } from './packem_shared/LunoraError-B_Fjp5jb.mjs';
|
|
2
|
+
export { ERROR_CATALOG, MESSAGE_SOLUTIONS, findSolutionByMessage, flattenHint, isInternalCode, resolveHint } from './packem_shared/ERROR_CATALOG-0x-vRYNm.mjs';
|
|
3
3
|
export { isLunoraError } from './packem_shared/isLunoraError-CSQtYMrF.mjs';
|
|
4
|
-
export { invariant, unreachable } from './packem_shared/invariant-
|
|
5
|
-
export { toErrorBody } from './packem_shared/toErrorBody-
|
|
4
|
+
export { invariant, unreachable } from './packem_shared/invariant-BngUFrZs.mjs';
|
|
5
|
+
export { toErrorBody } from './packem_shared/toErrorBody-CKa-c46O.mjs';
|
|
@@ -63,6 +63,34 @@ const ERROR_CATALOG = {
|
|
|
63
63
|
ENV_INVALID: { internal: true, status: 500, title: "Invalid environment" },
|
|
64
64
|
/** Runtime-reachable (auth/middleware.ts): message carries auth-wiring guidance — redact on the wire. */
|
|
65
65
|
AUTH_HEADERS_MISSING: { internal: true, status: 500, title: "Auth headers missing" },
|
|
66
|
+
/**
|
|
67
|
+
* Signup rejected by `@lunora/auth`'s email-domain gate — a disposable/throwaway
|
|
68
|
+
* provider (or a caller deny-list hit). Client-safe: the message names only the
|
|
69
|
+
* offending domain class, never a secret, so it is echoed rather than redacted.
|
|
70
|
+
*/
|
|
71
|
+
EMAIL_DOMAIN_BLOCKED: {
|
|
72
|
+
hint: [
|
|
73
|
+
"This address's domain is on the disposable/throwaway blocklist (or your configured deny-list).",
|
|
74
|
+
"",
|
|
75
|
+
"Sign up with a permanent mailbox. To tune the policy, pass `blockDisposable` / `allowDomains` / `denyDomains` to `emailGate(...)` (`@lunora/auth/email-guard`)."
|
|
76
|
+
],
|
|
77
|
+
status: 400,
|
|
78
|
+
title: "Email domain not allowed"
|
|
79
|
+
},
|
|
80
|
+
/**
|
|
81
|
+
* Opt-in MX verification (`@lunora/auth/email-guard`, `mx: true`) found no mail
|
|
82
|
+
* exchanger for the address's domain, so mail to it would never deliver.
|
|
83
|
+
* Client-safe: names only the domain, no secret.
|
|
84
|
+
*/
|
|
85
|
+
EMAIL_UNDELIVERABLE: {
|
|
86
|
+
hint: [
|
|
87
|
+
"The address's domain publishes no MX (or fallback A/AAAA) records, so it can't receive mail.",
|
|
88
|
+
"",
|
|
89
|
+
"Check for a typo in the domain. MX verification is opt-in (`mx: true`) and needs DNS — leave it off on the edge path if DNS is unavailable."
|
|
90
|
+
],
|
|
91
|
+
status: 400,
|
|
92
|
+
title: "Email domain cannot receive mail"
|
|
93
|
+
},
|
|
66
94
|
/**
|
|
67
95
|
* Upstream Cloudflare API failures surfaced from an action. The message
|
|
68
96
|
* carries the upstream response body (Cloudflare's own error text — trusted
|
|
@@ -197,7 +225,7 @@ const MESSAGE_SOLUTIONS = [
|
|
|
197
225
|
test: (message) => message.includes("optimistic concurrency conflict")
|
|
198
226
|
}
|
|
199
227
|
];
|
|
200
|
-
const flattenHint = (hint) => (
|
|
228
|
+
const flattenHint = (hint) => (typeof hint === "string" ? hint : hint.join("\n")).split("\n").filter((line) => !line.startsWith("```")).join("\n").replaceAll(/\*\*(.+?)\*\*/gu, "$1").replaceAll(/`([^`]+)`/gu, "$1");
|
|
201
229
|
const findSolutionByMessage = (message) => {
|
|
202
230
|
for (const rule of MESSAGE_SOLUTIONS) {
|
|
203
231
|
if (rule.test(message)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/errors",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.7",
|
|
4
4
|
"description": "Unified error layer for Lunora: one LunoraError base + a central catalog of codes, statuses, and actionable hints, rendered across CLI, overlay, Studio, and the client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|