honertia 0.1.37 → 0.1.40

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 CHANGED
@@ -824,7 +824,7 @@ export const listProjects = action(
824
824
  })
825
825
  ),
826
826
  S.Array(ProjectSchema),
827
- Duration.minutes(5)
827
+ { ttl: Duration.minutes(5) }
828
828
  )
829
829
 
830
830
  return yield* render('Projects/Index', { projects: userProjects })
@@ -1676,7 +1676,7 @@ export const listProjects = action(
1676
1676
  catch: (error) => new Error(String(error)),
1677
1677
  }),
1678
1678
  S.Array(ProjectSchema),
1679
- Duration.minutes(5)
1679
+ { ttl: Duration.minutes(5) }
1680
1680
  )
1681
1681
 
1682
1682
  return yield* render('Projects/Index', { projects: userProjects })
@@ -1688,12 +1688,19 @@ export const listProjects = action(
1688
1688
 
1689
1689
  | Function | Description |
1690
1690
  |----------|-------------|
1691
- | `cache(key, compute, schema, ttl)` | Get from cache or compute and store |
1691
+ | `cache(key, compute, schema, options)` | Get from cache or compute and store |
1692
1692
  | `cacheGet(key, schema)` | Get value from cache (returns `Option`) |
1693
- | `cacheSet(key, value, schema, ttl)` | Store value in cache |
1693
+ | `cacheSet(key, value, schema, options)` | Store value in cache |
1694
1694
  | `cacheInvalidate(key)` | Delete a single cache key |
1695
1695
  | `cacheInvalidatePrefix(prefix)` | Delete all keys with prefix |
1696
1696
 
1697
+ The `options` parameter is an object with the following properties:
1698
+
1699
+ | Property | Type | Description |
1700
+ |----------|------|-------------|
1701
+ | `ttl` | `Duration.DurationInput` | Time-to-live for cached values (required) |
1702
+ | `swr` | `Duration.DurationInput` | Stale-while-revalidate window (optional) |
1703
+
1697
1704
  ### Cache Invalidation
1698
1705
 
1699
1706
  Invalidate cache when data changes:
@@ -1783,7 +1790,7 @@ if (Option.isSome(cached)) {
1783
1790
  const user = yield* fetchUser(id)
1784
1791
 
1785
1792
  // Store in cache
1786
- yield* cacheSet(`user:${id}`, user, UserSchema, Duration.hours(1))
1793
+ yield* cacheSet(`user:${id}`, user, UserSchema, { ttl: Duration.hours(1) })
1787
1794
 
1788
1795
  return user
1789
1796
  ```
@@ -1921,8 +1928,8 @@ describe('cache', () => {
1921
1928
  return { id: '1', name: 'Test' }
1922
1929
  })
1923
1930
 
1924
- const first = yield* cache('test:1', compute, TestSchema, Duration.hours(1))
1925
- const second = yield* cache('test:1', compute, TestSchema, Duration.hours(1))
1931
+ const first = yield* cache('test:1', compute, TestSchema, { ttl: Duration.hours(1) })
1932
+ const second = yield* cache('test:1', compute, TestSchema, { ttl: Duration.hours(1) })
1926
1933
 
1927
1934
  expect(first).toEqual(second)
1928
1935
  expect(callCount).toBe(1) // Only computed once
@@ -1937,9 +1944,9 @@ describe('cache', () => {
1937
1944
  return { id: '1', name: `Call ${callCount}` }
1938
1945
  })
1939
1946
 
1940
- yield* cache('test:1', compute, TestSchema, Duration.hours(1))
1947
+ yield* cache('test:1', compute, TestSchema, { ttl: Duration.hours(1) })
1941
1948
  yield* cacheInvalidate('test:1')
1942
- yield* cache('test:1', compute, TestSchema, Duration.hours(1))
1949
+ yield* cache('test:1', compute, TestSchema, { ttl: Duration.hours(1) })
1943
1950
 
1944
1951
  expect(callCount).toBe(2) // Computed twice
1945
1952
  }).pipe(Effect.provide(makeTestCache()), Effect.runPromise))
@@ -1979,6 +1986,410 @@ Recommended cache key patterns:
1979
1986
  `api:exchange:${currency}`
1980
1987
  ```
1981
1988
 
1989
+ ### Stale-While-Revalidate (SWR)
1990
+
1991
+ The cache supports the stale-while-revalidate pattern for improved latency and resilience. When enabled, stale values are returned immediately while a background refresh is triggered.
1992
+
1993
+ ```typescript
1994
+ import { Effect, Duration } from 'effect'
1995
+ import { cache, DatabaseService } from 'honertia/effect'
1996
+
1997
+ const UserSchema = S.Struct({
1998
+ id: S.String,
1999
+ name: S.String,
2000
+ email: S.String,
2001
+ })
2002
+
2003
+ // Basic usage with TTL only
2004
+ const user = yield* cache(
2005
+ `user:${id}`,
2006
+ fetchUser(id),
2007
+ UserSchema,
2008
+ { ttl: Duration.hours(1) }
2009
+ )
2010
+
2011
+ // With stale-while-revalidate
2012
+ const user = yield* cache(
2013
+ `user:${id}`,
2014
+ fetchUser(id),
2015
+ UserSchema,
2016
+ {
2017
+ ttl: Duration.hours(1), // Fresh for 1 hour
2018
+ swr: Duration.minutes(5), // Serve stale for 5 more minutes while refreshing
2019
+ }
2020
+ )
2021
+ ```
2022
+
2023
+ **How SWR works:**
2024
+
2025
+ | Cache State | Behavior |
2026
+ |-------------|----------|
2027
+ | Fresh (age < TTL) | Return cached value immediately |
2028
+ | Stale (TTL < age < TTL + SWR) | Return stale value immediately, trigger background refresh |
2029
+ | Expired (age > TTL + SWR) | Compute new value synchronously |
2030
+ | Cold (no cache) | Compute new value synchronously |
2031
+
2032
+ **Benefits:**
2033
+ - **Faster responses**: Users always get an immediate response (stale or fresh)
2034
+ - **Reduced latency spikes**: No waiting for slow database queries during cache refresh
2035
+ - **Graceful degradation**: If the background refresh fails, stale data is still served
2036
+
2037
+ **Real-world example:**
2038
+
2039
+ ```typescript
2040
+ import { Effect, Duration, Schema as S } from 'effect'
2041
+ import { action, authorize, cache, render, DatabaseService } from 'honertia/effect'
2042
+ import { eq } from 'drizzle-orm'
2043
+ import { projects } from '~/db/schema'
2044
+
2045
+ const ProjectListSchema = S.Array(
2046
+ S.Struct({
2047
+ id: S.String,
2048
+ name: S.String,
2049
+ createdAt: S.Date,
2050
+ })
2051
+ )
2052
+
2053
+ export const indexProjects = action(
2054
+ Effect.gen(function* () {
2055
+ const auth = yield* authorize()
2056
+ const db = yield* DatabaseService
2057
+
2058
+ // Cache project list with SWR
2059
+ // - Fresh for 5 minutes
2060
+ // - Serve stale for 1 additional minute while refreshing in background
2061
+ const userProjects = yield* cache(
2062
+ `projects:user:${auth.user.id}`,
2063
+ Effect.tryPromise(() =>
2064
+ db.query.projects.findMany({
2065
+ where: eq(projects.userId, auth.user.id),
2066
+ orderBy: (p, { desc }) => [desc(p.createdAt)],
2067
+ })
2068
+ ),
2069
+ ProjectListSchema,
2070
+ {
2071
+ ttl: Duration.minutes(5),
2072
+ swr: Duration.minutes(1),
2073
+ }
2074
+ )
2075
+
2076
+ return yield* render('Projects/Index', { projects: userProjects })
2077
+ })
2078
+ )
2079
+ ```
2080
+
2081
+ ### Background Tasks with ExecutionContextService
2082
+
2083
+ The `ExecutionContextService` provides access to Cloudflare Workers' `waitUntil` API, allowing you to run tasks after the response is sent. This is automatically used by the cache's SWR feature for background refresh.
2084
+
2085
+ ```typescript
2086
+ import { Effect } from 'effect'
2087
+ import { action, ExecutionContextService, authorize, render } from 'honertia/effect'
2088
+
2089
+ export const dashboard = action(
2090
+ Effect.gen(function* () {
2091
+ const auth = yield* authorize()
2092
+ const ctx = yield* ExecutionContextService
2093
+
2094
+ // Send analytics in background - doesn't block response
2095
+ yield* ctx.runInBackground(
2096
+ Effect.tryPromise(() =>
2097
+ fetch('https://analytics.example.com/events', {
2098
+ method: 'POST',
2099
+ body: JSON.stringify({
2100
+ event: 'page_view',
2101
+ userId: auth.user.id,
2102
+ page: 'dashboard',
2103
+ timestamp: Date.now(),
2104
+ }),
2105
+ })
2106
+ )
2107
+ )
2108
+
2109
+ return yield* render('Dashboard', { user: auth.user })
2110
+ })
2111
+ )
2112
+ ```
2113
+
2114
+ **ExecutionContextService API:**
2115
+
2116
+ | Method | Description |
2117
+ |--------|-------------|
2118
+ | `isAvailable` | `boolean` - Whether background execution is available |
2119
+ | `runInBackground(effect)` | Run an Effect after the response is sent |
2120
+ | `waitUntil(promise)` | Raw `waitUntil` for external promises |
2121
+
2122
+ **Common use cases:**
2123
+
2124
+ ```typescript
2125
+ // Audit logging
2126
+ const auditLog = (action: string, details: Record<string, unknown>) =>
2127
+ Effect.gen(function* () {
2128
+ const ctx = yield* ExecutionContextService
2129
+ const user = yield* authorize()
2130
+ const db = yield* DatabaseService
2131
+
2132
+ yield* ctx.runInBackground(
2133
+ Effect.tryPromise(() =>
2134
+ db.insert(auditLogs).values({
2135
+ userId: user.id,
2136
+ action,
2137
+ details,
2138
+ timestamp: new Date(),
2139
+ })
2140
+ )
2141
+ )
2142
+ })
2143
+
2144
+ // Webhook delivery with retries
2145
+ const deliverWebhook = (url: string, payload: unknown) =>
2146
+ Effect.gen(function* () {
2147
+ const ctx = yield* ExecutionContextService
2148
+
2149
+ yield* ctx.runInBackground(
2150
+ Effect.tryPromise(() =>
2151
+ fetch(url, {
2152
+ method: 'POST',
2153
+ headers: { 'Content-Type': 'application/json' },
2154
+ body: JSON.stringify(payload),
2155
+ })
2156
+ ).pipe(
2157
+ Effect.retry({ times: 3 }),
2158
+ Effect.catchAll((error) =>
2159
+ Effect.logError('Webhook delivery failed', { url, error })
2160
+ )
2161
+ )
2162
+ )
2163
+ })
2164
+
2165
+ // Conditional background work
2166
+ const maybeNotifySlack = (message: string) =>
2167
+ Effect.gen(function* () {
2168
+ const ctx = yield* ExecutionContextService
2169
+ const bindings = yield* BindingsService
2170
+
2171
+ // Only run if Slack is configured and background is available
2172
+ if (bindings.SLACK_WEBHOOK_URL && ctx.isAvailable) {
2173
+ yield* ctx.runInBackground(
2174
+ Effect.tryPromise(() =>
2175
+ fetch(bindings.SLACK_WEBHOOK_URL, {
2176
+ method: 'POST',
2177
+ body: JSON.stringify({ text: message }),
2178
+ })
2179
+ )
2180
+ )
2181
+ }
2182
+ })
2183
+ ```
2184
+
2185
+ **Important notes:**
2186
+ - Background tasks run after the response is sent to the user
2187
+ - Errors in background tasks are logged but don't crash the worker
2188
+ - In non-Worker environments (tests, local dev), `isAvailable` is `false` and tasks are skipped
2189
+ - Use `catchAll` to handle errors gracefully in background tasks
2190
+
2191
+ ### Cache Key Versioning
2192
+
2193
+ Cache versioning ensures cache correctness when your data schema changes. Without versioning, schema changes can cause decode errors or serve stale data with the wrong shape.
2194
+
2195
+ **The Problem:**
2196
+
2197
+ ```typescript
2198
+ // Version 1 of your schema
2199
+ const UserSchemaV1 = S.Struct({
2200
+ id: S.String,
2201
+ name: S.String,
2202
+ email: S.String,
2203
+ })
2204
+
2205
+ // You deploy with cached data...
2206
+
2207
+ // Version 2 adds a required field
2208
+ const UserSchemaV2 = S.Struct({
2209
+ id: S.String,
2210
+ name: S.String,
2211
+ email: S.String,
2212
+ avatar: S.String, // New required field!
2213
+ })
2214
+
2215
+ // Cached V1 data fails to decode with V2 schema → Runtime error
2216
+ ```
2217
+
2218
+ **Solution 1: Auto Schema Versioning (Recommended)**
2219
+
2220
+ Pass `version: true` to automatically version cache keys based on a hash of the schema structure. When you change the schema, the hash changes, and old cached data is automatically bypassed.
2221
+
2222
+ ```typescript
2223
+ import { Effect, Duration, Schema as S } from 'effect'
2224
+ import { cache, DatabaseService } from 'honertia/effect'
2225
+
2226
+ const UserSchema = S.Struct({
2227
+ id: S.String,
2228
+ name: S.String,
2229
+ email: S.String,
2230
+ })
2231
+
2232
+ // Cache key becomes "a1b2c3:user:123" (hash:key)
2233
+ const user = yield* cache(
2234
+ `user:${id}`,
2235
+ fetchUser(id),
2236
+ UserSchema,
2237
+ { ttl: Duration.hours(1), version: true }
2238
+ )
2239
+ ```
2240
+
2241
+ **When to use `version: true`:**
2242
+ - You want automatic cache invalidation when schemas evolve
2243
+ - You're iterating quickly on data structures during development
2244
+ - You want zero-downtime deployments without manual cache clearing
2245
+
2246
+ **When NOT to use `version: true`:**
2247
+ - You need cache hits to survive deployments (use explicit versions instead)
2248
+ - Schema changes are intentionally backward-compatible
2249
+ - You're caching data that doesn't depend on schema structure
2250
+
2251
+ **Solution 2: Explicit Version Strings**
2252
+
2253
+ For more control, pass an explicit version string. Bump it manually when your schema changes.
2254
+
2255
+ ```typescript
2256
+ // Cache key becomes "v2:user:123"
2257
+ const user = yield* cache(
2258
+ `user:${id}`,
2259
+ fetchUser(id),
2260
+ UserSchema,
2261
+ { ttl: Duration.hours(1), version: 'v2' }
2262
+ )
2263
+ ```
2264
+
2265
+ **When to use explicit versions:**
2266
+ - You want cache hits to survive deployments
2267
+ - You need predictable cache keys for debugging
2268
+ - You're coordinating schema changes across services
2269
+
2270
+ **Full Example: User Profile with Versioned Cache**
2271
+
2272
+ ```typescript
2273
+ import { Effect, Duration, Schema as S } from 'effect'
2274
+ import {
2275
+ action,
2276
+ authorize,
2277
+ cache,
2278
+ cacheInvalidate,
2279
+ render,
2280
+ redirect,
2281
+ DatabaseService,
2282
+ validateRequest,
2283
+ dbMutation,
2284
+ } from 'honertia/effect'
2285
+ import { eq } from 'drizzle-orm'
2286
+ import { users } from '~/db/schema'
2287
+
2288
+ // Schema definition - changing this auto-invalidates cache when version: true
2289
+ const UserProfileSchema = S.Struct({
2290
+ id: S.String,
2291
+ name: S.String,
2292
+ email: S.String,
2293
+ bio: S.NullOr(S.String),
2294
+ avatarUrl: S.NullOr(S.String),
2295
+ })
2296
+
2297
+ // GET /profile - cached with auto-versioning
2298
+ export const showProfile = action(
2299
+ Effect.gen(function* () {
2300
+ const auth = yield* authorize()
2301
+ const db = yield* DatabaseService
2302
+
2303
+ const profile = yield* cache(
2304
+ `user:profile:${auth.user.id}`,
2305
+ Effect.tryPromise(() =>
2306
+ db.query.users.findFirst({
2307
+ where: eq(users.id, auth.user.id),
2308
+ columns: { id: true, name: true, email: true, bio: true, avatarUrl: true },
2309
+ })
2310
+ ),
2311
+ UserProfileSchema,
2312
+ {
2313
+ ttl: Duration.hours(1),
2314
+ swr: Duration.minutes(5),
2315
+ version: true, // Auto-invalidates when UserProfileSchema changes
2316
+ }
2317
+ )
2318
+
2319
+ return yield* render('Profile/Show', { profile })
2320
+ })
2321
+ )
2322
+
2323
+ // PUT /profile - invalidate cache after update
2324
+ export const updateProfile = action(
2325
+ Effect.gen(function* () {
2326
+ const auth = yield* authorize()
2327
+ const input = yield* validateRequest(UpdateProfileSchema, {
2328
+ errorComponent: 'Profile/Edit',
2329
+ })
2330
+ const db = yield* DatabaseService
2331
+
2332
+ yield* dbMutation(db, async (db) => {
2333
+ await db.update(users)
2334
+ .set({ name: input.name, bio: input.bio })
2335
+ .where(eq(users.id, auth.user.id))
2336
+ })
2337
+
2338
+ // Invalidate with same versioning strategy
2339
+ yield* cacheInvalidate(`user:profile:${auth.user.id}`, {
2340
+ schema: UserProfileSchema,
2341
+ version: true,
2342
+ })
2343
+
2344
+ return yield* redirect('/profile')
2345
+ })
2346
+ )
2347
+ ```
2348
+
2349
+ **Versioning with `cacheGet` and `cacheInvalidate`:**
2350
+
2351
+ When using manual cache operations, pass the same version option:
2352
+
2353
+ ```typescript
2354
+ import { cacheGet, cacheSet, cacheInvalidate } from 'honertia/effect'
2355
+
2356
+ // Get with auto-versioning
2357
+ const cached = yield* cacheGet(`user:${id}`, UserSchema, { version: true })
2358
+
2359
+ // Set with explicit version
2360
+ yield* cacheSet(`user:${id}`, user, UserSchema, {
2361
+ ttl: Duration.hours(1),
2362
+ version: 'v2',
2363
+ })
2364
+
2365
+ // Invalidate with versioning - requires schema when using version
2366
+ yield* cacheInvalidate(`user:${id}`, { schema: UserSchema, version: true })
2367
+
2368
+ // Simple invalidation (no versioning)
2369
+ yield* cacheInvalidate(`user:${id}`)
2370
+ ```
2371
+
2372
+ **How Schema Hashing Works:**
2373
+
2374
+ The auto-versioning feature uses the djb2 hash algorithm on the serialized schema AST:
2375
+
2376
+ 1. Schema structure is serialized to a string representation
2377
+ 2. A fast, deterministic hash is computed (djb2)
2378
+ 3. The hash is prepended to the cache key
2379
+
2380
+ This means:
2381
+ - Same schema definition → same hash → cache hits work
2382
+ - Changed schema structure → different hash → cache miss, fresh data computed
2383
+ - Adding/removing fields, changing types, or modifying constraints all change the hash
2384
+
2385
+ **Cache Options Reference:**
2386
+
2387
+ | Option | Type | Description |
2388
+ |--------|------|-------------|
2389
+ | `ttl` | `Duration.DurationInput` | Time-to-live for cached values (required) |
2390
+ | `swr` | `Duration.DurationInput` | Stale-while-revalidate window (optional) |
2391
+ | `version` | `string \| boolean` | `true` = auto schema hash, `string` = explicit prefix (optional) |
2392
+
1982
2393
  ---
1983
2394
 
1984
2395
  ## Services Reference
@@ -1990,6 +2401,7 @@ Recommended cache key patterns:
1990
2401
  | `AuthUserService` | Current user session | `const user = yield* AuthUserService` |
1991
2402
  | `BindingsService` | Cloudflare bindings | `const { KV } = yield* BindingsService` |
1992
2403
  | `CacheService` | KV-backed cache client | `const cache = yield* CacheService` |
2404
+ | `ExecutionContextService` | Background task execution | `const ctx = yield* ExecutionContextService` |
1993
2405
  | `RequestService` | Request context | `const req = yield* RequestService` |
1994
2406
 
1995
2407
  ### Using BindingsService
package/dist/cache.d.ts CHANGED
@@ -4,9 +4,36 @@
4
4
  * Simple cache abstraction for storing expensive DB operations.
5
5
  * Uses CacheService which is automatically provided and backed by Cloudflare KV by default.
6
6
  * Can be swapped for Redis, Memcached, or any other implementation.
7
+ *
8
+ * Supports stale-while-revalidate (SWR) pattern for improved latency and resilience.
7
9
  */
8
10
  import { Effect, Option, Schema, ParseResult, Duration } from 'effect';
9
- import { CacheService, CacheClientError } from './effect/services.js';
11
+ import { CacheService, CacheClientError, ExecutionContextService } from './effect/services.js';
12
+ export type CacheOptions = {
13
+ /** Time-to-live for cached values */
14
+ ttl: Duration.DurationInput;
15
+ /**
16
+ * Stale-while-revalidate window. When set, stale values within this window
17
+ * are returned immediately while a background refresh is triggered.
18
+ * Without ExecutionContext, the refresh happens on the next request.
19
+ */
20
+ swr?: Duration.DurationInput;
21
+ /**
22
+ * Cache key versioning for safe schema migrations.
23
+ * - `string`: Explicit version prefix (e.g., 'v2')
24
+ * - `true`: Auto-generate version from schema hash
25
+ * - `false` or omitted: No versioning
26
+ */
27
+ version?: string | boolean;
28
+ };
29
+ export type CacheGetOptions = {
30
+ /**
31
+ * Cache key versioning (must match what was used when caching).
32
+ * - `string`: Explicit version prefix
33
+ * - `true`: Auto-generate version from schema hash
34
+ */
35
+ version?: string | boolean;
36
+ };
10
37
  declare const CacheError_base: Schema.TaggedErrorClass<CacheError, "CacheError", {
11
38
  readonly _tag: Schema.tag<"CacheError">;
12
39
  } & {
@@ -17,18 +44,44 @@ export declare class CacheError extends CacheError_base {
17
44
  }
18
45
  /**
19
46
  * Cache a computed value with automatic serialization and TTL.
47
+ * Supports stale-while-revalidate (SWR) for improved latency.
20
48
  *
21
49
  * @example
22
50
  * ```typescript
51
+ * // Basic usage
23
52
  * const user = yield* cache(
24
53
  * `user:${id}`,
25
54
  * Effect.tryPromise(() => db.query.users.findFirst({ where: eq(users.id, id) })),
26
55
  * UserSchema,
27
- * Duration.hours(1)
56
+ * { ttl: Duration.hours(1) }
57
+ * )
58
+ *
59
+ * // With stale-while-revalidate
60
+ * const user = yield* cache(
61
+ * `user:${id}`,
62
+ * fetchUser(id),
63
+ * UserSchema,
64
+ * { ttl: Duration.hours(1), swr: Duration.minutes(5) }
65
+ * )
66
+ *
67
+ * // With auto schema versioning (cache auto-invalidates when schema changes)
68
+ * const user = yield* cache(
69
+ * `user:${id}`,
70
+ * fetchUser(id),
71
+ * UserSchema,
72
+ * { ttl: Duration.hours(1), version: true }
73
+ * )
74
+ *
75
+ * // With explicit version
76
+ * const user = yield* cache(
77
+ * `user:${id}`,
78
+ * fetchUser(id),
79
+ * UserSchema,
80
+ * { ttl: Duration.hours(1), version: 'v2' }
28
81
  * )
29
82
  * ```
30
83
  */
31
- export declare const cache: <V, E, R>(key: string, compute: Effect.Effect<V, E, R>, schema: Schema.Schema<V>, ttl: Duration.DurationInput) => Effect.Effect<V, E | CacheError | CacheClientError | ParseResult.ParseError, R | CacheService>;
84
+ export declare const cache: <V, E, R>(key: string, compute: Effect.Effect<V, E, R>, schema: Schema.Schema<V>, options: CacheOptions) => Effect.Effect<V, E | CacheError | CacheClientError | ParseResult.ParseError, R | CacheService | ExecutionContextService>;
32
85
  /**
33
86
  * Get a value from cache without computing.
34
87
  *
@@ -38,27 +91,43 @@ export declare const cache: <V, E, R>(key: string, compute: Effect.Effect<V, E,
38
91
  * if (Option.isSome(cached)) {
39
92
  * return cached.value
40
93
  * }
94
+ *
95
+ * // With versioning (must match what was used when caching)
96
+ * const cached = yield* cacheGet(`user:${id}`, UserSchema, { version: true })
41
97
  * ```
42
98
  */
43
- export declare const cacheGet: <V>(key: string, schema: Schema.Schema<V>) => Effect.Effect<Option.Option<V>, CacheError | CacheClientError | ParseResult.ParseError, CacheService>;
99
+ export declare const cacheGet: <V>(key: string, schema: Schema.Schema<V>, options?: CacheGetOptions) => Effect.Effect<Option.Option<V>, CacheError | CacheClientError | ParseResult.ParseError, CacheService>;
44
100
  /**
45
101
  * Set a value in cache.
46
102
  *
47
103
  * @example
48
104
  * ```typescript
49
- * yield* cacheSet(`user:${id}`, user, UserSchema, Duration.hours(1))
105
+ * yield* cacheSet(`user:${id}`, user, UserSchema, { ttl: Duration.hours(1) })
106
+ *
107
+ * // With auto schema versioning
108
+ * yield* cacheSet(`user:${id}`, user, UserSchema, { ttl: Duration.hours(1), version: true })
50
109
  * ```
51
110
  */
52
- export declare const cacheSet: <V>(key: string, value: V, schema: Schema.Schema<V>, ttl: Duration.DurationInput) => Effect.Effect<void, CacheError | CacheClientError | ParseResult.ParseError, CacheService>;
111
+ export declare const cacheSet: <V>(key: string, value: V, schema: Schema.Schema<V>, options: CacheOptions) => Effect.Effect<void, CacheError | CacheClientError | ParseResult.ParseError, CacheService>;
112
+ export type CacheInvalidateOptions<V> = {
113
+ /** Schema used when caching (required if version is set) */
114
+ schema: Schema.Schema<V>;
115
+ /** Version option (must match what was used when caching) */
116
+ version: string | boolean;
117
+ };
53
118
  /**
54
119
  * Invalidate a cache key.
55
120
  *
56
121
  * @example
57
122
  * ```typescript
123
+ * // Simple invalidation
58
124
  * yield* cacheInvalidate(`user:${id}`)
125
+ *
126
+ * // Invalidate versioned key
127
+ * yield* cacheInvalidate(`user:${id}`, { schema: UserSchema, version: true })
59
128
  * ```
60
129
  */
61
- export declare const cacheInvalidate: (key: string) => Effect.Effect<void, CacheClientError, CacheService>;
130
+ export declare const cacheInvalidate: <V = unknown>(key: string, options?: CacheInvalidateOptions<V>) => Effect.Effect<void, CacheClientError, CacheService>;
62
131
  /**
63
132
  * Invalidate all cache keys with a given prefix.
64
133
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;;;;;;;AAMrE,qBAAa,UAAW,SAAQ,eAG9B;CAAG;AAML;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAC3B,KAAK,MAAM,EACX,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC/B,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACxB,KAAK,QAAQ,CAAC,aAAa,KAC1B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC,GAAG,YAAY,CAqB5F,CAAA;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,KAAK,MAAM,EACX,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KACvB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,YAAY,CAYnG,CAAA;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,KAAK,MAAM,EACX,OAAO,CAAC,EACR,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACxB,KAAK,QAAQ,CAAC,aAAa,KAC1B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,YAAY,CAQvF,CAAA;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,GAC1B,KAAK,MAAM,KACV,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,YAAY,CAIjD,CAAA;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,YAAY,CAWjD,CAAA"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAA;AAM9F,MAAM,MAAM,YAAY,GAAG;IACzB,qCAAqC;IACrC,GAAG,EAAE,QAAQ,CAAC,aAAa,CAAA;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAA;IAC5B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CAC3B,CAAA;;;;;;;AAMD,qBAAa,UAAW,SAAQ,eAG9B;CAAG;AA2DL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAC3B,KAAK,MAAM,EACX,SAAS,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC/B,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACxB,SAAS,YAAY,KACpB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC,GAAG,YAAY,GAAG,uBAAuB,CAuDtH,CAAA;AAEJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,KAAK,MAAM,EACX,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACxB,UAAU,eAAe,KACxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,YAAY,CAenG,CAAA;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,KAAK,MAAM,EACX,OAAO,CAAC,EACR,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACxB,SAAS,YAAY,KACpB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,gBAAgB,GAAG,WAAW,CAAC,UAAU,EAAE,YAAY,CAevF,CAAA;AAEJ,MAAM,MAAM,sBAAsB,CAAC,CAAC,IAAI;IACtC,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;IACxB,6DAA6D;IAC7D,OAAO,EAAE,MAAM,GAAG,OAAO,CAAA;CAC1B,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,CAAC,GAAG,OAAO,EACzC,KAAK,MAAM,EACX,UAAU,sBAAsB,CAAC,CAAC,CAAC,KAClC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,YAAY,CAOjD,CAAA;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAQ,MAAM,KACb,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,YAAY,CAWjD,CAAA"}
package/dist/cache.js CHANGED
@@ -4,9 +4,11 @@
4
4
  * Simple cache abstraction for storing expensive DB operations.
5
5
  * Uses CacheService which is automatically provided and backed by Cloudflare KV by default.
6
6
  * Can be swapped for Redis, Memcached, or any other implementation.
7
+ *
8
+ * Supports stale-while-revalidate (SWR) pattern for improved latency and resilience.
7
9
  */
8
10
  import { Effect, Option, Schema, Duration } from 'effect';
9
- import { CacheService } from './effect/services.js';
11
+ import { CacheService, ExecutionContextService } from './effect/services.js';
10
12
  // ============================================================================
11
13
  // Errors
12
14
  // ============================================================================
@@ -16,34 +18,128 @@ export class CacheError extends Schema.TaggedError()('CacheError', {
16
18
  }) {
17
19
  }
18
20
  // ============================================================================
21
+ // Internal
22
+ // ============================================================================
23
+ /** Internal schema for storing value with metadata */
24
+ const CacheEntrySchema = (valueSchema) => Schema.Struct({
25
+ v: valueSchema,
26
+ t: Schema.Number, // cachedAt timestamp
27
+ });
28
+ /**
29
+ * Simple string hash function (djb2 algorithm).
30
+ * Produces a short, deterministic hash for cache key versioning.
31
+ */
32
+ const hashString = (str) => {
33
+ let hash = 5381;
34
+ for (let i = 0; i < str.length; i++) {
35
+ hash = ((hash << 5) + hash) ^ str.charCodeAt(i);
36
+ }
37
+ // Convert to unsigned 32-bit and then to base36 for short strings
38
+ return (hash >>> 0).toString(36);
39
+ };
40
+ /**
41
+ * Generate a version string from a schema's AST.
42
+ * The hash changes when the schema structure changes.
43
+ */
44
+ const hashSchema = (schema) => {
45
+ // Stringify the AST - this captures the schema structure
46
+ const astString = JSON.stringify(schema.ast);
47
+ return hashString(astString);
48
+ };
49
+ /**
50
+ * Resolve the effective cache key with optional versioning.
51
+ */
52
+ const resolveKey = (key, schema, version) => {
53
+ if (version === true) {
54
+ return `${hashSchema(schema)}:${key}`;
55
+ }
56
+ if (typeof version === 'string') {
57
+ return `${version}:${key}`;
58
+ }
59
+ return key;
60
+ };
61
+ // ============================================================================
19
62
  // Composable API
20
63
  // ============================================================================
21
64
  /**
22
65
  * Cache a computed value with automatic serialization and TTL.
66
+ * Supports stale-while-revalidate (SWR) for improved latency.
23
67
  *
24
68
  * @example
25
69
  * ```typescript
70
+ * // Basic usage
26
71
  * const user = yield* cache(
27
72
  * `user:${id}`,
28
73
  * Effect.tryPromise(() => db.query.users.findFirst({ where: eq(users.id, id) })),
29
74
  * UserSchema,
30
- * Duration.hours(1)
75
+ * { ttl: Duration.hours(1) }
76
+ * )
77
+ *
78
+ * // With stale-while-revalidate
79
+ * const user = yield* cache(
80
+ * `user:${id}`,
81
+ * fetchUser(id),
82
+ * UserSchema,
83
+ * { ttl: Duration.hours(1), swr: Duration.minutes(5) }
84
+ * )
85
+ *
86
+ * // With auto schema versioning (cache auto-invalidates when schema changes)
87
+ * const user = yield* cache(
88
+ * `user:${id}`,
89
+ * fetchUser(id),
90
+ * UserSchema,
91
+ * { ttl: Duration.hours(1), version: true }
92
+ * )
93
+ *
94
+ * // With explicit version
95
+ * const user = yield* cache(
96
+ * `user:${id}`,
97
+ * fetchUser(id),
98
+ * UserSchema,
99
+ * { ttl: Duration.hours(1), version: 'v2' }
31
100
  * )
32
101
  * ```
33
102
  */
34
- export const cache = (key, compute, schema, ttl) => Effect.gen(function* () {
103
+ export const cache = (key, compute, schema, options) => Effect.gen(function* () {
35
104
  const cacheService = yield* CacheService;
105
+ const executionContext = yield* ExecutionContextService;
106
+ const entrySchema = CacheEntrySchema(schema);
107
+ const jsonSchema = Schema.parseJson(entrySchema);
108
+ const effectiveKey = resolveKey(key, schema, options.version);
109
+ const ttlMs = Duration.toMillis(Duration.decode(options.ttl));
110
+ const swrMs = options.swr ? Duration.toMillis(Duration.decode(options.swr)) : 0;
111
+ const totalTtlSeconds = Math.ceil((ttlMs + swrMs) / 1000);
112
+ // Helper to store a value in cache
113
+ const storeInCache = (value) => Effect.gen(function* () {
114
+ const newEntry = { v: value, t: Date.now() };
115
+ const serialized = yield* Schema.encode(jsonSchema)(newEntry);
116
+ yield* cacheService.put(effectiveKey, serialized, { expirationTtl: totalTtlSeconds });
117
+ });
36
118
  // Check cache first
37
- const cached = yield* cacheService.get(key);
119
+ const cached = yield* cacheService.get(effectiveKey);
38
120
  if (cached !== null) {
39
- return yield* Schema.decodeUnknown(Schema.parseJson(schema))(cached);
121
+ const entry = yield* Schema.decodeUnknown(jsonSchema)(cached);
122
+ const age = Date.now() - entry.t;
123
+ if (age < ttlMs) {
124
+ // Fresh - return immediately
125
+ return entry.v;
126
+ }
127
+ if (swrMs > 0 && age < ttlMs + swrMs) {
128
+ // Stale but within SWR window - return stale, trigger background refresh
129
+ if (executionContext.isAvailable) {
130
+ yield* executionContext.runInBackground(Effect.gen(function* () {
131
+ const freshValue = yield* compute;
132
+ yield* storeInCache(freshValue);
133
+ }));
134
+ }
135
+ return entry.v;
136
+ }
137
+ // Beyond SWR window - fall through to recompute
40
138
  }
41
- // Compute value
139
+ // Compute value (cold cache or expired)
42
140
  const value = yield* compute;
43
- // Store in cache
44
- const serialized = yield* Schema.encode(Schema.parseJson(schema))(value);
45
- const ttlSeconds = Duration.toSeconds(Duration.decode(ttl));
46
- yield* cacheService.put(key, serialized, { expirationTtl: ttlSeconds });
141
+ // Store with timestamp
142
+ yield* storeInCache(value);
47
143
  return value;
48
144
  });
49
145
  /**
@@ -55,42 +151,64 @@ export const cache = (key, compute, schema, ttl) => Effect.gen(function* () {
55
151
  * if (Option.isSome(cached)) {
56
152
  * return cached.value
57
153
  * }
154
+ *
155
+ * // With versioning (must match what was used when caching)
156
+ * const cached = yield* cacheGet(`user:${id}`, UserSchema, { version: true })
58
157
  * ```
59
158
  */
60
- export const cacheGet = (key, schema) => Effect.gen(function* () {
159
+ export const cacheGet = (key, schema, options) => Effect.gen(function* () {
61
160
  const cacheService = yield* CacheService;
62
- const cached = yield* cacheService.get(key);
161
+ const entrySchema = CacheEntrySchema(schema);
162
+ const jsonSchema = Schema.parseJson(entrySchema);
163
+ const effectiveKey = resolveKey(key, schema, options?.version);
164
+ const cached = yield* cacheService.get(effectiveKey);
63
165
  if (cached === null) {
64
166
  return Option.none();
65
167
  }
66
- const decoded = yield* Schema.decodeUnknown(Schema.parseJson(schema))(cached);
67
- return Option.some(decoded);
168
+ const entry = yield* Schema.decodeUnknown(jsonSchema)(cached);
169
+ return Option.some(entry.v);
68
170
  });
69
171
  /**
70
172
  * Set a value in cache.
71
173
  *
72
174
  * @example
73
175
  * ```typescript
74
- * yield* cacheSet(`user:${id}`, user, UserSchema, Duration.hours(1))
176
+ * yield* cacheSet(`user:${id}`, user, UserSchema, { ttl: Duration.hours(1) })
177
+ *
178
+ * // With auto schema versioning
179
+ * yield* cacheSet(`user:${id}`, user, UserSchema, { ttl: Duration.hours(1), version: true })
75
180
  * ```
76
181
  */
77
- export const cacheSet = (key, value, schema, ttl) => Effect.gen(function* () {
182
+ export const cacheSet = (key, value, schema, options) => Effect.gen(function* () {
78
183
  const cacheService = yield* CacheService;
79
- const serialized = yield* Schema.encode(Schema.parseJson(schema))(value);
80
- const ttlSeconds = Duration.toSeconds(Duration.decode(ttl));
81
- yield* cacheService.put(key, serialized, { expirationTtl: ttlSeconds });
184
+ const entrySchema = CacheEntrySchema(schema);
185
+ const jsonSchema = Schema.parseJson(entrySchema);
186
+ const effectiveKey = resolveKey(key, schema, options.version);
187
+ const ttlMs = Duration.toMillis(Duration.decode(options.ttl));
188
+ const swrMs = options.swr ? Duration.toMillis(Duration.decode(options.swr)) : 0;
189
+ const totalTtlSeconds = Math.ceil((ttlMs + swrMs) / 1000);
190
+ const entry = { v: value, t: Date.now() };
191
+ const serialized = yield* Schema.encode(jsonSchema)(entry);
192
+ yield* cacheService.put(effectiveKey, serialized, { expirationTtl: totalTtlSeconds });
82
193
  });
83
194
  /**
84
195
  * Invalidate a cache key.
85
196
  *
86
197
  * @example
87
198
  * ```typescript
199
+ * // Simple invalidation
88
200
  * yield* cacheInvalidate(`user:${id}`)
201
+ *
202
+ * // Invalidate versioned key
203
+ * yield* cacheInvalidate(`user:${id}`, { schema: UserSchema, version: true })
89
204
  * ```
90
205
  */
91
- export const cacheInvalidate = (key) => Effect.gen(function* () {
206
+ export const cacheInvalidate = (key, options) => Effect.gen(function* () {
92
207
  const cacheService = yield* CacheService;
93
- yield* cacheService.delete(key);
208
+ const effectiveKey = options
209
+ ? resolveKey(key, options.schema, options.version)
210
+ : key;
211
+ yield* cacheService.delete(effectiveKey);
94
212
  });
95
213
  /**
96
214
  * Invalidate all cache keys with a given prefix.
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { Effect, Layer, Schema as S } from 'effect';
7
7
  import type { Hono, MiddlewareHandler, Env } from 'hono';
8
- import { AuthUserService, AuthService, HonertiaService, RequestService, type AuthUser } from './services.js';
8
+ import { AuthUserService, AuthService, DatabaseService, HonertiaService, RequestService, type AuthUser } from './services.js';
9
9
  import { UnauthorizedError, ValidationError } from './errors.js';
10
10
  import { type EffectHandler } from './routing.js';
11
11
  /**
@@ -102,7 +102,7 @@ export declare function shareAuthMiddleware<E extends Env>(): MiddlewareHandler<
102
102
  * that's what the factory functions (betterAuthFormAction, betterAuthLogoutAction)
103
103
  * return, and effectAuthRoutes provides these services automatically.
104
104
  */
105
- export type AuthActionEffect<R = RequestService | AuthService, E extends Error = Error> = EffectHandler<R, E>;
105
+ export type AuthActionEffect<R = RequestService | AuthService | DatabaseService, E extends Error = Error> = EffectHandler<R, E>;
106
106
  /**
107
107
  * Configuration for auth routes.
108
108
  */
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/effect/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/effect/auth.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AACxD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7H,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAI/D;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,wDAiB5B,CAAA;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,8CAe7B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,EAC1C,UAAU,SAAM,GACf,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAsB9C;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CACM,CAAA;AAEvE;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAGlE,CAAA;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,mBAAqB,KACpB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,CAQhD,CAAA;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,mBAAgB,KACf,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,iBAAiB,EAAE,KAAK,CAQ5C,CAAA;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,eAAe,CAK9D,CAAA;AAEJ;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,GAAG,KAAK,iBAAiB,CAAC,CAAC,CAAC,CAYzE;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,CAC1B,CAAC,GAAG,cAAc,GAAG,WAAW,GAAG,eAAe,EAClD,CAAC,SAAS,KAAK,GAAG,KAAK,IACrB,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAEvB;;GAEG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,GAAG;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI,CAAC,CAAA;QAC3E,WAAW,CAAC,EAAE,OAAO,CAAA;KACtB,CAAA;IACD;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAA;IACzD;;;;OAIG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAA;IAC9B;;;;OAIG;IACH,cAAc,CAAC,EAAE,gBAAgB,CAAA;IACjC;;;;OAIG;IACH,YAAY,CAAC,EAAE,gBAAgB,CAAA;IAC/B;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAChD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,EAC5C,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EACZ,MAAM,GAAE,gBAAgB,CAAC,CAAC,CAAM,GAC/B,IAAI,CAoHN;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,GAAG,EACpC,MAAM,GAAE;IACN,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,aAAa,CAAC,EAAE,MAAM,CAAA;CAClB,GACL,iBAAiB,CAAC,CAAC,CAAC,CA4BtB;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B,QAAQ,GACR,OAAO,GACP;IAAE,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAA;CAAE,CAAA;AAEvC;;GAEG;AACH,MAAM,WAAW,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO;IACpE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAA;IACvF,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxD,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,sBAAsB,KAAK,MAAM,CAAC,CAAA;CAC7E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,EAC7D,MAAM,EAAE,0BAA0B,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GACnD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,GAAG,WAAW,CAAC,CAiCxE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,GAAE,sBAA2B,GAClC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,cAAc,GAAG,WAAW,CAAC,CAiC9D"}
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { Layer, ManagedRuntime } from 'effect';
7
7
  import type { Context as HonoContext, MiddlewareHandler, Env } from 'hono';
8
- import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService } from './services.js';
8
+ import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, ExecutionContextService } from './services.js';
9
9
  /**
10
10
  * Configuration for the Effect bridge.
11
11
  *
@@ -61,7 +61,7 @@ declare module 'hono' {
61
61
  /**
62
62
  * Build the Effect layer from Hono context.
63
63
  */
64
- export declare function buildContextLayer<E extends Env, CustomServices = never>(c: HonoContext<E>, config?: EffectBridgeConfig<E, CustomServices>): Layer.Layer<RequestService | ResponseFactoryService | HonertiaService | DatabaseService | AuthService | AuthUserService | BindingsService | CacheService | CustomServices, never, never>;
64
+ export declare function buildContextLayer<E extends Env, CustomServices = never>(c: HonoContext<E>, config?: EffectBridgeConfig<E, CustomServices>): Layer.Layer<RequestService | ResponseFactoryService | HonertiaService | DatabaseService | AuthService | AuthUserService | BindingsService | CacheService | ExecutionContextService | CustomServices, never, never>;
65
65
  /**
66
66
  * Get the Effect runtime from Hono context.
67
67
  */
@@ -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,EAUb,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;;;;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;AA2GD;;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,cAAc,EAChB,KAAK,EACL,KAAK,CACN,CA6EA;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,CA6CtB;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"}
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;;;;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;AA0JD;;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,CA8FA;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,CA6CtB;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"}
@@ -6,7 +6,7 @@
6
6
  import { Effect, Layer, ManagedRuntime, Option } from 'effect';
7
7
  import { HonertiaConfigurationError } from './errors.js';
8
8
  import { ErrorCodes } from './error-catalog.js';
9
- import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, } from './services.js';
9
+ import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, ExecutionContextService, } from './services.js';
10
10
  import { TestCaptureService } from './test-layers.js';
11
11
  /**
12
12
  * Symbol for storing Effect runtime in Hono context.
@@ -123,6 +123,35 @@ function createUnconfiguredCacheClient() {
123
123
  list: () => Effect.fail(error),
124
124
  };
125
125
  }
126
+ /**
127
+ * Create an ExecutionContextClient from Cloudflare's ExecutionContext.
128
+ */
129
+ function createExecutionContextClient(ctx) {
130
+ return {
131
+ isAvailable: true,
132
+ waitUntil: (promise) => ctx.waitUntil(promise),
133
+ runInBackground: (effect) => Effect.flatMap(Effect.context(), (context) => Effect.sync(() => {
134
+ const promise = Effect.runPromise(effect.pipe(Effect.provide(context), Effect.catchAllCause((cause) => {
135
+ // Log errors but don't crash - this is background work
136
+ console.error('[Background Task Error]', cause);
137
+ return Effect.void;
138
+ })));
139
+ ctx.waitUntil(promise);
140
+ })),
141
+ };
142
+ }
143
+ /**
144
+ * Create a no-op ExecutionContextClient for environments without ExecutionContext.
145
+ */
146
+ function createNoopExecutionContextClient() {
147
+ return {
148
+ isAvailable: false,
149
+ waitUntil: () => {
150
+ // No-op - silently ignore in non-Worker environments
151
+ },
152
+ runInBackground: () => Effect.void,
153
+ };
154
+ }
126
155
  /**
127
156
  * Create a HonertiaRenderer from Hono context.
128
157
  */
@@ -161,7 +190,19 @@ export function buildContextLayer(c, config) {
161
190
  const auth = c.var?.auth;
162
191
  const authLayer = Layer.succeed(AuthService, (auth ??
163
192
  createUnconfiguredServiceProxy('AuthService', 'auth: (c) => createAuth(...)', 'auth: (c) => betterAuth({ database: c.var.db, ... })', ErrorCodes.CFG_301_AUTH_NOT_CONFIGURED)));
164
- let baseLayer = Layer.mergeAll(requestLayer, responseLayer, honertiaLayer, bindingsLayer, cacheLayer, databaseLayer, authLayer);
193
+ // ExecutionContext layer - for background task execution
194
+ // Note: Hono's executionCtx getter throws in non-Worker environments, so we wrap in try/catch
195
+ let executionCtx;
196
+ try {
197
+ executionCtx = c.executionCtx;
198
+ }
199
+ catch {
200
+ executionCtx = undefined;
201
+ }
202
+ const executionContextLayer = Layer.succeed(ExecutionContextService, executionCtx
203
+ ? createExecutionContextClient(executionCtx)
204
+ : createNoopExecutionContextClient());
205
+ let baseLayer = Layer.mergeAll(requestLayer, responseLayer, honertiaLayer, bindingsLayer, cacheLayer, databaseLayer, authLayer, executionContextLayer);
165
206
  if (c.var?.authUser) {
166
207
  baseLayer = Layer.merge(baseLayer, Layer.succeed(AuthUserService, c.var.authUser));
167
208
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Re-exports all Effect-related functionality.
5
5
  */
6
- export { DatabaseService, AuthService, AuthUserService, EmailService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, authorize, type AuthUser, type EmailClient, type HonertiaRenderer, type RequestContext, type ResponseFactory, type CacheClient, type HonertiaDatabaseType, type HonertiaAuthType, type HonertiaBindingsType, type HonertiaAuthUserType, type DefaultAuthUser, type DatabaseType, type SchemaType, type AuthType, type BindingsType, } from './services.js';
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
9
  export { ErrorCodes, ErrorCatalog, createStructuredError, getConfigErrorCode, getErrorDefinition, getErrorsByCategory, type ErrorCode, } from './error-catalog.js';
@@ -21,6 +21,6 @@ export { RouteRegistry, getGlobalRegistry, resetGlobalRegistry, type HttpMethod,
21
21
  export { describeRoute, createRouteTester, generateTestCases, type TestUserType, type TestUser, type TestRequestOptions, type TestExpectation, type TestContext, type TestCaseOptions, type TestFn, type TestAppConfig, } from './testing.js';
22
22
  export { TestLayer, TestCaptureService, type TestCaptures, } from './test-layers.js';
23
23
  export { BoundModels, BoundModelNotFound, bound, pluralize, parseBindings, toHonoPath, type ParsedBinding, type BoundModel, } from './binding.js';
24
- export { CacheError, cache, cacheGet, cacheSet, cacheInvalidate, cacheInvalidatePrefix, } from '../cache.js';
24
+ export { CacheError, cache, cacheGet, cacheSet, cacheInvalidate, cacheInvalidatePrefix, type CacheOptions, type CacheGetOptions, type CacheInvalidateOptions, } from '../cache.js';
25
25
  export { RequireAuthLayer, RequireGuestLayer, createGuestLayer, isAuthenticated, currentUser, requireAuth, requireGuest, shareAuth, shareAuthMiddleware, effectAuthRoutes, betterAuthFormAction, betterAuthLogoutAction, loadUser, type AuthRoutesConfig, type BetterAuthFormActionConfig, type BetterAuthLogoutConfig, type BetterAuthActionResult, } from './auth.js';
26
26
  //# sourceMappingURL=index.d.ts.map
@@ -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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"}
@@ -4,7 +4,7 @@
4
4
  * Re-exports all Effect-related functionality.
5
5
  */
6
6
  // Services
7
- export { DatabaseService, AuthService, AuthUserService, EmailService, HonertiaService, RequestService, ResponseFactoryService, BindingsService, CacheService, CacheClientError, authorize, } from './services.js';
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
10
  // Error Catalog
@@ -288,6 +288,70 @@ export declare class CacheClientError {
288
288
  declare const CacheService_base: Context.TagClass<CacheService, "honertia/Cache", CacheClient>;
289
289
  export declare class CacheService extends CacheService_base {
290
290
  }
291
+ /**
292
+ * Client interface for background execution.
293
+ * Wraps Cloudflare's ExecutionContext with Effect-native methods.
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const ctx = yield* ExecutionContextService
298
+ *
299
+ * // Effect-native: run an Effect in the background
300
+ * yield* ctx.runInBackground(
301
+ * sendAnalyticsEvent({ userId, page: 'dashboard' })
302
+ * )
303
+ *
304
+ * // Raw API: for promises from external libraries
305
+ * ctx.waitUntil(externalLib.doSomething())
306
+ *
307
+ * // Check availability before optional background work
308
+ * if (ctx.isAvailable) {
309
+ * yield* ctx.runInBackground(touchSession())
310
+ * }
311
+ * ```
312
+ */
313
+ export interface ExecutionContextClient {
314
+ /**
315
+ * Whether background execution is available.
316
+ * False in tests or non-Worker environments.
317
+ */
318
+ readonly isAvailable: boolean;
319
+ /**
320
+ * Run an Effect in the background after the response is sent.
321
+ * Errors are caught and logged - they won't crash the worker.
322
+ *
323
+ * The Effect's requirements (R) must be satisfied by the current context.
324
+ * Returns immediately - the actual work happens asynchronously.
325
+ */
326
+ runInBackground: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<void, never, R>;
327
+ /**
328
+ * Raw waitUntil - extends worker lifetime for a Promise.
329
+ * Use this for promises from external libraries.
330
+ * No-op if background execution is unavailable.
331
+ */
332
+ waitUntil: (promise: Promise<unknown>) => void;
333
+ }
334
+ declare const ExecutionContextService_base: Context.TagClass<ExecutionContextService, "honertia/ExecutionContext", ExecutionContextClient>;
335
+ /**
336
+ * Execution Context Service - Background task execution for Cloudflare Workers.
337
+ *
338
+ * Automatically provided by the Effect bridge. Uses Cloudflare's `waitUntil`
339
+ * to run work after the response is sent.
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * // In an action - send analytics without blocking response
344
+ * const ctx = yield* ExecutionContextService
345
+ * yield* ctx.runInBackground(
346
+ * Effect.tryPromise(() => fetch('https://analytics.example.com/events', {
347
+ * method: 'POST',
348
+ * body: JSON.stringify({ event: 'page_view', userId })
349
+ * }))
350
+ * )
351
+ * ```
352
+ */
353
+ export declare class ExecutionContextService extends ExecutionContextService_base {
354
+ }
291
355
  /**
292
356
  * Authorization helper - opt-in to auth check.
293
357
  *
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/effect/services.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/effect/services.ts"],"names":[],"mappings":"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"}
@@ -66,6 +66,26 @@ export class CacheClientError {
66
66
  }
67
67
  export class CacheService extends Context.Tag('honertia/Cache')() {
68
68
  }
69
+ /**
70
+ * Execution Context Service - Background task execution for Cloudflare Workers.
71
+ *
72
+ * Automatically provided by the Effect bridge. Uses Cloudflare's `waitUntil`
73
+ * to run work after the response is sent.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * // In an action - send analytics without blocking response
78
+ * const ctx = yield* ExecutionContextService
79
+ * yield* ctx.runInBackground(
80
+ * Effect.tryPromise(() => fetch('https://analytics.example.com/events', {
81
+ * method: 'POST',
82
+ * body: JSON.stringify({ event: 'page_view', userId })
83
+ * }))
84
+ * )
85
+ * ```
86
+ */
87
+ export class ExecutionContextService extends Context.Tag('honertia/ExecutionContext')() {
88
+ }
69
89
  /**
70
90
  * Authorization helper - opt-in to auth check.
71
91
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "honertia",
3
- "version": "0.1.37",
3
+ "version": "0.1.40",
4
4
  "description": "Inertia.js-style server-driven SPA adapter for Hono",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",