ai-props 0.1.2 → 2.0.2
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/.turbo/turbo-build.log +5 -0
- package/CHANGELOG.md +15 -0
- package/README.md +345 -352
- package/dist/ai.d.ts +125 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +199 -0
- package/dist/ai.js.map +1 -0
- package/dist/cache.d.ts +66 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +183 -0
- package/dist/cache.js.map +1 -0
- package/dist/generate.d.ts +69 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +221 -0
- package/dist/generate.js.map +1 -0
- package/dist/hoc.d.ts +164 -0
- package/dist/hoc.d.ts.map +1 -0
- package/dist/hoc.js +236 -0
- package/dist/hoc.js.map +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +58 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +253 -0
- package/dist/validate.js.map +1 -0
- package/package.json +16 -63
- package/src/ai.ts +264 -0
- package/src/cache.ts +216 -0
- package/src/generate.ts +276 -0
- package/src/hoc.ts +309 -0
- package/src/index.ts +66 -0
- package/src/types.ts +167 -0
- package/src/validate.ts +333 -0
- package/test/ai.test.ts +327 -0
- package/test/cache.test.ts +236 -0
- package/test/generate.test.ts +406 -0
- package/test/hoc.test.ts +411 -0
- package/test/validate.test.ts +324 -0
- package/tsconfig.json +9 -0
- package/vitest.config.ts +15 -0
- package/LICENSE +0 -21
- package/dist/AI.d.ts +0 -27
- package/dist/AI.d.ts.map +0 -1
- package/dist/AI.test.d.ts +0 -2
- package/dist/AI.test.d.ts.map +0 -1
- package/dist/ai-props.es.js +0 -3697
- package/dist/ai-props.umd.js +0 -30
- package/dist/components/ErrorBoundary.d.ts +0 -17
- package/dist/components/ErrorBoundary.d.ts.map +0 -1
- package/dist/examples/BlogList.d.ts +0 -2
- package/dist/examples/BlogList.d.ts.map +0 -1
- package/dist/examples/BlogList.fixture.d.ts +0 -5
- package/dist/examples/BlogList.fixture.d.ts.map +0 -1
- package/dist/examples/HeroSection.d.ts +0 -2
- package/dist/examples/HeroSection.d.ts.map +0 -1
- package/dist/examples/HeroSection.fixture.d.ts +0 -5
- package/dist/examples/HeroSection.fixture.d.ts.map +0 -1
- package/dist/test/setup.d.ts +0 -2
- package/dist/test/setup.d.ts.map +0 -1
- package/dist/utils/schema.d.ts +0 -28
- package/dist/utils/schema.d.ts.map +0 -1
- package/dist/utils/styles.d.ts +0 -3
- package/dist/utils/styles.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# ai-props
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
3
|
+
AI-powered props primitives for intelligent component properties.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`ai-props` provides utilities for automatically generating component props using AI based on schema definitions. It's designed to work seamlessly with React components, Next.js, and other frameworks.
|
|
7
8
|
|
|
8
9
|
## Installation
|
|
9
10
|
|
|
@@ -11,412 +12,404 @@ A React component package that provides an AI component for generating and sprea
|
|
|
11
12
|
npm install ai-props
|
|
12
13
|
```
|
|
13
14
|
|
|
14
|
-
##
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
<AI
|
|
35
|
-
model={model}
|
|
36
|
-
schema={schema}
|
|
37
|
-
prompt='Generate content'
|
|
38
|
-
/>
|
|
39
|
-
|
|
40
|
-
### Streaming Support
|
|
41
|
-
|
|
42
|
-
The AI component supports real-time streaming of generated content, providing a more interactive user experience:
|
|
43
|
-
|
|
44
|
-
```tsx
|
|
45
|
-
<AI
|
|
46
|
-
model='gpt-4'
|
|
47
|
-
stream={true}
|
|
48
|
-
schema={{
|
|
49
|
-
title: 'string',
|
|
50
|
-
content: 'string'
|
|
51
|
-
}}
|
|
52
|
-
prompt='Generate an article about React'
|
|
53
|
-
>
|
|
54
|
-
{(props, { isStreaming }) => (
|
|
55
|
-
<article className={isStreaming ? 'animate-pulse' : ''}>
|
|
56
|
-
<h1>{props.title}</h1>
|
|
57
|
-
<div>{props.content}</div>
|
|
58
|
-
{isStreaming && (
|
|
59
|
-
<div className='text-gray-500'>Generating content...</div>
|
|
60
|
-
)}
|
|
61
|
-
</article>
|
|
62
|
-
)}
|
|
63
|
-
</AI>
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { AI, generateProps } from 'ai-props'
|
|
19
|
+
|
|
20
|
+
// Define an AI-powered component schema
|
|
21
|
+
const UserCard = AI({
|
|
22
|
+
schema: {
|
|
23
|
+
name: 'User name',
|
|
24
|
+
bio: 'User biography',
|
|
25
|
+
avatar: 'Avatar URL',
|
|
26
|
+
},
|
|
27
|
+
defaults: {
|
|
28
|
+
avatar: '/default-avatar.png',
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
// Generate props with AI
|
|
33
|
+
const props = await UserCard({ name: 'John' })
|
|
34
|
+
// { name: 'John', bio: 'AI-generated bio...', avatar: '/default-avatar.png' }
|
|
64
35
|
```
|
|
65
36
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/>
|
|
37
|
+
## Core Features
|
|
38
|
+
|
|
39
|
+
### AI() Wrapper
|
|
40
|
+
|
|
41
|
+
Create AI-powered component wrappers that automatically fill in missing props:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { AI } from 'ai-props'
|
|
45
|
+
|
|
46
|
+
const ProductCard = AI({
|
|
47
|
+
schema: {
|
|
48
|
+
title: 'Product title',
|
|
49
|
+
description: 'Product description',
|
|
50
|
+
price: 'Price (number)',
|
|
51
|
+
},
|
|
52
|
+
required: ['price'], // Required props won't be generated
|
|
53
|
+
exclude: ['internal'], // Exclude props from generation
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// Use the component
|
|
57
|
+
const props = await ProductCard({ price: 99 })
|
|
88
58
|
```
|
|
89
59
|
|
|
90
|
-
|
|
91
|
-
- Accept the same parameters as the AI provider
|
|
92
|
-
- Return compatible streaming or non-streaming responses
|
|
93
|
-
- Handle authentication and rate limiting
|
|
94
|
-
- Implement proper error handling
|
|
60
|
+
### generateProps()
|
|
95
61
|
|
|
96
|
-
|
|
97
|
-
- Keep API keys secure on your server
|
|
98
|
-
- Add custom request validation
|
|
99
|
-
- Implement usage tracking
|
|
100
|
-
- Control model access and costs
|
|
101
|
-
- Add custom error handling
|
|
62
|
+
Low-level function for direct prop generation:
|
|
102
63
|
|
|
103
|
-
Example API endpoint implementation:
|
|
104
64
|
```typescript
|
|
105
|
-
|
|
106
|
-
import { OpenAIStream } from 'ai'
|
|
107
|
-
|
|
108
|
-
export async function POST(req: Request) {
|
|
109
|
-
const { prompt, schema, stream } = await req.json()
|
|
110
|
-
|
|
111
|
-
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
112
|
-
method: 'POST',
|
|
113
|
-
headers: {
|
|
114
|
-
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
|
|
115
|
-
'Content-Type': 'application/json',
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify({
|
|
118
|
-
model: 'gpt-4',
|
|
119
|
-
messages: [{ role: 'user', content: prompt }],
|
|
120
|
-
stream: stream,
|
|
121
|
-
}),
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
if (stream) {
|
|
125
|
-
const stream = OpenAIStream(response)
|
|
126
|
-
return new Response(stream)
|
|
127
|
-
}
|
|
65
|
+
import { generateProps } from 'ai-props'
|
|
128
66
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
67
|
+
const result = await generateProps({
|
|
68
|
+
schema: {
|
|
69
|
+
title: 'SEO-optimized page title',
|
|
70
|
+
description: 'Meta description',
|
|
71
|
+
keywords: ['Relevant keywords'],
|
|
72
|
+
},
|
|
73
|
+
context: { topic: 'AI-powered applications' },
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
console.log(result.props) // Generated props
|
|
77
|
+
console.log(result.cached) // Whether result came from cache
|
|
78
|
+
console.log(result.metadata) // Model info, duration, etc.
|
|
132
79
|
```
|
|
133
80
|
|
|
134
|
-
###
|
|
81
|
+
### createAIComponent()
|
|
135
82
|
|
|
136
|
-
|
|
83
|
+
Create typed AI components:
|
|
137
84
|
|
|
138
|
-
```
|
|
139
|
-
import {
|
|
85
|
+
```typescript
|
|
86
|
+
import { createAIComponent } from 'ai-props'
|
|
140
87
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
productType: 'App | API | Marketplace | Platform | Packaged Service | Professional Service | Website',
|
|
146
|
-
profile: {
|
|
147
|
-
customer: 'ideal customer profile in 3-5 words',
|
|
148
|
-
solution: 'describe the offer in 4-10 words'
|
|
149
|
-
},
|
|
150
|
-
description: 'website meta description',
|
|
151
|
-
tags: ['SEO-optimized meta tags']
|
|
152
|
-
}}
|
|
153
|
-
prompt='Generate product details'
|
|
154
|
-
>
|
|
155
|
-
{(props) => (
|
|
156
|
-
<article>
|
|
157
|
-
<h1>{props.productType}</h1>
|
|
158
|
-
<div>
|
|
159
|
-
<p>Customer: {props.profile.customer}</p>
|
|
160
|
-
<p>Solution: {props.profile.solution}</p>
|
|
161
|
-
</div>
|
|
162
|
-
<p>{props.description}</p>
|
|
163
|
-
<ul>
|
|
164
|
-
{props.tags.map((tag, i) => (
|
|
165
|
-
<li key={i}>{tag}</li>
|
|
166
|
-
))}
|
|
167
|
-
</ul>
|
|
168
|
-
</article>
|
|
169
|
-
)}
|
|
170
|
-
</AI>
|
|
171
|
-
)
|
|
88
|
+
interface ProductProps {
|
|
89
|
+
title: string
|
|
90
|
+
price: number
|
|
91
|
+
description: string
|
|
172
92
|
}
|
|
93
|
+
|
|
94
|
+
const ProductCard = createAIComponent<ProductProps>({
|
|
95
|
+
schema: {
|
|
96
|
+
title: 'Product title',
|
|
97
|
+
price: 'Price (number)',
|
|
98
|
+
description: 'Product description',
|
|
99
|
+
},
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const props = await ProductCard({})
|
|
103
|
+
// props is typed as ProductProps
|
|
173
104
|
```
|
|
174
105
|
|
|
175
|
-
|
|
176
|
-
- Pipe-separated strings (`'Option1 | Option2 | Option3'`) which are automatically converted to enums
|
|
177
|
-
- Nested objects with type descriptions
|
|
178
|
-
- Array types with description hints
|
|
106
|
+
### createComponentFactory()
|
|
179
107
|
|
|
180
|
-
|
|
108
|
+
Create a factory for generating multiple instances:
|
|
181
109
|
|
|
182
|
-
|
|
110
|
+
```typescript
|
|
111
|
+
import { createComponentFactory } from 'ai-props'
|
|
183
112
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
113
|
+
const factory = createComponentFactory({
|
|
114
|
+
schema: {
|
|
115
|
+
name: 'Product name',
|
|
116
|
+
price: 'Price (number)',
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// Generate a single instance
|
|
121
|
+
const product = await factory.generate({ category: 'electronics' })
|
|
122
|
+
|
|
123
|
+
// Generate multiple instances
|
|
124
|
+
const products = await factory.generateMany([
|
|
125
|
+
{ category: 'electronics' },
|
|
126
|
+
{ category: 'clothing' },
|
|
127
|
+
])
|
|
128
|
+
|
|
129
|
+
// Generate with overrides
|
|
130
|
+
const custom = await factory.generateWith(
|
|
131
|
+
{ category: 'tech' },
|
|
132
|
+
{ price: 99 }
|
|
133
|
+
)
|
|
134
|
+
```
|
|
187
135
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
136
|
+
### composeAIComponents()
|
|
137
|
+
|
|
138
|
+
Compose multiple schemas together:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { composeAIComponents } from 'ai-props'
|
|
142
|
+
|
|
143
|
+
const FullProfile = composeAIComponents({
|
|
144
|
+
user: {
|
|
145
|
+
schema: { name: 'User name', bio: 'Biography' },
|
|
146
|
+
},
|
|
147
|
+
settings: {
|
|
148
|
+
schema: { theme: 'Theme preference', notifications: 'Notification pref' },
|
|
149
|
+
},
|
|
192
150
|
})
|
|
193
151
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
schema={schema}
|
|
199
|
-
prompt='Generate a title and description for a blog post about React'
|
|
200
|
-
>
|
|
201
|
-
{(props) => (
|
|
202
|
-
<article>
|
|
203
|
-
<h1>{props.title}</h1>
|
|
204
|
-
<p>{props.description}</p>
|
|
205
|
-
</article>
|
|
206
|
-
)}
|
|
207
|
-
</AI>
|
|
208
|
-
)
|
|
209
|
-
}
|
|
152
|
+
const profile = await FullProfile({
|
|
153
|
+
user: { name: 'John' },
|
|
154
|
+
settings: {},
|
|
155
|
+
})
|
|
210
156
|
```
|
|
211
157
|
|
|
212
|
-
##
|
|
158
|
+
## HOC Utilities
|
|
159
|
+
|
|
160
|
+
### createPropsEnhancer()
|
|
213
161
|
|
|
214
|
-
|
|
162
|
+
Create a props enhancer for any component system:
|
|
215
163
|
|
|
216
164
|
```typescript
|
|
217
|
-
import {
|
|
218
|
-
|
|
165
|
+
import { createPropsEnhancer } from 'ai-props'
|
|
166
|
+
|
|
167
|
+
const enhancer = createPropsEnhancer({
|
|
168
|
+
schema: {
|
|
169
|
+
title: 'Page title',
|
|
170
|
+
description: 'Page description',
|
|
171
|
+
},
|
|
172
|
+
defaults: { title: 'Default Title' },
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
const props = await enhancer({ description: 'My page' })
|
|
219
176
|
```
|
|
220
177
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
- `experimental_telemetry`: Optional telemetry configuration
|
|
241
|
-
- `experimental_providerMetadata`: Additional provider-specific metadata
|
|
242
|
-
|
|
243
|
-
### Array Output Mode
|
|
244
|
-
|
|
245
|
-
The `AI` component supports generating and rendering arrays of items using the `output='array'` prop. When using array output mode, you can also enable CSS Grid layout with the `cols` prop:
|
|
246
|
-
|
|
247
|
-
```tsx
|
|
248
|
-
<AI
|
|
249
|
-
schema={blogSchema}
|
|
250
|
-
prompt='Generate 6 blog post previews'
|
|
251
|
-
output='array'
|
|
252
|
-
cols={3}
|
|
253
|
-
gap='2rem'
|
|
254
|
-
className='grid-container'
|
|
255
|
-
itemClassName='grid-item'
|
|
256
|
-
>
|
|
257
|
-
{(props) => (
|
|
258
|
-
<article>{/* Item content */}</article>
|
|
259
|
-
)}
|
|
260
|
-
</AI>
|
|
178
|
+
### createAsyncPropsProvider()
|
|
179
|
+
|
|
180
|
+
Create an async props provider for SSR:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { createAsyncPropsProvider } from 'ai-props'
|
|
184
|
+
|
|
185
|
+
const getPageProps = createAsyncPropsProvider({
|
|
186
|
+
schema: {
|
|
187
|
+
title: 'SEO title',
|
|
188
|
+
meta: { description: 'Meta description' },
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
// In getStaticProps or getServerSideProps
|
|
193
|
+
export async function getStaticProps() {
|
|
194
|
+
const props = await getPageProps.getProps({ slug: 'about' })
|
|
195
|
+
return { props }
|
|
196
|
+
}
|
|
261
197
|
```
|
|
262
198
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
- `className`: Class applied to the grid container
|
|
267
|
-
- `itemClassName`: Class applied to each grid item
|
|
199
|
+
### createBatchGenerator()
|
|
200
|
+
|
|
201
|
+
Generate props for multiple items efficiently:
|
|
268
202
|
|
|
269
|
-
|
|
203
|
+
```typescript
|
|
204
|
+
import { createBatchGenerator } from 'ai-props'
|
|
270
205
|
|
|
271
|
-
|
|
206
|
+
const batch = createBatchGenerator({
|
|
207
|
+
schema: { title: 'Item title', description: 'Description' },
|
|
208
|
+
concurrency: 3,
|
|
209
|
+
})
|
|
272
210
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
>
|
|
278
|
-
{/* Component content */}
|
|
279
|
-
</AI>
|
|
211
|
+
const items = await batch.generate([
|
|
212
|
+
{ id: 1, category: 'tech' },
|
|
213
|
+
{ id: 2, category: 'science' },
|
|
214
|
+
])
|
|
280
215
|
```
|
|
281
216
|
|
|
282
|
-
|
|
217
|
+
## Validation
|
|
283
218
|
|
|
284
|
-
###
|
|
219
|
+
### validateProps()
|
|
285
220
|
|
|
286
|
-
|
|
221
|
+
Validate props against a schema:
|
|
287
222
|
|
|
288
|
-
|
|
223
|
+
```typescript
|
|
224
|
+
import { validateProps } from 'ai-props'
|
|
289
225
|
|
|
290
|
-
|
|
291
|
-
|
|
226
|
+
const result = validateProps(
|
|
227
|
+
{ name: 'John', age: '25' },
|
|
228
|
+
{ name: 'Name', age: 'Age (number)' }
|
|
229
|
+
)
|
|
292
230
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
customer: 'ideal customer profile in 3-5 words',
|
|
297
|
-
solution: 'describe the offer in 4-10 words'
|
|
298
|
-
},
|
|
299
|
-
description: 'website meta description',
|
|
300
|
-
tags: ['SEO-optimized meta tags'],
|
|
301
|
-
headline: 'compelling headline for AI SaaS product',
|
|
302
|
-
subheadline: 'engaging subheadline explaining value proposition',
|
|
303
|
-
ctaText: 'action-oriented button text',
|
|
304
|
-
benefits: ['3-5 key benefits'],
|
|
305
|
-
targetAudience: 'specific target audience description'
|
|
231
|
+
if (!result.valid) {
|
|
232
|
+
console.log(result.errors)
|
|
233
|
+
// [{ path: 'age', message: 'Expected number, got string' }]
|
|
306
234
|
}
|
|
235
|
+
```
|
|
307
236
|
|
|
308
|
-
|
|
309
|
-
return (
|
|
310
|
-
<AI<typeof heroSchema>
|
|
311
|
-
schema={heroSchema}
|
|
312
|
-
prompt='Generate a hero section for an AI-powered SaaS product waitlist landing page'
|
|
313
|
-
className='bg-gradient-to-br from-blue-50 to-indigo-50'
|
|
314
|
-
>
|
|
315
|
-
{(props) => (
|
|
316
|
-
<div className='max-w-6xl mx-auto px-4 py-16'>
|
|
317
|
-
<h1 className='text-5xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-indigo-600'>
|
|
318
|
-
{props.headline}
|
|
319
|
-
</h1>
|
|
320
|
-
<p className='text-xl text-gray-600 mb-8'>{props.subheadline}</p>
|
|
321
|
-
<button className='bg-blue-600 text-white px-8 py-3 rounded-lg text-lg font-medium hover:bg-blue-700 transition-colors'>
|
|
322
|
-
{props.ctaText}
|
|
323
|
-
</button>
|
|
324
|
-
<div className='mt-12'>
|
|
325
|
-
<h2 className='text-2xl font-semibold mb-4'>Perfect for {props.targetAudience}</h2>
|
|
326
|
-
<ul className='grid grid-cols-1 md:grid-cols-2 gap-4'>
|
|
327
|
-
{props.benefits.map((benefit, index) => (
|
|
328
|
-
<li key={index} className='flex items-start bg-white p-4 rounded-lg shadow-sm'>
|
|
329
|
-
<span className='text-blue-500 mr-2'>✓</span>
|
|
330
|
-
{benefit}
|
|
331
|
-
</li>
|
|
332
|
-
))}
|
|
333
|
-
</ul>
|
|
334
|
-
</div>
|
|
335
|
-
</div>
|
|
336
|
-
)}
|
|
337
|
-
</AI>
|
|
338
|
-
)
|
|
339
|
-
}
|
|
237
|
+
### assertValidProps()
|
|
340
238
|
|
|
341
|
-
|
|
239
|
+
Assert props are valid (throws on error):
|
|
342
240
|
|
|
343
|
-
|
|
241
|
+
```typescript
|
|
242
|
+
import { assertValidProps } from 'ai-props'
|
|
344
243
|
|
|
345
|
-
|
|
346
|
-
|
|
244
|
+
assertValidProps(
|
|
245
|
+
{ name: 'John', age: 25 },
|
|
246
|
+
{ name: 'Name', age: 'Age (number)' }
|
|
247
|
+
)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Other Validation Utilities
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import {
|
|
254
|
+
hasRequiredProps,
|
|
255
|
+
getMissingProps,
|
|
256
|
+
isComplete,
|
|
257
|
+
getMissingFromSchema,
|
|
258
|
+
sanitizeProps,
|
|
259
|
+
mergeWithDefaults,
|
|
260
|
+
createValidator,
|
|
261
|
+
} from 'ai-props'
|
|
262
|
+
|
|
263
|
+
// Check required props
|
|
264
|
+
hasRequiredProps({ name: 'John' }, ['name', 'email']) // false
|
|
265
|
+
|
|
266
|
+
// Get missing props
|
|
267
|
+
getMissingProps({ name: 'John' }, ['name', 'email']) // ['email']
|
|
268
|
+
|
|
269
|
+
// Check schema completion
|
|
270
|
+
isComplete({ name: 'John' }, { name: 'Name', age: 'Age' }) // false
|
|
271
|
+
|
|
272
|
+
// Sanitize extra props
|
|
273
|
+
sanitizeProps({ name: 'John', extra: 'value' }, { name: 'Name' })
|
|
274
|
+
// { name: 'John' }
|
|
275
|
+
|
|
276
|
+
// Merge with defaults
|
|
277
|
+
mergeWithDefaults({ name: 'John' }, { age: 0 }, { name: 'Name', age: 'Age' })
|
|
278
|
+
// { name: 'John', age: 0 }
|
|
279
|
+
|
|
280
|
+
// Create reusable validator
|
|
281
|
+
const validate = createValidator({ name: 'Name', age: 'Age (number)' })
|
|
282
|
+
validate({ name: 'John', age: 25 }) // { valid: true, errors: [] }
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Caching
|
|
286
|
+
|
|
287
|
+
### Cache Configuration
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import { configureAIProps, configureCache, clearCache } from 'ai-props'
|
|
291
|
+
|
|
292
|
+
// Configure global settings
|
|
293
|
+
configureAIProps({
|
|
294
|
+
model: 'gpt-4',
|
|
295
|
+
cache: true,
|
|
296
|
+
cacheTTL: 5 * 60 * 1000, // 5 minutes
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
// Configure cache with custom TTL
|
|
300
|
+
configureCache(10 * 60 * 1000) // 10 minutes
|
|
301
|
+
|
|
302
|
+
// Clear all cached props
|
|
303
|
+
clearCache()
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Cache Classes
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
import { MemoryPropsCache, LRUPropsCache } from 'ai-props'
|
|
310
|
+
|
|
311
|
+
// Simple memory cache
|
|
312
|
+
const memCache = new MemoryPropsCache(5 * 60 * 1000)
|
|
313
|
+
|
|
314
|
+
// LRU cache with max entries
|
|
315
|
+
const lruCache = new LRUPropsCache(100, 5 * 60 * 1000)
|
|
316
|
+
|
|
317
|
+
// Cache operations
|
|
318
|
+
lruCache.set('key', { name: 'John' })
|
|
319
|
+
const entry = lruCache.get<{ name: string }>('key')
|
|
320
|
+
lruCache.delete('key')
|
|
321
|
+
lruCache.clear()
|
|
322
|
+
console.log(lruCache.size)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Schema Type Hints
|
|
326
|
+
|
|
327
|
+
Use type hints in schema strings:
|
|
347
328
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
329
|
+
```typescript
|
|
330
|
+
const schema = {
|
|
331
|
+
name: 'User name', // string
|
|
332
|
+
age: 'User age (number)', // number
|
|
333
|
+
count: 'Item count (integer)', // integer
|
|
334
|
+
active: 'Is active (boolean)', // boolean
|
|
335
|
+
tags: ['Tag names'], // array
|
|
336
|
+
status: 'pending | active | done', // enum
|
|
337
|
+
profile: { // nested object
|
|
338
|
+
bio: 'User bio',
|
|
339
|
+
avatar: 'Avatar URL',
|
|
353
340
|
},
|
|
354
|
-
description: 'website meta description',
|
|
355
|
-
tags: ['relevant topic tags'],
|
|
356
|
-
title: 'engaging blog post title',
|
|
357
|
-
excerpt: 'compelling 2-3 sentence excerpt',
|
|
358
|
-
readTime: 'estimated read time',
|
|
359
|
-
category: 'Blog | Tutorial | Case Study | News'
|
|
360
341
|
}
|
|
342
|
+
```
|
|
361
343
|
|
|
362
|
-
|
|
363
|
-
return (
|
|
364
|
-
<AI<typeof blogSchema>
|
|
365
|
-
schema={blogSchema}
|
|
366
|
-
prompt='Generate 6 blog post previews about AI and machine learning'
|
|
367
|
-
output='array'
|
|
368
|
-
cols={3}
|
|
369
|
-
gap='2rem'
|
|
370
|
-
className='max-w-7xl mx-auto px-4 py-16 grid-cols-1 md:grid-cols-2 lg:grid-cols-3'
|
|
371
|
-
itemClassName='h-full'
|
|
372
|
-
>
|
|
373
|
-
{(props) => (
|
|
374
|
-
<article className='bg-white p-6 rounded-lg shadow-md h-full flex flex-col'>
|
|
375
|
-
<div className='text-sm text-gray-500 mb-2 flex items-center justify-between'>
|
|
376
|
-
<span>{props.category}</span>
|
|
377
|
-
<span>{props.readTime}</span>
|
|
378
|
-
</div>
|
|
379
|
-
<h2 className='text-xl font-semibold mb-3'>{props.title}</h2>
|
|
380
|
-
<p className='text-gray-600 mb-4 flex-grow'>{props.excerpt}</p>
|
|
381
|
-
<div className='flex flex-wrap gap-2 mt-auto'>
|
|
382
|
-
{props.tags.map((tag, index) => (
|
|
383
|
-
<span key={index} className='bg-gray-100 text-gray-600 px-3 py-1 rounded-full text-sm'>
|
|
384
|
-
{tag}
|
|
385
|
-
</span>
|
|
386
|
-
))}
|
|
387
|
-
</div>
|
|
388
|
-
</article>
|
|
389
|
-
)}
|
|
390
|
-
</AI>
|
|
391
|
-
)
|
|
392
|
-
}
|
|
344
|
+
## Configuration
|
|
393
345
|
|
|
394
|
-
|
|
346
|
+
```typescript
|
|
347
|
+
import { configureAIProps, getConfig, resetConfig } from 'ai-props'
|
|
348
|
+
|
|
349
|
+
// Configure globally
|
|
350
|
+
configureAIProps({
|
|
351
|
+
model: 'sonnet', // Default model
|
|
352
|
+
cache: true, // Enable caching
|
|
353
|
+
cacheTTL: 300000, // Cache TTL in ms
|
|
354
|
+
system: 'Custom prompt', // System prompt
|
|
355
|
+
generate: async (schema, context) => {
|
|
356
|
+
// Custom generator
|
|
357
|
+
return { /* generated props */ }
|
|
358
|
+
},
|
|
359
|
+
})
|
|
395
360
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
- Vitest for testing
|
|
399
|
-
- React Cosmos for component development and testing
|
|
361
|
+
// Get current config
|
|
362
|
+
const config = getConfig()
|
|
400
363
|
|
|
401
|
-
|
|
364
|
+
// Reset to defaults
|
|
365
|
+
resetConfig()
|
|
366
|
+
```
|
|
402
367
|
|
|
403
|
-
|
|
404
|
-
- `react` (^18.2.0)
|
|
405
|
-
- `react-dom` (^18.2.0)
|
|
406
|
-
- `@types/react` (^18.2.0)
|
|
407
|
-
- `@types/react-dom` (^18.2.0)
|
|
368
|
+
## API Reference
|
|
408
369
|
|
|
409
|
-
|
|
410
|
-
- `ai` (^4.0.18)
|
|
411
|
-
- `@ai-sdk/openai` (^1.0.8)
|
|
412
|
-
- `clsx` (^2.1.1)
|
|
413
|
-
- `tailwind-merge` (^2.5.5)
|
|
414
|
-
- `zod` (^3.22.4)
|
|
370
|
+
### Types
|
|
415
371
|
|
|
416
|
-
|
|
372
|
+
```typescript
|
|
373
|
+
interface PropSchema {
|
|
374
|
+
[key: string]: string | string[] | PropSchema
|
|
375
|
+
}
|
|
417
376
|
|
|
418
|
-
|
|
419
|
-
|
|
377
|
+
interface GeneratePropsOptions {
|
|
378
|
+
schema: PropSchema
|
|
379
|
+
context?: Record<string, unknown>
|
|
380
|
+
prompt?: string
|
|
381
|
+
model?: string
|
|
382
|
+
system?: string
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
interface GeneratePropsResult<T> {
|
|
386
|
+
props: T
|
|
387
|
+
cached: boolean
|
|
388
|
+
metadata: {
|
|
389
|
+
model: string
|
|
390
|
+
duration?: number
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
interface AIComponentOptions<P> {
|
|
395
|
+
schema: PropSchema
|
|
396
|
+
defaults?: Partial<P>
|
|
397
|
+
required?: (keyof P)[]
|
|
398
|
+
exclude?: (keyof P)[]
|
|
399
|
+
config?: AIPropsConfig
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
interface ValidationResult {
|
|
403
|
+
valid: boolean
|
|
404
|
+
errors: ValidationError[]
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
interface ValidationError {
|
|
408
|
+
path: string
|
|
409
|
+
message: string
|
|
410
|
+
expected?: string
|
|
411
|
+
received?: unknown
|
|
412
|
+
}
|
|
420
413
|
```
|
|
421
414
|
|
|
422
415
|
## License
|