honertia 0.1.42 → 0.1.44
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 +157 -0
- package/dist/effect/bridge.d.ts +13 -0
- package/dist/effect/bridge.d.ts.map +1 -1
- package/dist/effect/bridge.js +21 -0
- package/dist/effect/error-observer.d.ts +22 -0
- package/dist/effect/error-observer.d.ts.map +1 -0
- package/dist/effect/error-observer.js +20 -0
- package/dist/effect/handler.d.ts +2 -2
- package/dist/effect/handler.d.ts.map +1 -1
- package/dist/effect/handler.js +48 -8
- package/dist/effect/index.d.ts +1 -0
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +2 -0
- package/dist/effect/routing.d.ts +4 -1
- package/dist/effect/routing.d.ts.map +1 -1
- package/dist/effect/routing.js +20 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1605,6 +1605,34 @@ effectRoutes(app)
|
|
|
1605
1605
|
- `.middleware()` adds Hono middleware that runs *before* the Effect handler (can redirect/short-circuit)
|
|
1606
1606
|
- `.provide()` adds Effect layers that run *within* the Effect computation (dependency injection)
|
|
1607
1607
|
|
|
1608
|
+
### `provide()` Layer Patterns
|
|
1609
|
+
|
|
1610
|
+
`provide()` supports two layer styles:
|
|
1611
|
+
|
|
1612
|
+
1. **Self-contained layer** (`R = never`)
|
|
1613
|
+
```typescript
|
|
1614
|
+
effectRoutes(app).provide(Layer.succeed(RequestIdService, { id: 'req-123' }))
|
|
1615
|
+
```
|
|
1616
|
+
2. **Context-aware layer** (consumes route context services like `DatabaseService`, `HonertiaService`, or previously provided services)
|
|
1617
|
+
```typescript
|
|
1618
|
+
const SharePropsLayer = Layer.effectDiscard(
|
|
1619
|
+
Effect.gen(function* () {
|
|
1620
|
+
const db = yield* DatabaseService
|
|
1621
|
+
const honertia = yield* HonertiaService
|
|
1622
|
+
const organizations = yield* Effect.tryPromise(() =>
|
|
1623
|
+
db.query.organizations.findMany()
|
|
1624
|
+
)
|
|
1625
|
+
honertia.share('organizations', organizations)
|
|
1626
|
+
honertia.share('authUserAvatarSeed', 'seed-123')
|
|
1627
|
+
})
|
|
1628
|
+
)
|
|
1629
|
+
|
|
1630
|
+
effectRoutes(app)
|
|
1631
|
+
.provide(RequireAuthLayer)
|
|
1632
|
+
.provide(SharePropsLayer)
|
|
1633
|
+
.get('/dashboard', showDashboard)
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1608
1636
|
| Level | Method | Scope |
|
|
1609
1637
|
|-------|--------|-------|
|
|
1610
1638
|
| `app.use('*', ...)` | Global | All routes |
|
|
@@ -1677,6 +1705,135 @@ registerErrorHandlers(app, {
|
|
|
1677
1705
|
})
|
|
1678
1706
|
```
|
|
1679
1707
|
|
|
1708
|
+
### External Error Reporting
|
|
1709
|
+
|
|
1710
|
+
Honertia can report request-time Effect failures to one optional observer service. You define that observer once in `setupHonertia({ effect: { services } })`, and the same observer receives:
|
|
1711
|
+
|
|
1712
|
+
- framework-reported unhandled request failures and defects
|
|
1713
|
+
- user-reported handled/recovered failures via `reportEffectError(...)`
|
|
1714
|
+
|
|
1715
|
+
This is the main integration point for PostHog, Sentry, or any other external reporting system. The observer is best-effort: if it is not installed, nothing happens; if it fails, request behavior does not change.
|
|
1716
|
+
|
|
1717
|
+
```typescript
|
|
1718
|
+
import { Effect, Layer } from 'effect'
|
|
1719
|
+
import { setupHonertia } from 'honertia'
|
|
1720
|
+
import {
|
|
1721
|
+
EffectErrorObserverService,
|
|
1722
|
+
type EffectErrorEvent,
|
|
1723
|
+
} from 'honertia/effect'
|
|
1724
|
+
|
|
1725
|
+
function makeErrorObserver(apiKey?: string) {
|
|
1726
|
+
return Layer.succeed(EffectErrorObserverService, {
|
|
1727
|
+
observe: (event: EffectErrorEvent) => {
|
|
1728
|
+
if (!apiKey) return Effect.void
|
|
1729
|
+
|
|
1730
|
+
return Effect.tryPromise({
|
|
1731
|
+
try: () =>
|
|
1732
|
+
fetch('https://eu.i.posthog.com/capture/', {
|
|
1733
|
+
method: 'POST',
|
|
1734
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1735
|
+
body: JSON.stringify({
|
|
1736
|
+
api_key: apiKey,
|
|
1737
|
+
event:
|
|
1738
|
+
event.source === 'framework'
|
|
1739
|
+
? 'honertia_unhandled_error'
|
|
1740
|
+
: 'honertia_handled_error',
|
|
1741
|
+
properties: {
|
|
1742
|
+
handling: event.handling,
|
|
1743
|
+
kind: event.kind,
|
|
1744
|
+
message:
|
|
1745
|
+
event.error instanceof Error
|
|
1746
|
+
? event.error.message
|
|
1747
|
+
: String(event.error),
|
|
1748
|
+
honertiaCode: event.structured?.code ?? null,
|
|
1749
|
+
httpStatus: event.structured?.httpStatus ?? null,
|
|
1750
|
+
metadata: event.metadata ?? null,
|
|
1751
|
+
},
|
|
1752
|
+
}),
|
|
1753
|
+
}),
|
|
1754
|
+
catch: () => undefined,
|
|
1755
|
+
}).pipe(Effect.asVoid, Effect.catchAll(() => Effect.void))
|
|
1756
|
+
},
|
|
1757
|
+
})
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
app.use('*', setupHonertia<Env>({
|
|
1761
|
+
honertia: {
|
|
1762
|
+
version,
|
|
1763
|
+
render,
|
|
1764
|
+
database: (c) => createDb(c.env.DB),
|
|
1765
|
+
auth: (c) => createAuth({
|
|
1766
|
+
db: c.var.db,
|
|
1767
|
+
secret: c.env.BETTER_AUTH_SECRET,
|
|
1768
|
+
baseURL: new URL(c.req.url).origin,
|
|
1769
|
+
}),
|
|
1770
|
+
schema,
|
|
1771
|
+
},
|
|
1772
|
+
effect: {
|
|
1773
|
+
services: (c) => makeErrorObserver(c.env.POSTHOG_API_KEY),
|
|
1774
|
+
},
|
|
1775
|
+
}))
|
|
1776
|
+
```
|
|
1777
|
+
|
|
1778
|
+
Replace the `fetch(...)` block with `Sentry.captureException(...)` or any other telemetry client if you prefer. The important part is that the reporting sink is configured once, at app setup, instead of inside every action.
|
|
1779
|
+
|
|
1780
|
+
The observer receives events with this shape:
|
|
1781
|
+
|
|
1782
|
+
```typescript
|
|
1783
|
+
type EffectErrorEvent = {
|
|
1784
|
+
source: 'framework' | 'user'
|
|
1785
|
+
handling: 'unhandled' | 'handled'
|
|
1786
|
+
kind: 'failure' | 'defect'
|
|
1787
|
+
error: unknown
|
|
1788
|
+
structured?: HonertiaStructuredError
|
|
1789
|
+
metadata?: Record<string, unknown>
|
|
1790
|
+
}
|
|
1791
|
+
```
|
|
1792
|
+
|
|
1793
|
+
Framework-emitted events use `source: 'framework'` and `handling: 'unhandled'`. User-emitted events use `source: 'user'` and `handling: 'handled'`.
|
|
1794
|
+
|
|
1795
|
+
### Reporting Recovered Errors from Userland
|
|
1796
|
+
|
|
1797
|
+
Unhandled request failures are reported automatically by Honertia. Use `reportEffectError(...)` only when you intentionally recover from an error and still want it forwarded to the same observer.
|
|
1798
|
+
|
|
1799
|
+
```typescript
|
|
1800
|
+
import { Effect } from 'effect'
|
|
1801
|
+
import { action, render, reportEffectError } from 'honertia/effect'
|
|
1802
|
+
|
|
1803
|
+
export const showHome = action(
|
|
1804
|
+
Effect.gen(function* () {
|
|
1805
|
+
const hasPendingNotifications = yield* Effect.tryPromise({
|
|
1806
|
+
try: () => hasPendingNotificationsForUser(),
|
|
1807
|
+
catch: (error) => error,
|
|
1808
|
+
}).pipe(
|
|
1809
|
+
Effect.tapError((error) =>
|
|
1810
|
+
reportEffectError(error, {
|
|
1811
|
+
// the metadata object can be anything you want to forward onto your
|
|
1812
|
+
// reporting service - use it to add any extra context that would be helpful
|
|
1813
|
+
metadata: {
|
|
1814
|
+
area: 'home',
|
|
1815
|
+
operation: 'hasPendingNotificationsForUser',
|
|
1816
|
+
fallbackStrategy: 'assume_no_pending_notifications',
|
|
1817
|
+
userImpact: 'notifications_badge_hidden',
|
|
1818
|
+
},
|
|
1819
|
+
})
|
|
1820
|
+
),
|
|
1821
|
+
Effect.catchAll(() => Effect.succeed(false))
|
|
1822
|
+
)
|
|
1823
|
+
|
|
1824
|
+
return yield* render('Home', { hasPendingNotifications })
|
|
1825
|
+
})
|
|
1826
|
+
)
|
|
1827
|
+
```
|
|
1828
|
+
|
|
1829
|
+
For the common case, the minimal form is enough:
|
|
1830
|
+
|
|
1831
|
+
```typescript
|
|
1832
|
+
Effect.tapError((error) => reportEffectError(error))
|
|
1833
|
+
```
|
|
1834
|
+
|
|
1835
|
+
`reportEffectError(error)` always expands to a handled user failure event. `metadata` is optional and only needed when extra context helps with debugging or analytics.
|
|
1836
|
+
|
|
1680
1837
|
### Error Page Component
|
|
1681
1838
|
|
|
1682
1839
|
```tsx
|
package/dist/effect/bridge.d.ts
CHANGED
|
@@ -49,6 +49,10 @@ export interface EffectBridgeConfig<E extends Env, CustomServices = never> {
|
|
|
49
49
|
* Symbol for storing Effect runtime in Hono context.
|
|
50
50
|
*/
|
|
51
51
|
declare const EFFECT_RUNTIME: unique symbol;
|
|
52
|
+
/**
|
|
53
|
+
* Symbol for storing Effect bridge config in Hono context.
|
|
54
|
+
*/
|
|
55
|
+
declare const EFFECT_BRIDGE_CONFIG: unique symbol;
|
|
52
56
|
/**
|
|
53
57
|
* Symbol for storing schema in Hono context.
|
|
54
58
|
*/
|
|
@@ -60,6 +64,7 @@ export declare function isUnconfiguredService(value: unknown): boolean;
|
|
|
60
64
|
declare module 'hono' {
|
|
61
65
|
interface ContextVariableMap {
|
|
62
66
|
[EFFECT_RUNTIME]?: ManagedRuntime.ManagedRuntime<DatabaseService | AuthService | AuthUserService | HonertiaService | RequestService | ResponseFactoryService, never>;
|
|
67
|
+
[EFFECT_BRIDGE_CONFIG]?: EffectBridgeConfig<any, any>;
|
|
63
68
|
[EFFECT_SCHEMA]?: Record<string, unknown>;
|
|
64
69
|
}
|
|
65
70
|
}
|
|
@@ -71,6 +76,14 @@ export declare function buildContextLayer<E extends Env, CustomServices = never>
|
|
|
71
76
|
* Get the Effect runtime from Hono context.
|
|
72
77
|
*/
|
|
73
78
|
export declare function getEffectRuntime<E extends Env>(c: HonoContext<E>): ManagedRuntime.ManagedRuntime<any, never> | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Store the Effect bridge config on Hono context for downstream handlers.
|
|
81
|
+
*/
|
|
82
|
+
export declare function setEffectBridgeConfig<E extends Env, CustomServices = never>(c: HonoContext<E>, config?: EffectBridgeConfig<E, CustomServices>): void;
|
|
83
|
+
/**
|
|
84
|
+
* Get the Effect bridge config from Hono context.
|
|
85
|
+
*/
|
|
86
|
+
export declare function getEffectBridgeConfig<E extends Env>(c: HonoContext<E>): EffectBridgeConfig<any, any> | undefined;
|
|
74
87
|
/**
|
|
75
88
|
* Middleware that sets up the Effect runtime for each request.
|
|
76
89
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAU,KAAK,EAAE,cAAc,EAAU,MAAM,QAAQ,CAAA;AAG9D,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,EACf,YAAY,EAEZ,uBAAuB,EAUxB,MAAM,eAAe,CAAA;AAGtB;;;;;;;;;;;;;;;;;;;;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;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;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;AAa5C,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM7D;AAqCD;;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;AA8JD;;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,YAAY,GACZ,uBAAuB,GACvB,cAAc,EAChB,KAAK,EACL,KAAK,CACN,CAuGA;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,
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/effect/bridge.js
CHANGED
|
@@ -12,6 +12,10 @@ import { TestCaptureService } from './test-layers.js';
|
|
|
12
12
|
* Symbol for storing Effect runtime in Hono context.
|
|
13
13
|
*/
|
|
14
14
|
const EFFECT_RUNTIME = Symbol('effectRuntime');
|
|
15
|
+
/**
|
|
16
|
+
* Symbol for storing Effect bridge config in Hono context.
|
|
17
|
+
*/
|
|
18
|
+
const EFFECT_BRIDGE_CONFIG = Symbol('effectBridgeConfig');
|
|
15
19
|
/**
|
|
16
20
|
* Symbol for storing schema in Hono context.
|
|
17
21
|
*/
|
|
@@ -222,6 +226,22 @@ export function buildContextLayer(c, config) {
|
|
|
222
226
|
export function getEffectRuntime(c) {
|
|
223
227
|
return c.var?.[EFFECT_RUNTIME];
|
|
224
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* Store the Effect bridge config on Hono context for downstream handlers.
|
|
231
|
+
*/
|
|
232
|
+
export function setEffectBridgeConfig(c, config) {
|
|
233
|
+
if (!config)
|
|
234
|
+
return;
|
|
235
|
+
// Hono's context typing does not preserve symbol-keyed variables through c.set/c.var.
|
|
236
|
+
c.set(EFFECT_BRIDGE_CONFIG, config);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Get the Effect bridge config from Hono context.
|
|
240
|
+
*/
|
|
241
|
+
export function getEffectBridgeConfig(c) {
|
|
242
|
+
// Read through `any` for the same symbol-keyed context limitation as setEffectBridgeConfig.
|
|
243
|
+
return c.var?.[EFFECT_BRIDGE_CONFIG];
|
|
244
|
+
}
|
|
225
245
|
/**
|
|
226
246
|
* Middleware that sets up the Effect runtime for each request.
|
|
227
247
|
*/
|
|
@@ -229,6 +249,7 @@ export function effectBridge(config) {
|
|
|
229
249
|
return async (c, next) => {
|
|
230
250
|
const testLayer = c.var?.__testLayer ?? c.env?.__testLayer;
|
|
231
251
|
const hasTestLayer = Layer.isLayer(testLayer);
|
|
252
|
+
setEffectBridgeConfig(c, config);
|
|
232
253
|
let layer = buildContextLayer(c, config);
|
|
233
254
|
if (hasTestLayer) {
|
|
234
255
|
layer = Layer.merge(layer, testLayer);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context, Effect } from 'effect';
|
|
2
|
+
import type { HonertiaStructuredError } from './error-types.js';
|
|
3
|
+
export interface EffectErrorEvent {
|
|
4
|
+
readonly source: 'framework' | 'user';
|
|
5
|
+
readonly handling: 'unhandled' | 'handled';
|
|
6
|
+
readonly kind: 'failure' | 'defect';
|
|
7
|
+
readonly error: unknown;
|
|
8
|
+
readonly structured?: HonertiaStructuredError;
|
|
9
|
+
readonly metadata?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
declare const EffectErrorObserverService_base: Context.TagClass<EffectErrorObserverService, "honertia/EffectErrorObserver", {
|
|
12
|
+
readonly observe: (event: EffectErrorEvent) => Effect.Effect<void, never>;
|
|
13
|
+
}>;
|
|
14
|
+
export declare class EffectErrorObserverService extends EffectErrorObserverService_base {
|
|
15
|
+
}
|
|
16
|
+
export declare function observeEffectErrorEvent(event: EffectErrorEvent): Effect.Effect<void, never>;
|
|
17
|
+
export declare function reportEffectError(error: unknown): Effect.Effect<void, never>;
|
|
18
|
+
export declare function reportEffectError(error: unknown, options: {
|
|
19
|
+
readonly metadata?: Record<string, unknown>;
|
|
20
|
+
}): Effect.Effect<void, never>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=error-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-observer.d.ts","sourceRoot":"","sources":["../../src/effect/error-observer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAA;AAChD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAA;IACrC,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,uBAAuB,CAAA;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5C;;sBAKmB,CAAC,KAAK,EAAE,gBAAgB,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC;;AAH3E,qBAAa,0BAA2B,SAAQ,+BAI5C;CAAG;AAEP,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,gBAAgB,GACtB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAO5B;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,GACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AAC7B,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IACP,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5C,GACA,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Context, Effect, Option } from 'effect';
|
|
2
|
+
export class EffectErrorObserverService extends Context.Tag('honertia/EffectErrorObserver')() {
|
|
3
|
+
}
|
|
4
|
+
export function observeEffectErrorEvent(event) {
|
|
5
|
+
return Effect.gen(function* () {
|
|
6
|
+
const maybeObserver = yield* Effect.serviceOption(EffectErrorObserverService);
|
|
7
|
+
if (Option.isNone(maybeObserver))
|
|
8
|
+
return;
|
|
9
|
+
yield* maybeObserver.value.observe(event);
|
|
10
|
+
}).pipe(Effect.catchAllCause(() => Effect.void));
|
|
11
|
+
}
|
|
12
|
+
export function reportEffectError(error, options) {
|
|
13
|
+
return observeEffectErrorEvent({
|
|
14
|
+
source: 'user',
|
|
15
|
+
handling: 'handled',
|
|
16
|
+
kind: 'failure',
|
|
17
|
+
error,
|
|
18
|
+
metadata: options?.metadata,
|
|
19
|
+
});
|
|
20
|
+
}
|
package/dist/effect/handler.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Wraps Effect computations into Hono handlers.
|
|
5
5
|
*/
|
|
6
|
-
import { Effect } from 'effect';
|
|
6
|
+
import { Effect, ManagedRuntime } from 'effect';
|
|
7
7
|
import type { Context as HonoContext, MiddlewareHandler, Env } from 'hono';
|
|
8
8
|
import { Redirect, type AppError } from './errors.js';
|
|
9
9
|
import type { HonertiaStructuredError } from './error-types.js';
|
|
@@ -15,7 +15,7 @@ import type { HonertiaStructuredError } from './error-types.js';
|
|
|
15
15
|
* (ValidationError for form re-rendering, UnauthorizedError for redirects)
|
|
16
16
|
* return responses directly.
|
|
17
17
|
*/
|
|
18
|
-
export declare function errorToResponse<E extends Env>(error: AppError, c: HonoContext<E>): Promise<Response>;
|
|
18
|
+
export declare function errorToResponse<E extends Env>(error: AppError, c: HonoContext<E>, runtime?: ManagedRuntime.ManagedRuntime<any, never>): Promise<Response>;
|
|
19
19
|
/**
|
|
20
20
|
* Wrap an Effect into a Hono handler.
|
|
21
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/effect/handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/effect/handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAe,cAAc,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAM1E,OAAO,EAML,QAAQ,EAER,KAAK,QAAQ,EACd,MAAM,aAAa,CAAA;AAQpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAmH/D;;;;;;;GAOG;AACH,wBAAsB,eAAe,CAAC,CAAC,SAAS,GAAG,EACjD,KAAK,EAAE,QAAQ,EACf,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACjB,OAAO,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,GAClD,OAAO,CAAC,QAAQ,CAAC,CAyFnB;AAgBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,GAAG,SAAS,QAAQ,EAClE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,GACjD,iBAAiB,CAAC,CAAC,CAAC,CAoBtB;AAkHD;;GAEG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE,GAAG,SAAS,QAAQ,EAC3D,EAAE,EAAE,MAAM,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,GACnD,iBAAiB,CAAC,CAAC,CAAC,CAEtB;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,sBAAgB,CAAA;AAEnC;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,GAAG,uBAAuB,GAAG,SAAS,CAEzF"}
|
package/dist/effect/handler.js
CHANGED
|
@@ -4,11 +4,12 @@
|
|
|
4
4
|
* Wraps Effect computations into Hono handlers.
|
|
5
5
|
*/
|
|
6
6
|
import { Effect, Exit, Cause, ManagedRuntime } from 'effect';
|
|
7
|
-
import { getEffectRuntime, buildContextLayer } from './bridge.js';
|
|
7
|
+
import { getEffectBridgeConfig, getEffectRuntime, buildContextLayer, } from './bridge.js';
|
|
8
8
|
import { ValidationError, UnauthorizedError, NotFoundError, HttpError, RouteConfigurationError, Redirect, toStructuredError, } from './errors.js';
|
|
9
9
|
import { createStructuredError, ErrorCodes } from './error-catalog.js';
|
|
10
10
|
import { captureErrorContext } from './error-context.js';
|
|
11
11
|
import { detectOutputFormat, JsonErrorFormatter, TerminalErrorFormatter, } from './error-formatter.js';
|
|
12
|
+
import { observeEffectErrorEvent, } from './error-observer.js';
|
|
12
13
|
/**
|
|
13
14
|
* Memoized formatter instances to avoid recreation on every error.
|
|
14
15
|
*/
|
|
@@ -94,6 +95,15 @@ function isDevelopment(c) {
|
|
|
94
95
|
env?.NODE_ENV === 'development' ||
|
|
95
96
|
env?.CF_PAGES_BRANCH !== undefined);
|
|
96
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Observe an Effect error without changing request behavior.
|
|
100
|
+
*/
|
|
101
|
+
async function observeEffectError(c, event, runtime) {
|
|
102
|
+
const activeRuntime = runtime ?? getEffectRuntime(c);
|
|
103
|
+
if (!activeRuntime)
|
|
104
|
+
return;
|
|
105
|
+
await activeRuntime.runPromise(observeEffectErrorEvent(event));
|
|
106
|
+
}
|
|
97
107
|
/**
|
|
98
108
|
* Convert an Effect error to an HTTP response.
|
|
99
109
|
*
|
|
@@ -102,12 +112,19 @@ function isDevelopment(c) {
|
|
|
102
112
|
* (ValidationError for form re-rendering, UnauthorizedError for redirects)
|
|
103
113
|
* return responses directly.
|
|
104
114
|
*/
|
|
105
|
-
export async function errorToResponse(error, c) {
|
|
115
|
+
export async function errorToResponse(error, c, runtime) {
|
|
106
116
|
const context = captureErrorContext(c);
|
|
107
117
|
const isDev = isDevelopment(c);
|
|
108
118
|
const format = detectOutputFormat(createFormatDetectionContext(c), (c.env ?? {}));
|
|
109
119
|
// Convert to structured error
|
|
110
120
|
const structured = toStructuredError(error, context);
|
|
121
|
+
await observeEffectError(c, {
|
|
122
|
+
source: 'framework',
|
|
123
|
+
handling: 'unhandled',
|
|
124
|
+
kind: 'failure',
|
|
125
|
+
error,
|
|
126
|
+
structured,
|
|
127
|
+
}, runtime);
|
|
111
128
|
// Log in development
|
|
112
129
|
logStructuredError(structured, isDev);
|
|
113
130
|
// ValidationError: re-render form with errors or redirect back
|
|
@@ -182,18 +199,18 @@ export function effectHandler(effect) {
|
|
|
182
199
|
const runtime = getEffectRuntime(c);
|
|
183
200
|
if (!runtime) {
|
|
184
201
|
// No runtime set up, create one for this request
|
|
185
|
-
const layer = buildContextLayer(c);
|
|
202
|
+
const layer = buildContextLayer(c, getEffectBridgeConfig(c));
|
|
186
203
|
const tempRuntime = ManagedRuntime.make(layer);
|
|
187
204
|
try {
|
|
188
205
|
const exit = await tempRuntime.runPromiseExit(effect);
|
|
189
|
-
return await handleExit(exit, c);
|
|
206
|
+
return await handleExit(exit, c, tempRuntime);
|
|
190
207
|
}
|
|
191
208
|
finally {
|
|
192
209
|
await tempRuntime.dispose();
|
|
193
210
|
}
|
|
194
211
|
}
|
|
195
212
|
const exit = await runtime.runPromiseExit(effect);
|
|
196
|
-
return await handleExit(exit, c);
|
|
213
|
+
return await handleExit(exit, c, runtime);
|
|
197
214
|
};
|
|
198
215
|
}
|
|
199
216
|
/**
|
|
@@ -202,7 +219,7 @@ export function effectHandler(effect) {
|
|
|
202
219
|
* Failures are converted to responses via errorToResponse.
|
|
203
220
|
* Defects (unexpected errors) are re-thrown for Hono's onError handler.
|
|
204
221
|
*/
|
|
205
|
-
async function handleExit(exit, c) {
|
|
222
|
+
async function handleExit(exit, c, runtime) {
|
|
206
223
|
if (Exit.isSuccess(exit)) {
|
|
207
224
|
const value = exit.value;
|
|
208
225
|
if (isRedirect(value)) {
|
|
@@ -215,7 +232,7 @@ async function handleExit(exit, c) {
|
|
|
215
232
|
if (Cause.isFailure(cause)) {
|
|
216
233
|
const error = Cause.failureOption(cause);
|
|
217
234
|
if (error._tag === 'Some') {
|
|
218
|
-
return await errorToResponse(error.value, c);
|
|
235
|
+
return await errorToResponse(error.value, c, runtime);
|
|
219
236
|
}
|
|
220
237
|
}
|
|
221
238
|
// Handle defects (unexpected errors) - attach structured error for Hono's onError
|
|
@@ -225,9 +242,18 @@ async function handleExit(exit, c) {
|
|
|
225
242
|
if (defect._tag === 'Some') {
|
|
226
243
|
const err = defect.value;
|
|
227
244
|
// If the defect is already a structured error (like HonertiaConfigurationError),
|
|
228
|
-
// convert it using its own toStructured method
|
|
245
|
+
// convert it using its own toStructured method.
|
|
246
|
+
// This branch always throws after observing, so the generic defect path below
|
|
247
|
+
// only runs for defects that do not implement toStructured.
|
|
229
248
|
if (err && typeof err === 'object' && 'toStructured' in err && typeof err.toStructured === 'function') {
|
|
230
249
|
const structured = err.toStructured(context);
|
|
250
|
+
await observeEffectError(c, {
|
|
251
|
+
source: 'framework',
|
|
252
|
+
handling: 'unhandled',
|
|
253
|
+
kind: 'defect',
|
|
254
|
+
error: err,
|
|
255
|
+
structured,
|
|
256
|
+
}, runtime);
|
|
231
257
|
const wrapped = new Error(err.message ?? String(err));
|
|
232
258
|
wrapped.__honertiaStructured = structured;
|
|
233
259
|
wrapped.hint = err.hint;
|
|
@@ -235,6 +261,13 @@ async function handleExit(exit, c) {
|
|
|
235
261
|
}
|
|
236
262
|
// Otherwise create a generic defect error
|
|
237
263
|
const structured = createStructuredError(ErrorCodes.INT_801_EFFECT_DEFECT, { reason: err instanceof Error ? err.message : String(err) }, context);
|
|
264
|
+
await observeEffectError(c, {
|
|
265
|
+
source: 'framework',
|
|
266
|
+
handling: 'unhandled',
|
|
267
|
+
kind: 'defect',
|
|
268
|
+
error: err,
|
|
269
|
+
structured,
|
|
270
|
+
}, runtime);
|
|
238
271
|
if (err instanceof Error) {
|
|
239
272
|
;
|
|
240
273
|
err.__honertiaStructured = structured;
|
|
@@ -247,6 +280,13 @@ async function handleExit(exit, c) {
|
|
|
247
280
|
}
|
|
248
281
|
// Fallback: throw generic error with structured info
|
|
249
282
|
const structured = createStructuredError(ErrorCodes.INT_800_UNEXPECTED, { reason: 'Unknown effect failure' }, context);
|
|
283
|
+
await observeEffectError(c, {
|
|
284
|
+
source: 'framework',
|
|
285
|
+
handling: 'unhandled',
|
|
286
|
+
kind: 'defect',
|
|
287
|
+
error: new Error('Unknown effect failure'),
|
|
288
|
+
structured,
|
|
289
|
+
}, runtime);
|
|
250
290
|
const fallbackError = new Error('Unknown effect failure');
|
|
251
291
|
fallbackError.__honertiaStructured = structured;
|
|
252
292
|
throw fallbackError;
|
package/dist/effect/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export { DatabaseService, AuthService, AuthUserService, EmailService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, ExecutionContextService, authorize, type AuthUser, type EmailClient, type HonertiaRenderer, type RequestContext, type ResponseFactory, type CacheClient, type ExecutionContextClient, type HonertiaDatabaseType, type HonertiaAuthType, type HonertiaBindingsType, type HonertiaAuthUserType, type DefaultAuthUser, type DatabaseType, type SchemaType, type AuthType, type BindingsType, } from './services.js';
|
|
7
7
|
export { ValidationError, UnauthorizedError, NotFoundError, ForbiddenError, HttpError, RouteConfigurationError, HonertiaConfigurationError, Redirect, isStructuredError, toStructuredError, type AppError, type StructuredErrorCapable, } from './errors.js';
|
|
8
8
|
export type { ErrorCategory, ErrorContext, SourceLocation, CodeSnippet, RouteContext, HandlerContext, RequestContext as ErrorRequestContext, ServiceContext, FixType, FixPosition, FixOperation, PostAction, FixSuggestion, ErrorDocs, HonertiaStructuredError, FieldError, ValidationErrorData, ConfigurationErrorData, BindingErrorData, ErrorDefinition, FixGenerator, } from './error-types.js';
|
|
9
|
+
export { EffectErrorObserverService, reportEffectError, type EffectErrorEvent, } from './error-observer.js';
|
|
9
10
|
export { ErrorCodes, ErrorCatalog, createStructuredError, getConfigErrorCode, getErrorDefinition, getErrorsByCategory, type ErrorCode, } from './error-catalog.js';
|
|
10
11
|
export { JsonErrorFormatter, TerminalErrorFormatter, InertiaErrorFormatter, detectOutputFormat, createFormatter, type ErrorFormatter, type JsonFormatterOptions, type TerminalFormatterOptions, type InertiaFormatterOptions, type OutputFormat, type FormatDetectionContext, } from './error-formatter.js';
|
|
11
12
|
export { captureErrorContext, captureEnhancedContext, parseStackTrace, findUserFrame, createSourceLocation, createCodeSnippet, withHandlerContext, withServiceContext, mergeContexts, emptyContext, type StackFrame, type EnhancedErrorContext, } from './error-context.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/effect/index.ts"],"names":[],"mappings":"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"}
|
package/dist/effect/index.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
export { DatabaseService, AuthService, AuthUserService, EmailService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, ExecutionContextService, authorize, } from './services.js';
|
|
8
8
|
// Errors
|
|
9
9
|
export { ValidationError, UnauthorizedError, NotFoundError, ForbiddenError, HttpError, RouteConfigurationError, HonertiaConfigurationError, Redirect, isStructuredError, toStructuredError, } from './errors.js';
|
|
10
|
+
// Error Observer
|
|
11
|
+
export { EffectErrorObserverService, reportEffectError, } from './error-observer.js';
|
|
10
12
|
// Error Catalog
|
|
11
13
|
export { ErrorCodes, ErrorCatalog, createStructuredError, getConfigErrorCode, getErrorDefinition, getErrorsByCategory, } from './error-catalog.js';
|
|
12
14
|
// Error Formatters
|
package/dist/effect/routing.d.ts
CHANGED
|
@@ -90,9 +90,12 @@ export declare class EffectRouteBuilder<E extends Env, ProvidedServices = never,
|
|
|
90
90
|
constructor(app: Hono<E>, layers?: Layer.Layer<any, never, never>[], pathPrefix?: string, bridgeConfig?: EffectBridgeConfig<E, CustomServices> | undefined, registry?: RouteRegistry, middlewares?: MiddlewareHandler<E>[]);
|
|
91
91
|
/**
|
|
92
92
|
* Add a layer to provide services to all routes in this builder.
|
|
93
|
+
* The layer may be self-contained (`R = never`) or consume services already
|
|
94
|
+
* available in this route context (`BaseServices`, previously provided services,
|
|
95
|
+
* and bridge-level custom services).
|
|
93
96
|
* The layer's error type must be handled by the effect bridge (AppError or subtype).
|
|
94
97
|
*/
|
|
95
|
-
provide<S, LayerErr extends AppError>(layer: Layer.Layer<S, LayerErr,
|
|
98
|
+
provide<S, LayerErr extends AppError, LayerReq extends BaseServices | ProvidedServices | CustomServices>(layer: Layer.Layer<S, LayerErr, LayerReq>): EffectRouteBuilder<E, ProvidedServices | S, CustomServices>;
|
|
96
99
|
/**
|
|
97
100
|
* Add Hono middleware that runs before the Effect handler.
|
|
98
101
|
* Use this for middleware that needs to redirect or short-circuit requests
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/effect/routing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/effect/routing.ts"],"names":[],"mappings":"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"}
|
package/dist/effect/routing.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Laravel-style routing with Effect handlers.
|
|
5
5
|
*/
|
|
6
|
-
import { Effect, Exit, Layer, Option, Schema as S } from 'effect';
|
|
6
|
+
import { Cause, Effect, Exit, Layer, Option, Schema as S } from 'effect';
|
|
7
7
|
import { effectHandler, errorToResponse } from './handler.js';
|
|
8
|
-
import { buildContextLayer, getEffectRuntime, getEffectSchema, isUnconfiguredService, } from './bridge.js';
|
|
8
|
+
import { buildContextLayer, getEffectRuntime, getEffectSchema, isUnconfiguredService, setEffectBridgeConfig, } from './bridge.js';
|
|
9
9
|
import { ValidationError, } from './errors.js';
|
|
10
10
|
import { DatabaseService, } from './services.js';
|
|
11
11
|
import { ValidatedBodyService, ValidatedQueryService } from './validated-services.js';
|
|
@@ -35,6 +35,17 @@ async function hydrateRequestDb(c) {
|
|
|
35
35
|
c.set('db', maybeDb.value);
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
async function runValidation(effect) {
|
|
39
|
+
const exit = await Effect.runPromiseExit(effect);
|
|
40
|
+
if (Exit.isSuccess(exit)) {
|
|
41
|
+
return exit.value;
|
|
42
|
+
}
|
|
43
|
+
const error = Cause.failureOption(exit.cause);
|
|
44
|
+
if (Option.isSome(error)) {
|
|
45
|
+
throw error.value;
|
|
46
|
+
}
|
|
47
|
+
throw Cause.squash(exit.cause);
|
|
48
|
+
}
|
|
38
49
|
/**
|
|
39
50
|
* Effect Route Builder with layer composition.
|
|
40
51
|
*/
|
|
@@ -55,6 +66,9 @@ export class EffectRouteBuilder {
|
|
|
55
66
|
}
|
|
56
67
|
/**
|
|
57
68
|
* Add a layer to provide services to all routes in this builder.
|
|
69
|
+
* The layer may be self-contained (`R = never`) or consume services already
|
|
70
|
+
* available in this route context (`BaseServices`, previously provided services,
|
|
71
|
+
* and bridge-level custom services).
|
|
58
72
|
* The layer's error type must be handled by the effect bridge (AppError or subtype).
|
|
59
73
|
*/
|
|
60
74
|
provide(layer) {
|
|
@@ -174,6 +188,7 @@ export class EffectRouteBuilder {
|
|
|
174
188
|
const layers = this.layers;
|
|
175
189
|
const bridgeConfig = this.bridgeConfig;
|
|
176
190
|
return async (c) => {
|
|
191
|
+
setEffectBridgeConfig(c, bridgeConfig);
|
|
177
192
|
// Get schema from bridgeConfig or from context (set by setupHonertia/effectBridge)
|
|
178
193
|
const schema = bridgeConfig?.schema ?? getEffectSchema(c);
|
|
179
194
|
// Use provided params schema, or infer from database schema if available
|
|
@@ -193,12 +208,12 @@ export class EffectRouteBuilder {
|
|
|
193
208
|
try {
|
|
194
209
|
if (shouldValidateBody && !BODYLESS_METHODS.has(c.req.method.toUpperCase())) {
|
|
195
210
|
const body = await parseRequestBody(c);
|
|
196
|
-
validatedBody = await
|
|
211
|
+
validatedBody = await runValidation(validateUnknown(bodySchema, body));
|
|
197
212
|
hasValidatedBody = true;
|
|
198
213
|
}
|
|
199
214
|
if (querySchema) {
|
|
200
215
|
const query = c.req.query();
|
|
201
|
-
validatedQuery = await
|
|
216
|
+
validatedQuery = await runValidation(validateUnknown(querySchema, query));
|
|
202
217
|
hasValidatedQuery = true;
|
|
203
218
|
}
|
|
204
219
|
}
|
|
@@ -243,7 +258,7 @@ export class EffectRouteBuilder {
|
|
|
243
258
|
fullLayer = Layer.merge(fullLayer, Layer.succeed(ValidatedQueryService, validatedQuery));
|
|
244
259
|
}
|
|
245
260
|
for (const layer of layers) {
|
|
246
|
-
fullLayer = Layer.
|
|
261
|
+
fullLayer = Layer.provideMerge(layer, fullLayer);
|
|
247
262
|
}
|
|
248
263
|
// Run the effect with the combined layer
|
|
249
264
|
const program = effect.pipe(Effect.provide(fullLayer));
|