honertia 0.1.21 → 0.1.22
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/README.md +111 -4
- package/dist/effect/binding.d.ts.map +1 -1
- package/dist/effect/binding.js +1 -4
- package/dist/effect/bridge.d.ts.map +1 -1
- package/dist/effect/bridge.js +11 -3
- package/dist/effect/error-catalog.d.ts +100 -0
- package/dist/effect/error-catalog.d.ts.map +1 -0
- package/dist/effect/error-catalog.js +700 -0
- package/dist/effect/error-context.d.ts +99 -0
- package/dist/effect/error-context.d.ts.map +1 -0
- package/dist/effect/error-context.js +230 -0
- package/dist/effect/error-formatter.d.ts +143 -0
- package/dist/effect/error-formatter.d.ts.map +1 -0
- package/dist/effect/error-formatter.js +355 -0
- package/dist/effect/error-types.d.ts +275 -0
- package/dist/effect/error-types.d.ts.map +1 -0
- package/dist/effect/error-types.js +7 -0
- package/dist/effect/errors.d.ts +183 -15
- package/dist/effect/errors.d.ts.map +1 -1
- package/dist/effect/errors.js +333 -8
- package/dist/effect/handler.d.ts +6 -0
- package/dist/effect/handler.d.ts.map +1 -1
- package/dist/effect/handler.js +124 -12
- package/dist/effect/index.d.ts +7 -3
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +9 -3
- package/dist/effect/validation.d.ts +16 -0
- package/dist/effect/validation.d.ts.map +1 -1
- package/dist/effect/validation.js +70 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +5 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +77 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1402,25 +1402,132 @@ registerErrorHandlers(app, {
|
|
|
1402
1402
|
})
|
|
1403
1403
|
```
|
|
1404
1404
|
|
|
1405
|
-
Your `Error` component receives:
|
|
1405
|
+
Your `Error` component receives structured error props that vary by environment:
|
|
1406
|
+
|
|
1407
|
+
**In Development** (`ENVIRONMENT=development`):
|
|
1408
|
+
|
|
1409
|
+
```json
|
|
1410
|
+
{
|
|
1411
|
+
"status": 500,
|
|
1412
|
+
"code": "HON_CFG_100_DATABASE_NOT_CONFIGURED",
|
|
1413
|
+
"title": "Database Not Configured",
|
|
1414
|
+
"message": "DatabaseService is not configured. Add it to setupHonertia.",
|
|
1415
|
+
"hint": "Add database to setupHonertia config",
|
|
1416
|
+
"fixes": [{ "description": "Add database config", "confidence": "high" }],
|
|
1417
|
+
"source": { "file": "src/routes/projects.ts", "line": 42 },
|
|
1418
|
+
"docsUrl": "https://..."
|
|
1419
|
+
}
|
|
1420
|
+
```
|
|
1421
|
+
|
|
1422
|
+
**In Production** (`ENVIRONMENT=production` or unset):
|
|
1423
|
+
|
|
1424
|
+
```json
|
|
1425
|
+
{
|
|
1426
|
+
"status": 500,
|
|
1427
|
+
"code": "HON_CFG_100_DATABASE_NOT_CONFIGURED",
|
|
1428
|
+
"title": "Database Not Configured",
|
|
1429
|
+
"message": "An error occurred. Please try again later."
|
|
1430
|
+
}
|
|
1431
|
+
```
|
|
1432
|
+
|
|
1433
|
+
In production, sensitive details (stack traces, source locations, hints, fixes) are automatically hidden while the error code and title remain visible for debugging reference.
|
|
1434
|
+
|
|
1435
|
+
**Example React Error Component:**
|
|
1406
1436
|
|
|
1407
1437
|
```tsx
|
|
1408
1438
|
// src/pages/Error.tsx
|
|
1409
1439
|
interface ErrorProps {
|
|
1410
|
-
status: number
|
|
1411
|
-
|
|
1440
|
+
status: number
|
|
1441
|
+
code: string
|
|
1442
|
+
title: string
|
|
1443
|
+
message: string
|
|
1444
|
+
hint?: string
|
|
1445
|
+
fixes?: Array<{ description: string; confidence: string }>
|
|
1446
|
+
source?: { file: string; line: number }
|
|
1447
|
+
docsUrl?: string
|
|
1412
1448
|
}
|
|
1413
1449
|
|
|
1414
|
-
export default function Error(
|
|
1450
|
+
export default function Error(props: ErrorProps) {
|
|
1451
|
+
const { status, title, message, hint, fixes, source, docsUrl } = props
|
|
1452
|
+
|
|
1415
1453
|
return (
|
|
1416
1454
|
<div className="error-page">
|
|
1417
1455
|
<h1>{status}</h1>
|
|
1456
|
+
<h2>{title}</h2>
|
|
1418
1457
|
<p>{message}</p>
|
|
1458
|
+
|
|
1459
|
+
{/* Only shown in dev (these props won't exist in prod) */}
|
|
1460
|
+
{hint && <p className="hint">{hint}</p>}
|
|
1461
|
+
|
|
1462
|
+
{source && (
|
|
1463
|
+
<code>{source.file}:{source.line}</code>
|
|
1464
|
+
)}
|
|
1465
|
+
|
|
1466
|
+
{fixes?.map((fix, i) => (
|
|
1467
|
+
<div key={i} className={`fix fix-${fix.confidence}`}>
|
|
1468
|
+
{fix.description}
|
|
1469
|
+
</div>
|
|
1470
|
+
))}
|
|
1471
|
+
|
|
1472
|
+
{docsUrl && <a href={docsUrl}>View Documentation</a>}
|
|
1419
1473
|
</div>
|
|
1420
1474
|
)
|
|
1421
1475
|
}
|
|
1422
1476
|
```
|
|
1423
1477
|
|
|
1478
|
+
### Environment Detection
|
|
1479
|
+
|
|
1480
|
+
Honertia automatically detects development mode by checking environment variables:
|
|
1481
|
+
|
|
1482
|
+
```typescript
|
|
1483
|
+
// Checks these in order:
|
|
1484
|
+
// 1. env.ENVIRONMENT === 'development'
|
|
1485
|
+
// 2. env.NODE_ENV === 'development'
|
|
1486
|
+
// 3. env.CF_PAGES_BRANCH !== undefined (Cloudflare Pages preview deployments)
|
|
1487
|
+
```
|
|
1488
|
+
|
|
1489
|
+
To enable development mode, set the environment variable in your Hono app:
|
|
1490
|
+
|
|
1491
|
+
```toml
|
|
1492
|
+
# wrangler.toml
|
|
1493
|
+
[vars]
|
|
1494
|
+
ENVIRONMENT = "development"
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
Or for Bun/Node:
|
|
1498
|
+
|
|
1499
|
+
```typescript
|
|
1500
|
+
// Pass env via Bun.serve or test setup
|
|
1501
|
+
const app = new Hono<{ Bindings: { ENVIRONMENT: string } }>()
|
|
1502
|
+
```
|
|
1503
|
+
|
|
1504
|
+
### Safe Message Filtering
|
|
1505
|
+
|
|
1506
|
+
For sensitive error categories, production automatically shows generic messages instead of implementation details:
|
|
1507
|
+
|
|
1508
|
+
| Category | Production Message |
|
|
1509
|
+
|----------|-------------------|
|
|
1510
|
+
| `configuration` | "An error occurred. Please try again later." |
|
|
1511
|
+
| `internal` | "An error occurred. Please try again later." |
|
|
1512
|
+
| `database` | "An error occurred. Please try again later." |
|
|
1513
|
+
| `validation` | Original message (safe to show) |
|
|
1514
|
+
| `auth` | Original message (safe to show) |
|
|
1515
|
+
|
|
1516
|
+
This ensures that configuration mistakes, database errors, and internal implementation details are never leaked to end users in production.
|
|
1517
|
+
|
|
1518
|
+
### Error Handler Options
|
|
1519
|
+
|
|
1520
|
+
The `registerErrorHandlers` function accepts these options:
|
|
1521
|
+
|
|
1522
|
+
```typescript
|
|
1523
|
+
registerErrorHandlers(app, {
|
|
1524
|
+
component: 'Error', // React component name (required)
|
|
1525
|
+
showDevErrors: true, // Set false to always hide details (default: true)
|
|
1526
|
+
envKey: 'ENVIRONMENT', // Which env var to check (default: 'ENVIRONMENT')
|
|
1527
|
+
devValue: 'development', // What value means "dev mode" (default: 'development')
|
|
1528
|
+
})
|
|
1529
|
+
```
|
|
1530
|
+
|
|
1424
1531
|
### Error Handling Flow
|
|
1425
1532
|
|
|
1426
1533
|
```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/effect/binding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAQ,MAAM,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAA;;;;AAWrD;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAC;IACA,IAAI,OAAO,WAEV;CACF;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAA;IACb,uEAAuE;IACvE,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAa3D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,gBAG9B;CAAG;AAEN;;;GAGG;AACH,KAAK,SAAS,CAAC,CAAC,SAAS,MAAM,IAC7B,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAC/D,CAAC,SAAS,GAAG,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,GACzC,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,GAC/E,GAAG,CAAC,GAAG,CAAA;AAET;;GAEG;AACH,UAAU,uBAAuB,CAAC,CAAC,SAAS,MAAM;IAChD,QAAQ,CAAC,OAAO,EAAE,gCAAgC,CAAC,oDAAoD,CAAA;IACvG,QAAQ,CAAC,MAAM,EAAE,wHAAwH,CAAA;CAC1I;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAErC,UAAU,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC,uBAAuB,CAAC,CAAC,CAAC,GAC1B,SAAS,CAAC,CAAC,CAAC,SAAS,MAAM,UAAU,GACnC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,GACpC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GACxC,OAAO,GACT,CAAC,SAAS,MAAM,UAAU,GACxB,UAAU,CAAC,CAAC,CAAC,SAAS,KAAK,GACzB,UAAU,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAC7B,OAAO,GACT,OAAO,CAAA;AAEjB;;;;;;;;GAQG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,SAAS,MAAM,EACpC,KAAK,CAAC,KACL,MAAM,CAAC,MAAM,CACd,UAAU,CAAC,CAAC,CAAC,EACb,kBAAkB,GAAG,uBAAuB,EAC5C,WAAW,
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/effect/binding.ts"],"names":[],"mappings":"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"}
|
package/dist/effect/binding.js
CHANGED
|
@@ -63,10 +63,7 @@ export const bound = (key) => Effect.gen(function* () {
|
|
|
63
63
|
const models = yield* BoundModels;
|
|
64
64
|
// Check if schema was not configured (sentinel value set by routing.ts)
|
|
65
65
|
if (models.has('__schema_not_configured__')) {
|
|
66
|
-
return yield*
|
|
67
|
-
message: `Route model binding requires schema configuration. Cannot resolve bound('${key}') without schema.`,
|
|
68
|
-
hint: `Pass your schema to setupHonertia: setupHonertia({ honertia: { schema } })`
|
|
69
|
-
});
|
|
66
|
+
return yield* RouteConfigurationError.schemaNotConfigured(key);
|
|
70
67
|
}
|
|
71
68
|
const model = models.get(key);
|
|
72
69
|
if (!model) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAG9C,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAC1E,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,eAAe,EAQhB,MAAM,eAAe,CAAA;AAEtB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK;IACvE;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;IAC3E;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACjC;AAED;;GAEG;AACH,QAAA,MAAM,cAAc,eAA0B,CAAA;AAE9C;;GAEG;AACH,QAAA,MAAM,aAAa,eAAyB,CAAA;AAsC5C;;GAEG;AACH,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,CAAC,cAAc,CAAC,CAAC,EAAE,cAAc,CAAC,cAAc,CAC5C,eAAe,GACf,WAAW,GACX,eAAe,GACf,eAAe,GACf,cAAc,GACd,sBAAsB,EACxB,KAAK,CACN,CAAA;QACD,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAC1C;CACF;AAsDD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK,EACrE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACjB,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,cAAc,CAAC,GAC7C,KAAK,CAAC,KAAK,CACV,cAAc,GACd,sBAAsB,GACtB,eAAe,GACf,eAAe,GACf,WAAW,GACX,eAAe,GACf,eAAe,GACf,cAAc,EAChB,KAAK,EACL,KAAK,CACN,CAoEA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,EAC5C,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAChB,cAAc,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,SAAS,CAEvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK,EAChE,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,cAAc,CAAC,GAC7C,iBAAiB,CAAC,CAAC,CAAC,CAoBtB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,GAAG,EAC3C,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAErC"}
|
package/dist/effect/bridge.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Layer, ManagedRuntime } from 'effect';
|
|
7
7
|
import { HonertiaConfigurationError } from './errors.js';
|
|
8
|
+
import { ErrorCodes } from './error-catalog.js';
|
|
8
9
|
import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, } from './services.js';
|
|
9
10
|
/**
|
|
10
11
|
* Symbol for storing Effect runtime in Hono context.
|
|
@@ -17,8 +18,13 @@ const EFFECT_SCHEMA = Symbol('effectSchema');
|
|
|
17
18
|
/**
|
|
18
19
|
* Creates a proxy that throws a helpful error when any property is accessed.
|
|
19
20
|
* Used when a service (database, auth) is not configured but the user tries to use it.
|
|
21
|
+
*
|
|
22
|
+
* @param serviceName - The name of the unconfigured service.
|
|
23
|
+
* @param configPath - The configuration path hint (e.g., 'database: (c) => ...').
|
|
24
|
+
* @param example - An example of how to configure the service.
|
|
25
|
+
* @param errorCode - The specific error code to use.
|
|
20
26
|
*/
|
|
21
|
-
function createUnconfiguredServiceProxy(serviceName, configPath, example) {
|
|
27
|
+
function createUnconfiguredServiceProxy(serviceName, configPath, example, errorCode) {
|
|
22
28
|
const message = `${serviceName} is not configured. Add it to setupHonertia: setupHonertia({ honertia: { ${configPath} } })`;
|
|
23
29
|
return new Proxy({}, {
|
|
24
30
|
get(_, prop) {
|
|
@@ -29,6 +35,8 @@ function createUnconfiguredServiceProxy(serviceName, configPath, example) {
|
|
|
29
35
|
throw new HonertiaConfigurationError({
|
|
30
36
|
message,
|
|
31
37
|
hint: `Example: ${example}`,
|
|
38
|
+
code: errorCode,
|
|
39
|
+
service: serviceName,
|
|
32
40
|
});
|
|
33
41
|
},
|
|
34
42
|
});
|
|
@@ -94,11 +102,11 @@ export function buildContextLayer(c, config) {
|
|
|
94
102
|
// Database layer - provide helpful error proxy if not configured
|
|
95
103
|
const db = c.var?.db;
|
|
96
104
|
const databaseLayer = Layer.succeed(DatabaseService, (db ??
|
|
97
|
-
createUnconfiguredServiceProxy('DatabaseService', 'database: (c) => createDb(...)', 'database: (c) => drizzle(c.env.DB)')));
|
|
105
|
+
createUnconfiguredServiceProxy('DatabaseService', 'database: (c) => createDb(...)', 'database: (c) => drizzle(c.env.DB)', ErrorCodes.CFG_300_DATABASE_NOT_CONFIGURED)));
|
|
98
106
|
// Auth layer - provide helpful error proxy if not configured
|
|
99
107
|
const auth = c.var?.auth;
|
|
100
108
|
const authLayer = Layer.succeed(AuthService, (auth ??
|
|
101
|
-
createUnconfiguredServiceProxy('AuthService', 'auth: (c) => createAuth(...)', 'auth: (c) => betterAuth({ database: c.var.db, ... })')));
|
|
109
|
+
createUnconfiguredServiceProxy('AuthService', 'auth: (c) => createAuth(...)', 'auth: (c) => betterAuth({ database: c.var.db, ... })', ErrorCodes.CFG_301_AUTH_NOT_CONFIGURED)));
|
|
102
110
|
let baseLayer = Layer.mergeAll(requestLayer, responseLayer, honertiaLayer, bindingsLayer, databaseLayer, authLayer);
|
|
103
111
|
if (c.var?.authUser) {
|
|
104
112
|
baseLayer = Layer.merge(baseLayer, Layer.succeed(AuthUserService, c.var.authUser));
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Catalog for Honertia
|
|
3
|
+
*
|
|
4
|
+
* Central registry of all error codes with fix generators.
|
|
5
|
+
* This is the single source of truth for error definitions.
|
|
6
|
+
*/
|
|
7
|
+
import type { ErrorCategory, ErrorContext, ErrorDefinition, HonertiaStructuredError } from './error-types.js';
|
|
8
|
+
/**
|
|
9
|
+
* All Honertia error codes organized by category.
|
|
10
|
+
*
|
|
11
|
+
* Naming convention: HON_<CATEGORY>_<NUMBER>_<NAME>
|
|
12
|
+
*
|
|
13
|
+
* Categories:
|
|
14
|
+
* - VAL (001-099): Validation errors
|
|
15
|
+
* - AUTH (100-199): Authentication/authorization
|
|
16
|
+
* - RES (200-299): Resource errors
|
|
17
|
+
* - CFG (300-399): Configuration errors
|
|
18
|
+
* - HTTP (400-499): HTTP errors
|
|
19
|
+
* - DB (500-599): Database errors
|
|
20
|
+
* - RTE (600-699): Routing errors
|
|
21
|
+
* - SVC (700-799): Service errors
|
|
22
|
+
* - INT (800-899): Internal errors
|
|
23
|
+
*/
|
|
24
|
+
export declare const ErrorCodes: {
|
|
25
|
+
readonly VAL_001_FIELD_REQUIRED: "HON_VAL_001_FIELD_REQUIRED";
|
|
26
|
+
readonly VAL_002_FIELD_INVALID: "HON_VAL_002_FIELD_INVALID";
|
|
27
|
+
readonly VAL_003_BODY_PARSE_FAILED: "HON_VAL_003_BODY_PARSE_FAILED";
|
|
28
|
+
readonly VAL_004_SCHEMA_MISMATCH: "HON_VAL_004_SCHEMA_MISMATCH";
|
|
29
|
+
readonly VAL_005_TYPE_COERCION_FAILED: "HON_VAL_005_TYPE_COERCION_FAILED";
|
|
30
|
+
readonly AUTH_100_UNAUTHENTICATED: "HON_AUTH_100_UNAUTHENTICATED";
|
|
31
|
+
readonly AUTH_101_SESSION_EXPIRED: "HON_AUTH_101_SESSION_EXPIRED";
|
|
32
|
+
readonly AUTH_102_FORBIDDEN: "HON_AUTH_102_FORBIDDEN";
|
|
33
|
+
readonly AUTH_103_INVALID_CREDENTIALS: "HON_AUTH_103_INVALID_CREDENTIALS";
|
|
34
|
+
readonly RES_200_NOT_FOUND: "HON_RES_200_NOT_FOUND";
|
|
35
|
+
readonly RES_201_ALREADY_EXISTS: "HON_RES_201_ALREADY_EXISTS";
|
|
36
|
+
readonly RES_202_GONE: "HON_RES_202_GONE";
|
|
37
|
+
readonly CFG_300_DATABASE_NOT_CONFIGURED: "HON_CFG_300_DATABASE_NOT_CONFIGURED";
|
|
38
|
+
readonly CFG_301_AUTH_NOT_CONFIGURED: "HON_CFG_301_AUTH_NOT_CONFIGURED";
|
|
39
|
+
readonly CFG_302_SCHEMA_NOT_CONFIGURED: "HON_CFG_302_SCHEMA_NOT_CONFIGURED";
|
|
40
|
+
readonly CFG_303_HONERTIA_NOT_CONFIGURED: "HON_CFG_303_HONERTIA_NOT_CONFIGURED";
|
|
41
|
+
readonly CFG_304_BINDINGS_NOT_CONFIGURED: "HON_CFG_304_BINDINGS_NOT_CONFIGURED";
|
|
42
|
+
readonly CFG_305_INVALID_CONFIG: "HON_CFG_305_INVALID_CONFIG";
|
|
43
|
+
readonly HTTP_400_BAD_REQUEST: "HON_HTTP_400_BAD_REQUEST";
|
|
44
|
+
readonly HTTP_429_RATE_LIMITED: "HON_HTTP_429_RATE_LIMITED";
|
|
45
|
+
readonly HTTP_500_INTERNAL_ERROR: "HON_HTTP_500_INTERNAL_ERROR";
|
|
46
|
+
readonly HTTP_502_BAD_GATEWAY: "HON_HTTP_502_BAD_GATEWAY";
|
|
47
|
+
readonly HTTP_503_SERVICE_UNAVAILABLE: "HON_HTTP_503_SERVICE_UNAVAILABLE";
|
|
48
|
+
readonly DB_500_CONNECTION_FAILED: "HON_DB_500_CONNECTION_FAILED";
|
|
49
|
+
readonly DB_501_QUERY_FAILED: "HON_DB_501_QUERY_FAILED";
|
|
50
|
+
readonly DB_502_CONSTRAINT_VIOLATION: "HON_DB_502_CONSTRAINT_VIOLATION";
|
|
51
|
+
readonly DB_503_TRANSACTION_FAILED: "HON_DB_503_TRANSACTION_FAILED";
|
|
52
|
+
readonly RTE_600_BINDING_NOT_FOUND: "HON_RTE_600_BINDING_NOT_FOUND";
|
|
53
|
+
readonly RTE_601_TABLE_NOT_FOUND: "HON_RTE_601_TABLE_NOT_FOUND";
|
|
54
|
+
readonly RTE_602_PARAM_VALIDATION: "HON_RTE_602_PARAM_VALIDATION";
|
|
55
|
+
readonly RTE_603_RELATION_NOT_FOUND: "HON_RTE_603_RELATION_NOT_FOUND";
|
|
56
|
+
readonly SVC_700_SERVICE_UNAVAILABLE: "HON_SVC_700_SERVICE_UNAVAILABLE";
|
|
57
|
+
readonly SVC_701_SERVICE_ERROR: "HON_SVC_701_SERVICE_ERROR";
|
|
58
|
+
readonly INT_800_UNEXPECTED: "HON_INT_800_UNEXPECTED";
|
|
59
|
+
readonly INT_801_EFFECT_DEFECT: "HON_INT_801_EFFECT_DEFECT";
|
|
60
|
+
};
|
|
61
|
+
export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|
|
62
|
+
/**
|
|
63
|
+
* The error catalog with all error definitions.
|
|
64
|
+
*/
|
|
65
|
+
export declare const ErrorCatalog: Record<ErrorCode, ErrorDefinition>;
|
|
66
|
+
/**
|
|
67
|
+
* Create a structured error from an error code and parameters.
|
|
68
|
+
*
|
|
69
|
+
* @param code - The error code (from ErrorCodes) or any string. Unknown codes fallback to INT_800_UNEXPECTED.
|
|
70
|
+
* @param params - Parameters to interpolate into the message template.
|
|
71
|
+
* @param context - The error context (route, request, handler info).
|
|
72
|
+
* @returns A fully structured error with fix suggestions.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const error = createStructuredError(
|
|
77
|
+
* ErrorCodes.VAL_001_FIELD_REQUIRED,
|
|
78
|
+
* { field: 'email' },
|
|
79
|
+
* captureErrorContext(c)
|
|
80
|
+
* )
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function createStructuredError(code: ErrorCode | string, params: Record<string, unknown>, context: ErrorContext): HonertiaStructuredError;
|
|
84
|
+
/**
|
|
85
|
+
* Get an error definition by code.
|
|
86
|
+
*/
|
|
87
|
+
export declare function getErrorDefinition(code: ErrorCode): ErrorDefinition | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Get all error codes for a category.
|
|
90
|
+
*/
|
|
91
|
+
export declare function getErrorsByCategory(category: ErrorCategory): ErrorCode[];
|
|
92
|
+
/**
|
|
93
|
+
* Determine the appropriate configuration error code from a service name or message.
|
|
94
|
+
*
|
|
95
|
+
* @param serviceName - The service name (e.g., 'DatabaseService').
|
|
96
|
+
* @param message - Optional message to check if service name doesn't match.
|
|
97
|
+
* @returns The appropriate error code, defaulting to CFG_305_INVALID_CONFIG.
|
|
98
|
+
*/
|
|
99
|
+
export declare function getConfigErrorCode(serviceName?: string, message?: string): ErrorCode;
|
|
100
|
+
//# sourceMappingURL=error-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-catalog.d.ts","sourceRoot":"","sources":["../../src/effect/error-catalog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,eAAe,EAGf,uBAAuB,EACxB,MAAM,kBAAkB,CAAA;AAEzB;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDb,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAA;AA8JpE;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,eAAe,CAmb3D,CAAA;AAOD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,SAAS,GAAG,MAAM,EACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,YAAY,GACpB,uBAAuB,CAwCzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,GAAG,SAAS,CAE/E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,EAAE,CAIxE;AAWD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,GACf,SAAS,CAUX"}
|