@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 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
- * 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
- */
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
- }; /** RPC/REST dispatch codes emitted by the runtime + Durable Object router. */
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
- }; /** Free-form internal failure — redacted to a generic message on the wire. */
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
- }; /** Package-specific codes. Build-time-only — never cross the RPC wire, so deliberately not `internal`. */
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
- * Upstream Cloudflare API failures surfaced from an action. The message
180
- * carries the upstream response body (Cloudflare's own error text trusted
181
- * infra, not user input), so it is echoed rather than redacted. `status`
182
- * here is a fallback; each throw passes the actual upstream HTTP status.
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
- * Discriminator recognised by `@visulima/error`'s `renderError`/`isVisulimaError`
288
- * (`error.type === "VisulimaError"`), so a `LunoraError` renders like a native
289
- * `VisulimaError` — hint and all.
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
- * Wire-encode a `LunoraError`'s structured `data` for the client (so a
340
- * `bigint`/`bytes` inside it survives). Omit to drop `data` from the body.
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
- * 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
- */
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
- }; /** RPC/REST dispatch codes emitted by the runtime + Durable Object router. */
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
- }; /** Free-form internal failure — redacted to a generic message on the wire. */
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
- }; /** Package-specific codes. Build-time-only — never cross the RPC wire, so deliberately not `internal`. */
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
- * Upstream Cloudflare API failures surfaced from an action. The message
180
- * carries the upstream response body (Cloudflare's own error text trusted
181
- * infra, not user input), so it is echoed rather than redacted. `status`
182
- * here is a fallback; each throw passes the actual upstream HTTP status.
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
- * Discriminator recognised by `@visulima/error`'s `renderError`/`isVisulimaError`
288
- * (`error.type === "VisulimaError"`), so a `LunoraError` renders like a native
289
- * `VisulimaError` — hint and all.
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
- * Wire-encode a `LunoraError`'s structured `data` for the client (so a
340
- * `bigint`/`bytes` inside it survives). Omit to drop `data` from the body.
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-Cdb2-Hda.mjs';
2
- export { ERROR_CATALOG, MESSAGE_SOLUTIONS, findSolutionByMessage, flattenHint, isInternalCode, resolveHint } from './packem_shared/ERROR_CATALOG-pJvm6SQP.mjs';
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-HhlkSkbP.mjs';
5
- export { toErrorBody } from './packem_shared/toErrorBody-BXvKCSrv.mjs';
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) => (Array.isArray(hint) ? hint.join("\n") : hint).split("\n").filter((line) => !line.startsWith("```")).join("\n").replaceAll(/\*\*(.+?)\*\*/gu, "$1").replaceAll(/`([^`]+)`/gu, "$1");
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)) {
@@ -1,4 +1,4 @@
1
- import { getCatalogEntry } from './ERROR_CATALOG-pJvm6SQP.mjs';
1
+ import { getCatalogEntry } from './ERROR_CATALOG-0x-vRYNm.mjs';
2
2
 
3
3
  class LunoraError extends Error {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { LunoraError } from './LunoraError-Cdb2-Hda.mjs';
1
+ import { LunoraError } from './LunoraError-B_Fjp5jb.mjs';
2
2
 
3
3
  const invariant = (condition, message) => {
4
4
  if (!condition) {
@@ -1,4 +1,4 @@
1
- import { isInternalCode, resolveHint } from './ERROR_CATALOG-pJvm6SQP.mjs';
1
+ import { isInternalCode, resolveHint } from './ERROR_CATALOG-0x-vRYNm.mjs';
2
2
  import { isLunoraError } from './isLunoraError-CSQtYMrF.mjs';
3
3
 
4
4
  const toErrorBody = (error, options = {}) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/errors",
3
- "version": "1.0.0-alpha.5",
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",