ai-props 2.1.3 → 2.3.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 (73) hide show
  1. package/.dev.vars +2 -0
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +2 -0
  4. package/package.json +39 -13
  5. package/src/ai.ts +12 -31
  6. package/src/cascade.ts +795 -0
  7. package/src/client.ts +440 -0
  8. package/src/durable-cascade.ts +743 -0
  9. package/src/event-bridge.ts +478 -0
  10. package/src/generate.ts +14 -12
  11. package/src/hoc.ts +15 -19
  12. package/src/hono-jsx.ts +675 -0
  13. package/src/index.ts +30 -0
  14. package/src/mdx-types.ts +169 -0
  15. package/src/mdx-utils.ts +437 -0
  16. package/src/mdx.ts +1008 -0
  17. package/src/rpc.ts +614 -0
  18. package/src/streaming.ts +618 -0
  19. package/src/validate.ts +15 -29
  20. package/src/worker.ts +547 -0
  21. package/test/cascade.test.ts +338 -0
  22. package/test/durable-cascade.test.ts +319 -0
  23. package/test/event-bridge.test.ts +351 -0
  24. package/test/generate.test.ts +6 -16
  25. package/test/mdx.test.ts +817 -0
  26. package/test/worker/capnweb-rpc.test.ts +1084 -0
  27. package/test/worker/full-flow.integration.test.ts +1463 -0
  28. package/test/worker/hono-jsx.test.ts +1258 -0
  29. package/test/worker/mdx-parsing.test.ts +1148 -0
  30. package/test/worker/setup.ts +56 -0
  31. package/test/worker.test.ts +595 -0
  32. package/tsconfig.json +2 -1
  33. package/vitest.config.js +6 -0
  34. package/vitest.config.ts +15 -1
  35. package/vitest.workers.config.ts +58 -0
  36. package/wrangler.jsonc +27 -0
  37. package/.turbo/turbo-build.log +0 -4
  38. package/LICENSE +0 -21
  39. package/dist/ai.d.ts +0 -125
  40. package/dist/ai.d.ts.map +0 -1
  41. package/dist/ai.js +0 -199
  42. package/dist/ai.js.map +0 -1
  43. package/dist/cache.d.ts +0 -66
  44. package/dist/cache.d.ts.map +0 -1
  45. package/dist/cache.js +0 -183
  46. package/dist/cache.js.map +0 -1
  47. package/dist/generate.d.ts +0 -69
  48. package/dist/generate.d.ts.map +0 -1
  49. package/dist/generate.js +0 -221
  50. package/dist/generate.js.map +0 -1
  51. package/dist/hoc.d.ts +0 -164
  52. package/dist/hoc.d.ts.map +0 -1
  53. package/dist/hoc.js +0 -236
  54. package/dist/hoc.js.map +0 -1
  55. package/dist/index.d.ts +0 -15
  56. package/dist/index.d.ts.map +0 -1
  57. package/dist/index.js +0 -21
  58. package/dist/index.js.map +0 -1
  59. package/dist/types.d.ts +0 -152
  60. package/dist/types.d.ts.map +0 -1
  61. package/dist/types.js +0 -7
  62. package/dist/types.js.map +0 -1
  63. package/dist/validate.d.ts +0 -58
  64. package/dist/validate.d.ts.map +0 -1
  65. package/dist/validate.js +0 -253
  66. package/dist/validate.js.map +0 -1
  67. package/src/ai.js +0 -198
  68. package/src/cache.js +0 -182
  69. package/src/generate.js +0 -220
  70. package/src/hoc.js +0 -235
  71. package/src/index.js +0 -20
  72. package/src/types.js +0 -6
  73. package/src/validate.js +0 -252
@@ -0,0 +1,675 @@
1
+ /**
2
+ * hono/jsx integration for AI-powered props with hydration and streaming
3
+ *
4
+ * This module provides:
5
+ * - Hydration data collection during server render
6
+ * - Streaming render support with hono/jsx
7
+ * - AI-powered component prop generation
8
+ * - Context-aware rendering with Suspense support
9
+ *
10
+ * Bead: aip-fxpy (tests), aip-z57t (implementation)
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+
15
+ import { generateProps, mergeWithGenerated } from './generate.js'
16
+
17
+ // ============================================================================
18
+ // Types
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Hydration data structure collected during render
23
+ */
24
+ export interface HydrationData {
25
+ /** Map of component ID to props used during render */
26
+ components: Map<string, Record<string, unknown>>
27
+ /** Component hierarchy tree */
28
+ tree: HydrationNode[]
29
+ /** Serialize to JSON string */
30
+ toJSON(): string
31
+ }
32
+
33
+ /**
34
+ * Node in the component hydration tree
35
+ */
36
+ export interface HydrationNode {
37
+ id: string
38
+ component: string
39
+ props: Record<string, unknown>
40
+ children: HydrationNode[]
41
+ }
42
+
43
+ /**
44
+ * Context for hydration tracking
45
+ */
46
+ export interface HydrationContext {
47
+ /** Register a component render with props */
48
+ register(componentName: string, props: Record<string, unknown>): string
49
+ /** Get collected hydration data */
50
+ getData(): HydrationData
51
+ /** Clear collected data */
52
+ clear(): void
53
+ }
54
+
55
+ /**
56
+ * Options for streaming render
57
+ */
58
+ export interface StreamingOptions {
59
+ /** Include hydration data in stream */
60
+ includeHydration?: boolean
61
+ /** Suspense configuration */
62
+ suspense?: {
63
+ fallback: string
64
+ }
65
+ /** Error handler */
66
+ onError?: (error: Error) => string
67
+ /** Enable progressive enhancement */
68
+ progressive?: boolean
69
+ /** Custom headers for response */
70
+ headers?: Record<string, string>
71
+ /** Enable streaming mode */
72
+ streaming?: boolean
73
+ }
74
+
75
+ /**
76
+ * Options for streaming renderer
77
+ */
78
+ export interface StreamingRendererOptions {
79
+ /** DOCTYPE to prepend */
80
+ doctype?: string
81
+ /** Shell wrapper function */
82
+ shell?: (content: string, hydration?: string) => string
83
+ /** Include hydration data */
84
+ includeHydration?: boolean
85
+ }
86
+
87
+ /**
88
+ * Props for AI component creation
89
+ */
90
+ export interface AIComponentProps<P = Record<string, unknown>> {
91
+ /** Component name */
92
+ name: string
93
+ /** Schema for AI prop generation */
94
+ schema: Record<string, string>
95
+ /** Render function */
96
+ render: (props: P) => string | Promise<string>
97
+ /** Fallback props on error */
98
+ fallback?: Partial<P>
99
+ /** Enable progressive enhancement */
100
+ progressive?: boolean
101
+ }
102
+
103
+ /**
104
+ * Props for withAIProps wrapper
105
+ */
106
+ export interface WithAIPropsOptions {
107
+ /** Schema for AI prop generation */
108
+ schema: Record<string, string>
109
+ /** Fallback props on error */
110
+ fallback?: Record<string, unknown>
111
+ }
112
+
113
+ /**
114
+ * Props for AIPropsProvider
115
+ */
116
+ export interface AIPropsProviderProps {
117
+ /** AI props configuration */
118
+ config: {
119
+ model?: string
120
+ cache?: boolean
121
+ system?: string
122
+ }
123
+ /** Children to render */
124
+ children: unknown
125
+ }
126
+
127
+ /**
128
+ * Component type with schema attached
129
+ */
130
+ export interface AIComponentFunction<P = Record<string, unknown>> {
131
+ (props: Partial<P> & { context?: Record<string, unknown> }): Promise<string>
132
+ schema: Record<string, string>
133
+ displayName?: string
134
+ }
135
+
136
+ // ============================================================================
137
+ // Global hydration context (for useHydration hook simulation)
138
+ // ============================================================================
139
+
140
+ let globalHydrationContext: HydrationContext | null = null
141
+
142
+ // ============================================================================
143
+ // Hydration Data Collection
144
+ // ============================================================================
145
+
146
+ /**
147
+ * Create hydration data with the toJSON method
148
+ */
149
+ function createHydrationData(
150
+ components: Map<string, Record<string, unknown>>,
151
+ tree: HydrationNode[]
152
+ ): HydrationData {
153
+ return {
154
+ components,
155
+ tree,
156
+ toJSON() {
157
+ return serializeHydrationData(this)
158
+ },
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Collect hydration data from a component render
164
+ *
165
+ * @param component - Component function to render
166
+ * @param props - Props to pass to component
167
+ * @returns Hydration data collected during render
168
+ */
169
+ export async function collectHydrationData<P>(
170
+ component: (props: P) => string | Promise<string>,
171
+ props: P
172
+ ): Promise<HydrationData> {
173
+ // Create a hydration context
174
+ const ctx = createHydrationContext()
175
+
176
+ // Store global context for nested components
177
+ const prevContext = globalHydrationContext
178
+ globalHydrationContext = ctx
179
+
180
+ try {
181
+ // Get component name
182
+ const componentName = component.name || 'Anonymous'
183
+
184
+ // Register the component
185
+ ctx.register(componentName, props as Record<string, unknown>)
186
+
187
+ // Render the component (this might trigger nested registrations)
188
+ await component(props)
189
+
190
+ // Return collected data
191
+ return ctx.getData()
192
+ } finally {
193
+ // Restore previous context
194
+ globalHydrationContext = prevContext
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Create a hydration context for tracking component renders
200
+ *
201
+ * @returns New hydration context
202
+ */
203
+ export function createHydrationContext(): HydrationContext {
204
+ const components = new Map<string, Record<string, unknown>>()
205
+ const tree: HydrationNode[] = []
206
+ let idCounter = 0
207
+
208
+ return {
209
+ register(componentName: string, props: Record<string, unknown>): string {
210
+ const id = `${componentName}-${idCounter++}`
211
+ components.set(componentName, props)
212
+
213
+ const node: HydrationNode = {
214
+ id,
215
+ component: componentName,
216
+ props,
217
+ children: [],
218
+ }
219
+ tree.push(node)
220
+
221
+ return id
222
+ },
223
+
224
+ getData(): HydrationData {
225
+ return createHydrationData(new Map(components), [...tree])
226
+ },
227
+
228
+ clear(): void {
229
+ components.clear()
230
+ tree.length = 0
231
+ idCounter = 0
232
+ },
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Serialize hydration data to JSON string
238
+ *
239
+ * @param data - Hydration data to serialize
240
+ * @returns JSON string safe for script embedding
241
+ */
242
+ export function serializeHydrationData(data: HydrationData): string {
243
+ // Convert Map to object for serialization
244
+ const componentsObj: Record<string, Record<string, unknown>> = {}
245
+
246
+ // Use a WeakSet to detect circular references
247
+ const seen = new WeakSet()
248
+
249
+ function sanitizeValue(value: unknown): unknown {
250
+ if (value === null || value === undefined) {
251
+ return value
252
+ }
253
+
254
+ if (typeof value === 'object') {
255
+ if (seen.has(value as object)) {
256
+ return '[Circular]'
257
+ }
258
+ seen.add(value as object)
259
+
260
+ if (Array.isArray(value)) {
261
+ return value.map(sanitizeValue)
262
+ }
263
+
264
+ const result: Record<string, unknown> = {}
265
+ for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
266
+ result[k] = sanitizeValue(v)
267
+ }
268
+ return result
269
+ }
270
+
271
+ return value
272
+ }
273
+
274
+ for (const [key, value] of data.components) {
275
+ componentsObj[key] = sanitizeValue(value) as Record<string, unknown>
276
+ }
277
+
278
+ const serializable = {
279
+ components: componentsObj,
280
+ tree: data.tree.map((node) => ({
281
+ id: node.id,
282
+ component: node.component,
283
+ props: sanitizeValue(node.props),
284
+ children: node.children,
285
+ })),
286
+ }
287
+
288
+ let json = JSON.stringify(serializable)
289
+
290
+ // Escape script tags to prevent XSS
291
+ json = json.replace(/<script/gi, '\\u003cscript')
292
+ json = json.replace(/<\/script/gi, '\\u003c/script')
293
+
294
+ return json
295
+ }
296
+
297
+ /**
298
+ * Provider component that enables hydration tracking for children
299
+ *
300
+ * @param props - Provider props with context and children
301
+ * @returns Rendered output with hydration tracking
302
+ */
303
+ export function HydrationProvider(props: {
304
+ context: HydrationContext
305
+ children: unknown
306
+ }): unknown {
307
+ // Store context globally for nested components
308
+ const prevContext = globalHydrationContext
309
+ globalHydrationContext = props.context
310
+
311
+ try {
312
+ // Return children - in a real JSX environment this would render them
313
+ return props.children
314
+ } finally {
315
+ // Note: In real JSX, we'd restore on unmount, not here
316
+ // For our purposes, we keep it set for the duration
317
+ globalHydrationContext = prevContext
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Hook to access hydration context from within a component
323
+ *
324
+ * @returns Current hydration context
325
+ */
326
+ export function useHydration(): HydrationContext {
327
+ if (!globalHydrationContext) {
328
+ // Return a no-op context if not in a HydrationProvider
329
+ return createHydrationContext()
330
+ }
331
+ return globalHydrationContext
332
+ }
333
+
334
+ // ============================================================================
335
+ // Streaming Render
336
+ // ============================================================================
337
+
338
+ /**
339
+ * Render a component to a ReadableStream
340
+ *
341
+ * @param component - Component function to render
342
+ * @param props - Props to pass to component
343
+ * @param options - Streaming options
344
+ * @returns ReadableStream of rendered HTML
345
+ */
346
+ export async function renderToReadableStream<P>(
347
+ component: (props: P) => string | Promise<string>,
348
+ props: P,
349
+ options?: StreamingOptions
350
+ ): Promise<ReadableStream<Uint8Array>> {
351
+ const encoder = new TextEncoder()
352
+
353
+ return new ReadableStream<Uint8Array>({
354
+ async start(controller) {
355
+ try {
356
+ // Create hydration context if needed
357
+ const ctx = options?.includeHydration ? createHydrationContext() : null
358
+
359
+ if (ctx) {
360
+ globalHydrationContext = ctx
361
+ }
362
+
363
+ // Render the component
364
+ let content: string
365
+ try {
366
+ content = await component(props)
367
+ } catch (error) {
368
+ if (options?.onError && error instanceof Error) {
369
+ content = options.onError(error)
370
+ } else {
371
+ throw error
372
+ }
373
+ }
374
+
375
+ // Enqueue the content in chunks for streaming behavior
376
+ const chunkSize = 1024
377
+ for (let i = 0; i < content.length; i += chunkSize) {
378
+ const chunk = content.slice(i, i + chunkSize)
379
+ controller.enqueue(encoder.encode(chunk))
380
+ }
381
+
382
+ // Add hydration script if requested
383
+ if (options?.includeHydration && ctx) {
384
+ const componentName = component.name || 'Anonymous'
385
+ ctx.register(componentName, props as Record<string, unknown>)
386
+ const hydrationData = ctx.getData()
387
+ const hydrationScript = `<script>window.__HYDRATION_DATA__=${serializeHydrationData(
388
+ hydrationData
389
+ )}</script>`
390
+ controller.enqueue(encoder.encode(hydrationScript))
391
+ }
392
+
393
+ controller.close()
394
+ } catch (error) {
395
+ controller.error(error)
396
+ } finally {
397
+ globalHydrationContext = null
398
+ }
399
+ },
400
+ })
401
+ }
402
+
403
+ /**
404
+ * Create a streaming Response from a component
405
+ *
406
+ * @param component - Component function to render
407
+ * @param props - Props to pass to component
408
+ * @param options - Streaming options
409
+ * @returns Response with streaming body
410
+ */
411
+ export async function streamJSXResponse<P>(
412
+ component: (props: P) => string | Promise<string>,
413
+ props: P,
414
+ options?: StreamingOptions
415
+ ): Promise<Response> {
416
+ const stream = await renderToReadableStream(component, props, options)
417
+
418
+ const headers = new Headers({
419
+ 'Content-Type': 'text/html; charset=utf-8',
420
+ ...options?.headers,
421
+ })
422
+
423
+ // Don't set Content-Length for streaming responses
424
+ if (options?.streaming) {
425
+ // Transfer-Encoding is typically set automatically by the runtime
426
+ }
427
+
428
+ return new Response(stream, {
429
+ status: 200,
430
+ headers,
431
+ })
432
+ }
433
+
434
+ /**
435
+ * Create a reusable streaming renderer with configuration
436
+ *
437
+ * @param options - Renderer options
438
+ * @returns Streaming renderer instance
439
+ */
440
+ export function createStreamingRenderer(options: StreamingRendererOptions): {
441
+ render: <P>(
442
+ component: (props: P) => string | Promise<string>,
443
+ props: P
444
+ ) => Promise<ReadableStream<Uint8Array>>
445
+ } {
446
+ return {
447
+ async render<P>(
448
+ component: (props: P) => string | Promise<string>,
449
+ props: P
450
+ ): Promise<ReadableStream<Uint8Array>> {
451
+ const encoder = new TextEncoder()
452
+
453
+ return new ReadableStream<Uint8Array>({
454
+ async start(controller) {
455
+ try {
456
+ // Create hydration context
457
+ const ctx = options.includeHydration ? createHydrationContext() : null
458
+
459
+ if (ctx) {
460
+ globalHydrationContext = ctx
461
+ }
462
+
463
+ // Render the component
464
+ const content = await component(props)
465
+
466
+ // Register for hydration data
467
+ if (ctx) {
468
+ const componentName = component.name || 'Anonymous'
469
+ ctx.register(componentName, props as Record<string, unknown>)
470
+ }
471
+
472
+ // Get hydration data
473
+ let hydrationJson = ''
474
+ if (options.includeHydration && ctx) {
475
+ hydrationJson = serializeHydrationData(ctx.getData())
476
+ }
477
+
478
+ // Apply shell wrapper if provided
479
+ let output: string
480
+ if (options.shell) {
481
+ // When using shell, pass hydration data with __HYDRATION_DATA__ prefix
482
+ // so the shell can embed it directly in a script tag
483
+ const hydrationScript = hydrationJson
484
+ ? `window.__HYDRATION_DATA__=${hydrationJson}`
485
+ : ''
486
+ output = options.shell(content, hydrationScript)
487
+ } else {
488
+ output = content
489
+ if (options.includeHydration && hydrationJson) {
490
+ output += `<script>window.__HYDRATION_DATA__=${hydrationJson}</script>`
491
+ }
492
+ }
493
+
494
+ // Prepend doctype if provided
495
+ if (options.doctype) {
496
+ output = options.doctype + '\n' + output
497
+ }
498
+
499
+ // Stream in chunks
500
+ const chunkSize = 1024
501
+ for (let i = 0; i < output.length; i += chunkSize) {
502
+ const chunk = output.slice(i, i + chunkSize)
503
+ controller.enqueue(encoder.encode(chunk))
504
+ }
505
+
506
+ controller.close()
507
+ } catch (error) {
508
+ controller.error(error)
509
+ } finally {
510
+ globalHydrationContext = null
511
+ }
512
+ },
513
+ })
514
+ },
515
+ }
516
+ }
517
+
518
+ // ============================================================================
519
+ // AI Component Creation
520
+ // ============================================================================
521
+
522
+ /**
523
+ * Create a component with AI-powered prop generation
524
+ *
525
+ * @param options - Component options including schema and render function
526
+ * @returns AI-enhanced component function
527
+ */
528
+ export function createAIComponent<P extends Record<string, unknown>>(
529
+ options: AIComponentProps<P>
530
+ ): AIComponentFunction<P> {
531
+ const { name, schema, render, fallback, progressive } = options
532
+
533
+ const aiComponent = async (
534
+ props: Partial<P> & { context?: Record<string, unknown> }
535
+ ): Promise<string> => {
536
+ const { context, ...partialProps } = props
537
+
538
+ // Check which props are missing
539
+ const schemaKeys = Object.keys(schema)
540
+ const providedKeys = Object.keys(partialProps)
541
+ const missingKeys = schemaKeys.filter((k) => !providedKeys.includes(k))
542
+
543
+ let finalProps: P
544
+
545
+ if (missingKeys.length === 0) {
546
+ // All props provided, no generation needed
547
+ finalProps = partialProps as P
548
+ } else {
549
+ // Generate missing props
550
+ try {
551
+ // Build schema for only missing props
552
+ const missingSchema: Record<string, string> = {}
553
+ for (const key of missingKeys) {
554
+ const schemaValue = schema[key]
555
+ if (schemaValue !== undefined) {
556
+ missingSchema[key] = schemaValue
557
+ }
558
+ }
559
+
560
+ const result = await generateProps<Partial<P>>({
561
+ schema: missingSchema,
562
+ context: context || partialProps,
563
+ })
564
+
565
+ finalProps = {
566
+ ...result.props,
567
+ ...partialProps,
568
+ } as P
569
+ } catch (error) {
570
+ // Use fallback on error
571
+ if (fallback) {
572
+ finalProps = {
573
+ ...fallback,
574
+ ...partialProps,
575
+ } as P
576
+ } else {
577
+ throw error
578
+ }
579
+ }
580
+ }
581
+
582
+ // Render the component
583
+ return render(finalProps)
584
+ }
585
+
586
+ // Attach schema and metadata
587
+ aiComponent.schema = schema
588
+ aiComponent.displayName = `AI(${name})`
589
+
590
+ return aiComponent
591
+ }
592
+
593
+ /**
594
+ * Wrap an existing component with AI prop generation
595
+ *
596
+ * @param component - Component function to wrap
597
+ * @param options - AI props options
598
+ * @returns Wrapped component with AI props
599
+ */
600
+ export function withAIProps<P extends Record<string, unknown>>(
601
+ component: (props: P) => string | Promise<string>,
602
+ options: WithAIPropsOptions
603
+ ): AIComponentFunction<P> {
604
+ const { schema, fallback } = options
605
+
606
+ const wrappedComponent = async (
607
+ props: Partial<P> & { context?: Record<string, unknown> }
608
+ ): Promise<string> => {
609
+ const { context, ...partialProps } = props
610
+
611
+ // Check which props are missing
612
+ const schemaKeys = Object.keys(schema)
613
+ const providedKeys = Object.keys(partialProps)
614
+ const missingKeys = schemaKeys.filter((k) => !providedKeys.includes(k))
615
+
616
+ let finalProps: P
617
+
618
+ if (missingKeys.length === 0) {
619
+ // All props provided
620
+ finalProps = partialProps as P
621
+ } else {
622
+ // Generate missing props
623
+ try {
624
+ const missingSchema: Record<string, string> = {}
625
+ for (const key of missingKeys) {
626
+ const schemaValue = schema[key]
627
+ if (schemaValue !== undefined) {
628
+ missingSchema[key] = schemaValue
629
+ }
630
+ }
631
+
632
+ const result = await generateProps<Partial<P>>({
633
+ schema: missingSchema,
634
+ context: context || partialProps,
635
+ })
636
+
637
+ finalProps = {
638
+ ...result.props,
639
+ ...partialProps,
640
+ } as P
641
+ } catch (error) {
642
+ if (fallback) {
643
+ finalProps = {
644
+ ...fallback,
645
+ ...partialProps,
646
+ } as P
647
+ } else {
648
+ throw error
649
+ }
650
+ }
651
+ }
652
+
653
+ return component(finalProps)
654
+ }
655
+
656
+ // Preserve displayName
657
+ const originalName =
658
+ (component as { displayName?: string }).displayName || component.name || 'Component'
659
+ wrappedComponent.schema = schema
660
+ wrappedComponent.displayName = `withAIProps(${originalName})`
661
+
662
+ return wrappedComponent
663
+ }
664
+
665
+ /**
666
+ * Provider component for AI props configuration
667
+ *
668
+ * @param props - Provider props with config and children
669
+ * @returns Rendered output with AI props context
670
+ */
671
+ export function AIPropsProvider(props: AIPropsProviderProps): unknown {
672
+ // Store configuration globally (in a real implementation, use React Context)
673
+ // For now, we just pass through children
674
+ return props.children
675
+ }
package/src/index.ts CHANGED
@@ -64,3 +64,33 @@ export {
64
64
  createValidator,
65
65
  assertValidProps,
66
66
  } from './validate.js'
67
+
68
+ // Export MDX utilities
69
+ export {
70
+ parseMDX,
71
+ extractComponentSchemas,
72
+ renderMDXWithProps,
73
+ streamMDXWithProps,
74
+ createMDXPropsGenerator,
75
+ compileMDX,
76
+ clearMDXCache,
77
+ getMDXCacheSize,
78
+ configureMDXCache,
79
+ getMDXCacheStats,
80
+ invalidateMDXCacheByTag,
81
+ cleanupMDXCache,
82
+ type ParsedMDX,
83
+ type ComponentSchemas,
84
+ type MDXPropsGeneratorOptions,
85
+ type MDXPropsGenerator,
86
+ type RenderMDXOptions,
87
+ type StreamMDXOptions,
88
+ type CompileMDXOptions,
89
+ type CompiledMDXFunction,
90
+ type MDXCacheEntry,
91
+ type MDXParseError,
92
+ type CacheInvalidationStrategy,
93
+ type MDXCacheOptions,
94
+ type MDXCacheStats,
95
+ type ParseMDXOptions,
96
+ } from './mdx.js'