@lunora/errors 1.0.0-alpha.1 → 1.0.0-alpha.3

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/LICENSE.md CHANGED
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
103
103
  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
104
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
105
  specific language governing permissions and limitations under the License.
106
+
107
+ <!-- DEPENDENCIES -->
108
+ <!-- /DEPENDENCIES -->
109
+
110
+ <!-- TYPE_DEPENDENCIES -->
111
+ <!-- /TYPE_DEPENDENCIES -->
package/dist/index.d.mts CHANGED
@@ -59,9 +59,9 @@ declare const ERROR_CATALOG: {
59
59
  readonly title: "Conflict";
60
60
  };
61
61
  readonly NOT_UNIQUE: {
62
- readonly hint: readonly ["A row with the same value already exists in a `unique` index.", "", "- If you meant to upsert, use `ctx.db.<table>().upsert(...)` (or `.patch(...)` an existing row) instead of `.insert(...)`.", "- Otherwise pick a value that isn't already taken, and consider surfacing a friendly \"already exists\" message to the user."];
62
+ readonly hint: readonly ["`.unique()` matched more than one document — it expects the query to identify at most one row.", "", "- If several matches are legitimate, use `.first()` (take one) or `.collect()` (take all) instead.", "- Otherwise tighten the query (e.g. filter on a unique/indexed field) so it can only match one row."];
63
63
  readonly status: 400;
64
- readonly title: "Unique constraint violation";
64
+ readonly title: "Query matched more than one document";
65
65
  };
66
66
  readonly VALIDATION_ERROR: {
67
67
  readonly status: 400;
@@ -125,6 +125,23 @@ declare const ERROR_CATALOG: {
125
125
  readonly status: 403;
126
126
  readonly title: "RLS policy required";
127
127
  };
128
+ readonly RUN_DEPTH_EXCEEDED: {
129
+ readonly internal: true;
130
+ readonly status: 500;
131
+ readonly title: "Run depth exceeded";
132
+ };
133
+ readonly MIGRATION_NOT_FOUND: {
134
+ readonly status: 404;
135
+ readonly title: "Data migration not found";
136
+ };
137
+ readonly UNKNOWN_TABLE: {
138
+ readonly status: 404;
139
+ readonly title: "Unknown table";
140
+ };
141
+ readonly GLOBAL_TABLE_NOT_EDITABLE: {
142
+ readonly status: 400;
143
+ readonly title: "Global table is not editable";
144
+ };
128
145
  readonly SHARD_ERROR: {
129
146
  readonly status: 503;
130
147
  readonly title: "Shard error";
@@ -136,20 +153,25 @@ declare const ERROR_CATALOG: {
136
153
  readonly OFFLINE_IDENTITY_CHANGED: {
137
154
  readonly status: 409;
138
155
  readonly title: "Offline identity changed";
139
- }; /** Package-specific codes. Build-time (codegen) codes never cross the RPC wire. */
156
+ }; /** Package-specific codes. Build-time-only never cross the RPC wire, so deliberately not `internal`. */
140
157
  readonly CODEGEN_DIAGNOSTIC: {
141
158
  readonly status: 500;
142
159
  readonly title: "Codegen diagnostic";
143
160
  };
161
+ /** Build-time-only — never crosses the RPC wire, so deliberately not `internal`. */
144
162
  readonly SCHEMA_SNAPSHOT_PARSE: {
145
163
  readonly status: 500;
146
164
  readonly title: "Schema snapshot parse error";
147
165
  };
166
+ /** Runtime-reachable (env.ts): message enumerates failing env key names — redact on the wire. */
148
167
  readonly ENV_INVALID: {
168
+ readonly internal: true;
149
169
  readonly status: 500;
150
170
  readonly title: "Invalid environment";
151
171
  };
172
+ /** Runtime-reachable (auth/middleware.ts): message carries auth-wiring guidance — redact on the wire. */
152
173
  readonly AUTH_HEADERS_MISSING: {
174
+ readonly internal: true;
153
175
  readonly status: 500;
154
176
  readonly title: "Auth headers missing";
155
177
  };
@@ -290,8 +312,15 @@ interface LunoraErrorLike extends Error {
290
312
  docsUrl?: string;
291
313
  hint?: ErrorHint;
292
314
  status: number;
315
+ /** Wire brand that distinguishes real `LunoraError`s from foreign errors. */
316
+ type: "VisulimaError";
293
317
  }
294
- /** True when `error` carries the Lunora transport shape (string `code` + numeric `status`). */
318
+ /**
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
+ */
295
324
  declare const isLunoraError: (error: unknown) => error is LunoraErrorLike;
296
325
  /** Throw an `INTERNAL` {@link LunoraError} when `condition` is falsy. */
297
326
  declare const invariant: (condition: unknown, message: string) => asserts condition;
package/dist/index.d.ts CHANGED
@@ -59,9 +59,9 @@ declare const ERROR_CATALOG: {
59
59
  readonly title: "Conflict";
60
60
  };
61
61
  readonly NOT_UNIQUE: {
62
- readonly hint: readonly ["A row with the same value already exists in a `unique` index.", "", "- If you meant to upsert, use `ctx.db.<table>().upsert(...)` (or `.patch(...)` an existing row) instead of `.insert(...)`.", "- Otherwise pick a value that isn't already taken, and consider surfacing a friendly \"already exists\" message to the user."];
62
+ readonly hint: readonly ["`.unique()` matched more than one document — it expects the query to identify at most one row.", "", "- If several matches are legitimate, use `.first()` (take one) or `.collect()` (take all) instead.", "- Otherwise tighten the query (e.g. filter on a unique/indexed field) so it can only match one row."];
63
63
  readonly status: 400;
64
- readonly title: "Unique constraint violation";
64
+ readonly title: "Query matched more than one document";
65
65
  };
66
66
  readonly VALIDATION_ERROR: {
67
67
  readonly status: 400;
@@ -125,6 +125,23 @@ declare const ERROR_CATALOG: {
125
125
  readonly status: 403;
126
126
  readonly title: "RLS policy required";
127
127
  };
128
+ readonly RUN_DEPTH_EXCEEDED: {
129
+ readonly internal: true;
130
+ readonly status: 500;
131
+ readonly title: "Run depth exceeded";
132
+ };
133
+ readonly MIGRATION_NOT_FOUND: {
134
+ readonly status: 404;
135
+ readonly title: "Data migration not found";
136
+ };
137
+ readonly UNKNOWN_TABLE: {
138
+ readonly status: 404;
139
+ readonly title: "Unknown table";
140
+ };
141
+ readonly GLOBAL_TABLE_NOT_EDITABLE: {
142
+ readonly status: 400;
143
+ readonly title: "Global table is not editable";
144
+ };
128
145
  readonly SHARD_ERROR: {
129
146
  readonly status: 503;
130
147
  readonly title: "Shard error";
@@ -136,20 +153,25 @@ declare const ERROR_CATALOG: {
136
153
  readonly OFFLINE_IDENTITY_CHANGED: {
137
154
  readonly status: 409;
138
155
  readonly title: "Offline identity changed";
139
- }; /** Package-specific codes. Build-time (codegen) codes never cross the RPC wire. */
156
+ }; /** Package-specific codes. Build-time-only never cross the RPC wire, so deliberately not `internal`. */
140
157
  readonly CODEGEN_DIAGNOSTIC: {
141
158
  readonly status: 500;
142
159
  readonly title: "Codegen diagnostic";
143
160
  };
161
+ /** Build-time-only — never crosses the RPC wire, so deliberately not `internal`. */
144
162
  readonly SCHEMA_SNAPSHOT_PARSE: {
145
163
  readonly status: 500;
146
164
  readonly title: "Schema snapshot parse error";
147
165
  };
166
+ /** Runtime-reachable (env.ts): message enumerates failing env key names — redact on the wire. */
148
167
  readonly ENV_INVALID: {
168
+ readonly internal: true;
149
169
  readonly status: 500;
150
170
  readonly title: "Invalid environment";
151
171
  };
172
+ /** Runtime-reachable (auth/middleware.ts): message carries auth-wiring guidance — redact on the wire. */
152
173
  readonly AUTH_HEADERS_MISSING: {
174
+ readonly internal: true;
153
175
  readonly status: 500;
154
176
  readonly title: "Auth headers missing";
155
177
  };
@@ -290,8 +312,15 @@ interface LunoraErrorLike extends Error {
290
312
  docsUrl?: string;
291
313
  hint?: ErrorHint;
292
314
  status: number;
315
+ /** Wire brand that distinguishes real `LunoraError`s from foreign errors. */
316
+ type: "VisulimaError";
293
317
  }
294
- /** True when `error` carries the Lunora transport shape (string `code` + numeric `status`). */
318
+ /**
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
+ */
295
324
  declare const isLunoraError: (error: unknown) => error is LunoraErrorLike;
296
325
  /** Throw an `INTERNAL` {@link LunoraError} when `condition` is falsy. */
297
326
  declare const invariant: (condition: unknown, message: string) => asserts condition;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- export { LunoraError } from './packem_shared/LunoraError-bpS_TPIe.mjs';
2
- export { ERROR_CATALOG, MESSAGE_SOLUTIONS, findSolutionByMessage, flattenHint, isInternalCode, resolveHint } from './packem_shared/ERROR_CATALOG-D3knuUQT.mjs';
3
- export { isLunoraError } from './packem_shared/isLunoraError-BvsoKcWE.mjs';
4
- export { invariant, unreachable } from './packem_shared/invariant-DLXTsHpj.mjs';
5
- export { toErrorBody } from './packem_shared/toErrorBody-DihI5p4Q.mjs';
1
+ export { LunoraError } from './packem_shared/LunoraError-CwQSmeL3.mjs';
2
+ export { ERROR_CATALOG, MESSAGE_SOLUTIONS, findSolutionByMessage, flattenHint, isInternalCode, resolveHint } from './packem_shared/ERROR_CATALOG-CoCPcAHf.mjs';
3
+ export { isLunoraError } from './packem_shared/isLunoraError-CSQtYMrF.mjs';
4
+ export { invariant, unreachable } from './packem_shared/invariant-DawIQfjN.mjs';
5
+ export { toErrorBody } from './packem_shared/toErrorBody-CyqyVwGF.mjs';
@@ -14,13 +14,13 @@ const ERROR_CATALOG = {
14
14
  },
15
15
  NOT_UNIQUE: {
16
16
  hint: [
17
- "A row with the same value already exists in a `unique` index.",
17
+ "`.unique()` matched more than one document — it expects the query to identify at most one row.",
18
18
  "",
19
- "- If you meant to upsert, use `ctx.db.<table>().upsert(...)` (or `.patch(...)` an existing row) instead of `.insert(...)`.",
20
- `- Otherwise pick a value that isn't already taken, and consider surfacing a friendly "already exists" message to the user.`
19
+ "- If several matches are legitimate, use `.first()` (take one) or `.collect()` (take all) instead.",
20
+ "- Otherwise tighten the query (e.g. filter on a unique/indexed field) so it can only match one row."
21
21
  ],
22
22
  status: 400,
23
- title: "Unique constraint violation"
23
+ title: "Query matched more than one document"
24
24
  },
25
25
  VALIDATION_ERROR: { status: 400, title: "Validation failed" },
26
26
  TOO_MANY_REQUESTS: { status: 429, title: "Too many requests" },
@@ -48,14 +48,21 @@ const ERROR_CATALOG = {
48
48
  status: 403,
49
49
  title: "RLS policy required"
50
50
  },
51
+ RUN_DEPTH_EXCEEDED: { internal: true, status: 500, title: "Run depth exceeded" },
52
+ MIGRATION_NOT_FOUND: { status: 404, title: "Data migration not found" },
53
+ UNKNOWN_TABLE: { status: 404, title: "Unknown table" },
54
+ GLOBAL_TABLE_NOT_EDITABLE: { status: 400, title: "Global table is not editable" },
51
55
  SHARD_ERROR: { status: 503, title: "Shard error" },
52
56
  SHARD_UNAVAILABLE: { status: 503, title: "Shard unavailable" },
53
57
  OFFLINE_IDENTITY_CHANGED: { status: 409, title: "Offline identity changed" },
54
- /** Package-specific codes. Build-time (codegen) codes never cross the RPC wire. */
58
+ /** Package-specific codes. Build-time-only never cross the RPC wire, so deliberately not `internal`. */
55
59
  CODEGEN_DIAGNOSTIC: { status: 500, title: "Codegen diagnostic" },
60
+ /** Build-time-only — never crosses the RPC wire, so deliberately not `internal`. */
56
61
  SCHEMA_SNAPSHOT_PARSE: { status: 500, title: "Schema snapshot parse error" },
57
- ENV_INVALID: { status: 500, title: "Invalid environment" },
58
- AUTH_HEADERS_MISSING: { status: 500, title: "Auth headers missing" },
62
+ /** Runtime-reachable (env.ts): message enumerates failing env key names — redact on the wire. */
63
+ ENV_INVALID: { internal: true, status: 500, title: "Invalid environment" },
64
+ /** Runtime-reachable (auth/middleware.ts): message carries auth-wiring guidance — redact on the wire. */
65
+ AUTH_HEADERS_MISSING: { internal: true, status: 500, title: "Auth headers missing" },
59
66
  /**
60
67
  * Upstream Cloudflare API failures surfaced from an action. The message
61
68
  * carries the upstream response body (Cloudflare's own error text — trusted
@@ -167,7 +174,17 @@ const MESSAGE_SOLUTIONS = [
167
174
  test: (message) => message.includes("not exported by your worker entry")
168
175
  },
169
176
  {
170
- body: ERROR_CATALOG.NOT_UNIQUE.hint.join("\n"),
177
+ // Deliberately NOT ERROR_CATALOG.NOT_UNIQUE.hint: that code (and hint)
178
+ // describes the read-side `.unique()` multi-match, while this matcher
179
+ // fires on the WRITE-path message ("unique constraint violation on
180
+ // <table>") thrown as a CONFLICT by an insert/patch breaching a
181
+ // `unique` index — a different error class needing insert remediation.
182
+ body: [
183
+ "A row with the same value already exists in a `unique` index.",
184
+ "",
185
+ "- If you meant to upsert, use `ctx.db.<table>().upsert(...)` (or `.patch(...)` an existing row) instead of `.insert(...)`.",
186
+ `- Otherwise pick a value that isn't already taken, and consider surfacing a friendly "already exists" message to the user.`
187
+ ].join("\n"),
171
188
  header: "Unique constraint violation",
172
189
  id: "lunora-runtime-unique",
173
190
  test: (message) => message.includes("unique constraint violation on")
@@ -1,4 +1,4 @@
1
- import { ERROR_CATALOG } from './ERROR_CATALOG-D3knuUQT.mjs';
1
+ import { ERROR_CATALOG } from './ERROR_CATALOG-CoCPcAHf.mjs';
2
2
 
3
3
  class LunoraError extends Error {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { LunoraError } from './LunoraError-bpS_TPIe.mjs';
1
+ import { LunoraError } from './LunoraError-CwQSmeL3.mjs';
2
2
 
3
3
  const invariant = (condition, message) => {
4
4
  if (!condition) {
@@ -3,7 +3,7 @@ const isLunoraError = (error) => {
3
3
  return false;
4
4
  }
5
5
  const candidate = error;
6
- return typeof candidate.code === "string" && typeof candidate.status === "number";
6
+ return candidate.type === "VisulimaError" && typeof candidate.code === "string" && typeof candidate.status === "number";
7
7
  };
8
8
 
9
9
  export { isLunoraError };
@@ -1,5 +1,5 @@
1
- import { isInternalCode, resolveHint } from './ERROR_CATALOG-D3knuUQT.mjs';
2
- import { isLunoraError } from './isLunoraError-BvsoKcWE.mjs';
1
+ import { isInternalCode, resolveHint } from './ERROR_CATALOG-CoCPcAHf.mjs';
2
+ import { isLunoraError } from './isLunoraError-CSQtYMrF.mjs';
3
3
 
4
4
  const toErrorBody = (error, options = {}) => {
5
5
  const redactedMessage = options.redactedMessage ?? "Internal error";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/errors",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.3",
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",