ai-props 2.1.3 → 2.4.0

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.
Files changed (105) hide show
  1. package/.dev.vars +2 -0
  2. package/.turbo/turbo-build.log +1 -1
  3. package/CHANGELOG.md +20 -0
  4. package/README.md +2 -0
  5. package/dist/ai.d.ts.map +1 -1
  6. package/dist/ai.js +4 -4
  7. package/dist/ai.js.map +1 -1
  8. package/dist/cascade.d.ts +329 -0
  9. package/dist/cascade.d.ts.map +1 -0
  10. package/dist/cascade.js +522 -0
  11. package/dist/cascade.js.map +1 -0
  12. package/dist/client.d.ts +233 -0
  13. package/dist/client.d.ts.map +1 -0
  14. package/dist/client.js +191 -0
  15. package/dist/client.js.map +1 -0
  16. package/dist/durable-cascade.d.ts +280 -0
  17. package/dist/durable-cascade.d.ts.map +1 -0
  18. package/dist/durable-cascade.js +469 -0
  19. package/dist/durable-cascade.js.map +1 -0
  20. package/dist/event-bridge.d.ts +257 -0
  21. package/dist/event-bridge.d.ts.map +1 -0
  22. package/dist/event-bridge.js +317 -0
  23. package/dist/event-bridge.js.map +1 -0
  24. package/dist/generate.d.ts.map +1 -1
  25. package/dist/generate.js +12 -6
  26. package/dist/generate.js.map +1 -1
  27. package/dist/hoc.d.ts.map +1 -1
  28. package/dist/hoc.js +13 -13
  29. package/dist/hoc.js.map +1 -1
  30. package/dist/hono-jsx.d.ts +208 -0
  31. package/dist/hono-jsx.d.ts.map +1 -0
  32. package/dist/hono-jsx.js +459 -0
  33. package/dist/hono-jsx.js.map +1 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +2 -0
  37. package/dist/index.js.map +1 -1
  38. package/dist/mdx-types.d.ts +152 -0
  39. package/dist/mdx-types.d.ts.map +1 -0
  40. package/dist/mdx-types.js +9 -0
  41. package/dist/mdx-types.js.map +1 -0
  42. package/dist/mdx-utils.d.ts +106 -0
  43. package/dist/mdx-utils.d.ts.map +1 -0
  44. package/dist/mdx-utils.js +384 -0
  45. package/dist/mdx-utils.js.map +1 -0
  46. package/dist/mdx.d.ts +230 -0
  47. package/dist/mdx.d.ts.map +1 -0
  48. package/dist/mdx.js +820 -0
  49. package/dist/mdx.js.map +1 -0
  50. package/dist/rpc.d.ts +313 -0
  51. package/dist/rpc.d.ts.map +1 -0
  52. package/dist/rpc.js +359 -0
  53. package/dist/rpc.js.map +1 -0
  54. package/dist/streaming.d.ts +199 -0
  55. package/dist/streaming.d.ts.map +1 -0
  56. package/dist/streaming.js +402 -0
  57. package/dist/streaming.js.map +1 -0
  58. package/dist/validate.d.ts.map +1 -1
  59. package/dist/validate.js +11 -13
  60. package/dist/validate.js.map +1 -1
  61. package/dist/worker.d.ts +270 -0
  62. package/dist/worker.d.ts.map +1 -0
  63. package/dist/worker.js +405 -0
  64. package/dist/worker.js.map +1 -0
  65. package/package.json +39 -13
  66. package/src/ai.ts +12 -31
  67. package/src/cascade.ts +795 -0
  68. package/src/client.ts +440 -0
  69. package/src/durable-cascade.ts +743 -0
  70. package/src/event-bridge.ts +478 -0
  71. package/src/generate.ts +14 -12
  72. package/src/hoc.ts +15 -19
  73. package/src/hono-jsx.ts +675 -0
  74. package/src/index.ts +30 -0
  75. package/src/mdx-types.ts +169 -0
  76. package/src/mdx-utils.ts +437 -0
  77. package/src/mdx.ts +1008 -0
  78. package/src/rpc.ts +614 -0
  79. package/src/streaming.ts +618 -0
  80. package/src/validate.ts +15 -29
  81. package/src/worker.ts +547 -0
  82. package/test/cascade.test.ts +338 -0
  83. package/test/durable-cascade.test.ts +319 -0
  84. package/test/event-bridge.test.ts +351 -0
  85. package/test/generate.test.ts +6 -16
  86. package/test/mdx.test.ts +817 -0
  87. package/test/worker/capnweb-rpc.test.ts +1084 -0
  88. package/test/worker/full-flow.integration.test.ts +1463 -0
  89. package/test/worker/hono-jsx.test.ts +1258 -0
  90. package/test/worker/mdx-parsing.test.ts +1148 -0
  91. package/test/worker/setup.ts +56 -0
  92. package/test/worker.test.ts +595 -0
  93. package/tsconfig.json +2 -1
  94. package/vitest.config.js +6 -0
  95. package/vitest.config.ts +15 -1
  96. package/vitest.workers.config.ts +58 -0
  97. package/wrangler.jsonc +27 -0
  98. package/LICENSE +0 -21
  99. package/src/ai.js +0 -198
  100. package/src/cache.js +0 -182
  101. package/src/generate.js +0 -220
  102. package/src/hoc.js +0 -235
  103. package/src/index.js +0 -20
  104. package/src/types.js +0 -6
  105. package/src/validate.js +0 -252
package/src/validate.ts CHANGED
@@ -33,12 +33,12 @@ export function validateProps(
33
33
 
34
34
  if (typeof schema === 'string') {
35
35
  // Simple string schema - just check if value exists
36
- if (!props.value) {
36
+ if (!props['value']) {
37
37
  errors.push({
38
38
  path: 'value',
39
39
  message: 'Value is required',
40
40
  expected: 'string',
41
- received: props.value,
41
+ received: props['value'],
42
42
  })
43
43
  }
44
44
  return { valid: errors.length === 0, errors }
@@ -194,7 +194,7 @@ export function hasRequiredProps<P extends Record<string, unknown>>(
194
194
  props: Partial<P>,
195
195
  required: (keyof P)[]
196
196
  ): boolean {
197
- return required.every(key => props[key] !== undefined)
197
+ return required.every((key) => props[key] !== undefined)
198
198
  }
199
199
 
200
200
  /**
@@ -204,35 +204,29 @@ export function getMissingProps<P extends Record<string, unknown>>(
204
204
  props: Partial<P>,
205
205
  required: (keyof P)[]
206
206
  ): (keyof P)[] {
207
- return required.filter(key => props[key] === undefined)
207
+ return required.filter((key) => props[key] === undefined)
208
208
  }
209
209
 
210
210
  /**
211
211
  * Check if props are complete according to schema
212
212
  */
213
- export function isComplete(
214
- props: Record<string, unknown>,
215
- schema: PropSchema
216
- ): boolean {
213
+ export function isComplete(props: Record<string, unknown>, schema: PropSchema): boolean {
217
214
  if (typeof schema === 'string') {
218
- return props.value !== undefined
215
+ return props['value'] !== undefined
219
216
  }
220
217
 
221
- return Object.keys(schema).every(key => props[key] !== undefined)
218
+ return Object.keys(schema).every((key) => props[key] !== undefined)
222
219
  }
223
220
 
224
221
  /**
225
222
  * Get list of missing props according to schema
226
223
  */
227
- export function getMissingFromSchema(
228
- props: Record<string, unknown>,
229
- schema: PropSchema
230
- ): string[] {
224
+ export function getMissingFromSchema(props: Record<string, unknown>, schema: PropSchema): string[] {
231
225
  if (typeof schema === 'string') {
232
- return props.value === undefined ? ['value'] : []
226
+ return props['value'] === undefined ? ['value'] : []
233
227
  }
234
228
 
235
- return Object.keys(schema).filter(key => props[key] === undefined)
229
+ return Object.keys(schema).filter((key) => props[key] === undefined)
236
230
  }
237
231
 
238
232
  /**
@@ -243,7 +237,7 @@ export function sanitizeProps<P extends Record<string, unknown>>(
243
237
  schema: PropSchema
244
238
  ): Partial<P> {
245
239
  if (typeof schema === 'string') {
246
- return { value: (props as Record<string, unknown>).value } as unknown as Partial<P>
240
+ return { value: (props as Record<string, unknown>)['value'] } as unknown as Partial<P>
247
241
  }
248
242
 
249
243
  const schemaKeys = new Set(Object.keys(schema))
@@ -273,15 +267,10 @@ export function mergeWithDefaults<P extends Record<string, unknown>>(
273
267
  for (const [key, schemaDef] of Object.entries(schema)) {
274
268
  if (result[key as keyof P] === undefined) continue
275
269
 
276
- const expectedType = typeof schemaDef === 'string'
277
- ? extractTypeFromSchema(schemaDef)
278
- : null
270
+ const expectedType = typeof schemaDef === 'string' ? extractTypeFromSchema(schemaDef) : null
279
271
 
280
272
  if (expectedType) {
281
- result[key as keyof P] = coerceType(
282
- result[key as keyof P],
283
- expectedType
284
- ) as P[keyof P]
273
+ result[key as keyof P] = coerceType(result[key as keyof P], expectedType) as P[keyof P]
285
274
  }
286
275
  }
287
276
  }
@@ -321,13 +310,10 @@ export function createValidator<P extends Record<string, unknown>>(
321
310
  /**
322
311
  * Assert props are valid, throwing on error
323
312
  */
324
- export function assertValidProps(
325
- props: Record<string, unknown>,
326
- schema: PropSchema
327
- ): void {
313
+ export function assertValidProps(props: Record<string, unknown>, schema: PropSchema): void {
328
314
  const result = validateProps(props, schema)
329
315
  if (!result.valid) {
330
- const messages = result.errors.map(e => `${e.path}: ${e.message}`).join(', ')
316
+ const messages = result.errors.map((e) => `${e.path}: ${e.message}`).join(', ')
331
317
  throw new Error(`Invalid props: ${messages}`)
332
318
  }
333
319
  }
package/src/worker.ts ADDED
@@ -0,0 +1,547 @@
1
+ /**
2
+ * Worker Export - WorkerEntrypoint for RPC access to AI Props
3
+ *
4
+ * Exposes AI props generation methods via Cloudflare RPC.
5
+ * Provides schema-based prop generation, caching, validation,
6
+ * and cascade execution patterns.
7
+ *
8
+ * ## Features
9
+ *
10
+ * - **RPC Service**: WorkerEntrypoint for service binding access
11
+ * - **Cascade Execution**: Code -> Generative -> Agentic -> Human escalation
12
+ * - **Durable Cascades**: Cloudflare Workflows integration for durability
13
+ * - **AI Gateway**: Configuration helpers for Cloudflare AI Gateway
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // wrangler.jsonc
18
+ * {
19
+ * "services": [
20
+ * { "binding": "AI_PROPS", "service": "ai-props" }
21
+ * ]
22
+ * }
23
+ *
24
+ * // worker.ts - consuming service
25
+ * export default {
26
+ * async fetch(request: Request, env: Env) {
27
+ * const service = env.AI_PROPS.connect()
28
+ * const result = await service.generate({
29
+ * schema: { title: 'Page title', description: 'Page description' },
30
+ * context: { topic: 'AI' }
31
+ * })
32
+ * return Response.json(result.props)
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * ## Cascade Pattern
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import {
42
+ * DurableCascadeExecutor,
43
+ * createDurableCascadeStep,
44
+ * createAIGatewayConfig
45
+ * } from 'ai-props/worker'
46
+ *
47
+ * // Create a durable cascade for content generation
48
+ * const contentCascade = createDurableCascadeStep({
49
+ * name: 'generate-content',
50
+ * code: async (input) => {
51
+ * if (input.template) return { content: input.template }
52
+ * throw new Error('No template available')
53
+ * },
54
+ * generative: async (input, ctx) => {
55
+ * const result = await ctx.ai.run('@cf/meta/llama-3-8b-instruct', {
56
+ * messages: [{ role: 'user', content: `Generate content about: ${input.topic}` }]
57
+ * })
58
+ * return { content: result.response }
59
+ * }
60
+ * })
61
+ *
62
+ * // In a Cloudflare Workflow
63
+ * const result = await contentCascade.run(step, { topic: 'AI' })
64
+ * console.log(result.tier) // 'code' or 'generative'
65
+ * ```
66
+ *
67
+ * @packageDocumentation
68
+ */
69
+
70
+ import { WorkerEntrypoint, RpcTarget } from 'cloudflare:workers'
71
+ import type {
72
+ PropSchema,
73
+ GeneratePropsOptions,
74
+ GeneratePropsResult,
75
+ AIPropsConfig,
76
+ PropsCache,
77
+ PropsCacheEntry,
78
+ ValidationResult,
79
+ } from './types.js'
80
+ import {
81
+ generateProps,
82
+ getPropsSync,
83
+ prefetchProps,
84
+ generatePropsMany,
85
+ mergeWithGenerated,
86
+ configureAIProps,
87
+ getConfig,
88
+ resetConfig,
89
+ } from './generate.js'
90
+ import {
91
+ MemoryPropsCache,
92
+ LRUPropsCache,
93
+ createCacheKey,
94
+ getDefaultCache,
95
+ configureCache,
96
+ clearCache,
97
+ } from './cache.js'
98
+ import {
99
+ validateProps,
100
+ hasRequiredProps,
101
+ getMissingFromSchema,
102
+ isComplete,
103
+ sanitizeProps,
104
+ mergeWithDefaults,
105
+ } from './validate.js'
106
+
107
+ /**
108
+ * Environment bindings for the worker
109
+ */
110
+ export interface Env {
111
+ AI?: unknown
112
+ }
113
+
114
+ /**
115
+ * PropsServiceCore - RpcTarget wrapper for AI props functionality
116
+ *
117
+ * Exposes all required methods as RPC-callable methods.
118
+ * This is the core service class that can be instantiated directly.
119
+ */
120
+ export class PropsServiceCore extends RpcTarget {
121
+ private cache: MemoryPropsCache
122
+
123
+ constructor() {
124
+ super()
125
+ this.cache = getDefaultCache()
126
+ }
127
+
128
+ // ==================== Generation ====================
129
+
130
+ /**
131
+ * Generate props using AI
132
+ *
133
+ * @example
134
+ * ```ts
135
+ * const result = await service.generate({
136
+ * schema: {
137
+ * title: 'A compelling page title',
138
+ * description: 'A brief description',
139
+ * },
140
+ * context: { topic: 'AI-powered applications' },
141
+ * })
142
+ * ```
143
+ */
144
+ async generate<T = Record<string, unknown>>(
145
+ options: GeneratePropsOptions
146
+ ): Promise<GeneratePropsResult<T>> {
147
+ return generateProps<T>(options)
148
+ }
149
+
150
+ /**
151
+ * Generate props synchronously from cache
152
+ *
153
+ * @throws {Error} If props are not in cache
154
+ */
155
+ getSync<T = Record<string, unknown>>(schema: PropSchema, context?: Record<string, unknown>): T {
156
+ return getPropsSync<T>(schema, context)
157
+ }
158
+
159
+ /**
160
+ * Pre-generate props for warming the cache
161
+ */
162
+ async prefetch(requests: GeneratePropsOptions[]): Promise<void> {
163
+ return prefetchProps(requests)
164
+ }
165
+
166
+ /**
167
+ * Generate multiple prop sets in parallel
168
+ */
169
+ async generateMany<T = Record<string, unknown>>(
170
+ requests: GeneratePropsOptions[]
171
+ ): Promise<GeneratePropsResult<T>[]> {
172
+ return generatePropsMany<T>(requests)
173
+ }
174
+
175
+ /**
176
+ * Merge partial props with generated props
177
+ *
178
+ * Generates only the missing props, keeping provided ones.
179
+ */
180
+ async mergeWithGenerated<T extends Record<string, unknown>>(
181
+ schema: PropSchema,
182
+ partialProps: Partial<T>,
183
+ options?: Omit<GeneratePropsOptions, 'schema' | 'context'>
184
+ ): Promise<T> {
185
+ return mergeWithGenerated<T>(schema, partialProps, options)
186
+ }
187
+
188
+ // ==================== Configuration ====================
189
+
190
+ /**
191
+ * Configure global AI props settings
192
+ */
193
+ configure(config: Partial<AIPropsConfig>): void {
194
+ configureAIProps(config)
195
+ }
196
+
197
+ /**
198
+ * Get current configuration
199
+ */
200
+ getConfig(): AIPropsConfig {
201
+ return getConfig()
202
+ }
203
+
204
+ /**
205
+ * Reset configuration to defaults
206
+ */
207
+ resetConfig(): void {
208
+ resetConfig()
209
+ }
210
+
211
+ // ==================== Cache Operations ====================
212
+
213
+ /**
214
+ * Get cached props by key
215
+ */
216
+ getCached<T>(key: string): PropsCacheEntry<T> | undefined {
217
+ return this.cache.get<T>(key)
218
+ }
219
+
220
+ /**
221
+ * Set props in cache
222
+ */
223
+ setCached<T>(key: string, props: T): void {
224
+ this.cache.set(key, props)
225
+ }
226
+
227
+ /**
228
+ * Delete cached entry by key
229
+ */
230
+ deleteCached(key: string): boolean {
231
+ return this.cache.delete(key)
232
+ }
233
+
234
+ /**
235
+ * Clear all cached props
236
+ */
237
+ clearCache(): void {
238
+ clearCache()
239
+ }
240
+
241
+ /**
242
+ * Get cache size
243
+ */
244
+ getCacheSize(): number {
245
+ return this.cache.size
246
+ }
247
+
248
+ /**
249
+ * Create a cache key from schema and context
250
+ */
251
+ createCacheKey(schema: PropSchema, context?: Record<string, unknown>): string {
252
+ return createCacheKey(schema, context)
253
+ }
254
+
255
+ /**
256
+ * Configure cache TTL
257
+ */
258
+ configureCache(ttl: number): void {
259
+ configureCache(ttl)
260
+ this.cache = getDefaultCache()
261
+ }
262
+
263
+ // ==================== Validation ====================
264
+
265
+ /**
266
+ * Validate props against a schema
267
+ */
268
+ validate(props: Record<string, unknown>, schema: PropSchema): ValidationResult {
269
+ return validateProps(props, schema)
270
+ }
271
+
272
+ /**
273
+ * Check if all required props are present
274
+ */
275
+ hasRequired(props: Record<string, unknown>, required: string[]): boolean {
276
+ return hasRequiredProps(props, required)
277
+ }
278
+
279
+ /**
280
+ * Get list of missing props according to schema
281
+ */
282
+ getMissing(props: Record<string, unknown>, schema: PropSchema): string[] {
283
+ return getMissingFromSchema(props, schema)
284
+ }
285
+
286
+ /**
287
+ * Check if props are complete according to schema
288
+ */
289
+ isComplete(props: Record<string, unknown>, schema: PropSchema): boolean {
290
+ return isComplete(props, schema)
291
+ }
292
+
293
+ /**
294
+ * Sanitize props by removing unknown keys
295
+ */
296
+ sanitize<T extends Record<string, unknown>>(props: T, schema: PropSchema): Partial<T> {
297
+ return sanitizeProps(props, schema)
298
+ }
299
+
300
+ /**
301
+ * Merge props with default values
302
+ */
303
+ mergeDefaults<T extends Record<string, unknown>>(
304
+ props: Partial<T>,
305
+ defaults: Partial<T>,
306
+ schema: PropSchema
307
+ ): Partial<T> {
308
+ return mergeWithDefaults(props, defaults, schema)
309
+ }
310
+ }
311
+
312
+ /**
313
+ * PropsService - WorkerEntrypoint for RPC access
314
+ *
315
+ * Provides `connect()` method that returns an RpcTarget service
316
+ * with all AI props methods. Also handles HTTP endpoints for
317
+ * direct JSON-RPC access.
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * // In consuming worker
322
+ * const service = env.AI_PROPS.connect()
323
+ * const result = await service.generate({
324
+ * schema: { title: 'Page title' }
325
+ * })
326
+ * ```
327
+ */
328
+ export class PropsService extends WorkerEntrypoint<Env> {
329
+ private serviceCore: PropsServiceCore | null = null
330
+
331
+ /**
332
+ * Get or create the service core instance
333
+ */
334
+ private getServiceCore(): PropsServiceCore {
335
+ if (!this.serviceCore) {
336
+ this.serviceCore = new PropsServiceCore()
337
+ }
338
+ return this.serviceCore
339
+ }
340
+
341
+ /**
342
+ * Get a connected service instance for RPC calls
343
+ *
344
+ * Note: Named 'getService' instead of 'connect' because 'connect'
345
+ * is a reserved method name in Cloudflare Workers RPC (used for sockets).
346
+ *
347
+ * @returns PropsServiceCore instance for RPC calls
348
+ */
349
+ getService(): PropsServiceCore {
350
+ return this.getServiceCore()
351
+ }
352
+
353
+ /**
354
+ * Alias for getService() - provides the connect() interface
355
+ * Note: This may conflict with the Fetcher's connect() for sockets
356
+ * when accessed via service bindings. Use getService() instead.
357
+ *
358
+ * @deprecated Use getService() instead
359
+ * @returns PropsServiceCore instance for RPC calls
360
+ */
361
+ connect(): PropsServiceCore {
362
+ return this.getServiceCore()
363
+ }
364
+
365
+ /**
366
+ * HTTP request handler for JSON-RPC and service info endpoints
367
+ *
368
+ * Routes:
369
+ * - GET / - Returns service info
370
+ * - POST /rpc - JSON-RPC endpoint for calling service methods
371
+ */
372
+ override async fetch(request: Request): Promise<Response> {
373
+ const url = new URL(request.url)
374
+
375
+ // GET / - Service info
376
+ if (request.method === 'GET' && url.pathname === '/') {
377
+ const service = this.getServiceCore()
378
+ return Response.json({
379
+ name: 'ai-props',
380
+ version: '1.0.0',
381
+ methods: [
382
+ 'generate',
383
+ 'getSync',
384
+ 'prefetch',
385
+ 'generateMany',
386
+ 'mergeWithGenerated',
387
+ 'configure',
388
+ 'getConfig',
389
+ 'resetConfig',
390
+ 'getCached',
391
+ 'setCached',
392
+ 'deleteCached',
393
+ 'clearCache',
394
+ 'getCacheSize',
395
+ 'createCacheKey',
396
+ 'configureCache',
397
+ 'validate',
398
+ 'hasRequired',
399
+ 'getMissing',
400
+ 'isComplete',
401
+ 'sanitize',
402
+ 'mergeDefaults',
403
+ ],
404
+ rpc: '/rpc',
405
+ })
406
+ }
407
+
408
+ // POST /rpc - JSON-RPC endpoint
409
+ if (url.pathname === '/rpc' && request.method === 'POST') {
410
+ try {
411
+ const body = (await request.json()) as { method: string; args?: unknown[] }
412
+ const { method, args = [] } = body
413
+
414
+ if (!method || typeof method !== 'string') {
415
+ return Response.json({ error: 'Missing or invalid method' }, { status: 400 })
416
+ }
417
+
418
+ const service = this.getServiceCore()
419
+
420
+ // Check if method exists on service
421
+ const methodFn = (service as unknown as Record<string, unknown>)[method]
422
+ if (typeof methodFn !== 'function') {
423
+ return Response.json({ error: `Method "${method}" not found` }, { status: 404 })
424
+ }
425
+
426
+ // Call the method
427
+ const result = await (methodFn as (...args: unknown[]) => unknown).apply(service, args)
428
+ return Response.json({ result })
429
+ } catch (error) {
430
+ const message = error instanceof Error ? error.message : 'Unknown error'
431
+ return Response.json({ error: message }, { status: 500 })
432
+ }
433
+ }
434
+
435
+ // 404 for other routes
436
+ return Response.json({ error: 'Not found' }, { status: 404 })
437
+ }
438
+ }
439
+
440
+ /**
441
+ * Default export for Cloudflare Workers
442
+ */
443
+ export default PropsService
444
+
445
+ /**
446
+ * Export aliases
447
+ */
448
+ export { PropsService as PropsWorker }
449
+
450
+ // =============================================================================
451
+ // Cascade Execution - Code -> Generative -> Agentic -> Human pattern
452
+ // =============================================================================
453
+
454
+ export {
455
+ // Base cascade (non-durable)
456
+ CascadeExecutor,
457
+ createCascadeStep,
458
+ // Types
459
+ type CascadeConfig,
460
+ type CascadeResult,
461
+ type CascadeContext,
462
+ type TierContext,
463
+ type TierHandler,
464
+ type TierResult,
465
+ type CapabilityTier,
466
+ type FiveWHEvent,
467
+ type TierRetryConfig,
468
+ type SkipCondition,
469
+ type CascadeMetrics,
470
+ type CascadeStep,
471
+ // Constants
472
+ TIER_ORDER,
473
+ DEFAULT_TIER_TIMEOUTS,
474
+ // Errors
475
+ CascadeTimeoutError,
476
+ TierSkippedError,
477
+ AllTiersFailedError,
478
+ // Helpers
479
+ createCascadeContext,
480
+ recordStep,
481
+ } from './cascade.js'
482
+
483
+ // =============================================================================
484
+ // Durable Cascade - Cloudflare Workflows integration
485
+ // =============================================================================
486
+
487
+ export {
488
+ // Durable cascade executor
489
+ DurableCascadeExecutor,
490
+ createDurableCascadeStep,
491
+ // AI Gateway configuration
492
+ createAIGatewayConfig,
493
+ // Types
494
+ type DurableCascadeConfig,
495
+ type DurableCascadeTierContext,
496
+ type DurableStepConfig,
497
+ type DurableRetryConfig,
498
+ type WorkflowStep,
499
+ type AiBinding,
500
+ type HumanReviewRequest,
501
+ type AIGatewayConfig,
502
+ type CodeTierHandler,
503
+ type AiTierHandler,
504
+ type HumanTierHandler,
505
+ } from './durable-cascade.js'
506
+
507
+ // =============================================================================
508
+ // Event System - Queue-based event handling
509
+ // =============================================================================
510
+
511
+ /**
512
+ * Event System exports for Queue-based event handling
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * import { EventBridge, createQueueHandler } from 'ai-props/worker'
517
+ *
518
+ * const bridge = new EventBridge(env.MY_QUEUE)
519
+ * bridge.on('user.created', async (data) => {
520
+ * console.log('User created:', data.id)
521
+ * })
522
+ *
523
+ * export default {
524
+ * async fetch(request, env) {
525
+ * await bridge.emit('user.created', { id: '123' })
526
+ * return new Response('OK')
527
+ * },
528
+ * async queue(batch, env) {
529
+ * const handler = createQueueHandler(bridge)
530
+ * await handler.queue(batch, env)
531
+ * }
532
+ * }
533
+ * ```
534
+ */
535
+ export {
536
+ EventBridge,
537
+ createQueueHandler,
538
+ createEventBridge,
539
+ type QueuedEvent,
540
+ type EventBridgeConfig,
541
+ type EventHandler,
542
+ type EmitOptions,
543
+ type Queue,
544
+ type QueueMessage,
545
+ type MessageBatch,
546
+ type TypedEventBridge,
547
+ } from './event-bridge.js'