howone 0.1.7 → 0.1.9
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/package.json
CHANGED
|
@@ -29,4 +29,4 @@ Use this skill when writing app code that consumes `@howone/sdk`. The goal is st
|
|
|
29
29
|
|
|
30
30
|
## References
|
|
31
31
|
|
|
32
|
-
Read `references/usage-patterns.md`
|
|
32
|
+
Read `references/usage-patterns.md` before writing any code. It is the complete API reference for `@howone/sdk` and `@howone/sdk/react` — all type signatures, method names, import paths, and call patterns are already there.
|
|
@@ -1,5 +1,192 @@
|
|
|
1
1
|
# HowOne SDK Usage Patterns
|
|
2
2
|
|
|
3
|
+
Complete API reference for `@howone/sdk` and `@howone/sdk/react`. Covers all type signatures, method names, import paths, and usage patterns needed to wire up entities, AI actions, and React components in a HowOne app.
|
|
4
|
+
|
|
5
|
+
## Complete Import Reference
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
// @howone/sdk — all public exports
|
|
9
|
+
import {
|
|
10
|
+
createClient,
|
|
11
|
+
defineAiAction,
|
|
12
|
+
defineAiActions,
|
|
13
|
+
defineEntities,
|
|
14
|
+
withAiActions,
|
|
15
|
+
withEntities,
|
|
16
|
+
type CreateClientOptions,
|
|
17
|
+
type EntityRecord,
|
|
18
|
+
type EntityClient,
|
|
19
|
+
type EntityBindings,
|
|
20
|
+
type QueryOptions,
|
|
21
|
+
type QueryResult,
|
|
22
|
+
type PageInfo,
|
|
23
|
+
type DeleteResult,
|
|
24
|
+
type AiClient,
|
|
25
|
+
type AiActionDefinition,
|
|
26
|
+
type AiActionClient,
|
|
27
|
+
type AiActionConfig,
|
|
28
|
+
type AiResult, // = ExecutionResult
|
|
29
|
+
type AiSession, // { result: Promise<AiResult>, cancel(): void, signal: AbortSignal }
|
|
30
|
+
type AiEvent, // SSE event payload
|
|
31
|
+
type AiOptions,
|
|
32
|
+
type UserProfile,
|
|
33
|
+
AiSchemaValidationError,
|
|
34
|
+
} from '@howone/sdk'
|
|
35
|
+
|
|
36
|
+
// @howone/sdk/react — React components and hooks
|
|
37
|
+
import {
|
|
38
|
+
HowOneProvider,
|
|
39
|
+
useHowoneContext,
|
|
40
|
+
FloatingButton,
|
|
41
|
+
Loading,
|
|
42
|
+
LoadingSpinner,
|
|
43
|
+
type HowOneProviderProps,
|
|
44
|
+
type HowOneAuthMode,
|
|
45
|
+
type HowOneThemeMode,
|
|
46
|
+
type HowOneBrandMode,
|
|
47
|
+
} from '@howone/sdk/react'
|
|
48
|
+
|
|
49
|
+
import { z } from 'zod'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## createClient — signature & return shape
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
const client = createClient({
|
|
58
|
+
projectId: import.meta.env.VITE_HOWONE_PROJECT_ID, // required in Vite apps
|
|
59
|
+
env: import.meta.env.VITE_HOWONE_ENV, // 'local' | 'dev' | 'prod'
|
|
60
|
+
// Optional advanced options (rarely needed):
|
|
61
|
+
// apiUrl, aiUrl, caseStyle ('camel'|'snake'), auth: { mode, getToken }
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// client shape:
|
|
65
|
+
client.entity<TRecord, TCreate, TUpdate>(entityName: string): EntityClient<...>
|
|
66
|
+
client.entities: Record<string, EntityClient>
|
|
67
|
+
client.ai: AiClient // low-level; prefer withAiActions bindings
|
|
68
|
+
client.me(): Promise<UserProfile | null>
|
|
69
|
+
client.requireMe(): Promise<UserProfile>
|
|
70
|
+
client.auth.setToken(t: string | null): void
|
|
71
|
+
client.auth.getToken(): string | null
|
|
72
|
+
client.auth.isAuthenticated(): boolean
|
|
73
|
+
client.auth.login(redirect?: string): void
|
|
74
|
+
client.auth.logout(): void
|
|
75
|
+
client.upload.file(file, options?): Promise<{ url, thumbnailUrl?, id?, size?, mimeType? }>
|
|
76
|
+
client.upload.image(file): Promise<{ url }>
|
|
77
|
+
client.upload.batch({ files, concurrent?, onProgress?, onFileComplete? }): Promise<BatchUploadResponse>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## EntityClient — complete method signatures
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
type EntityClient<TRecord, TCreate, TUpdate> = {
|
|
86
|
+
name: string
|
|
87
|
+
// Basic CRUD
|
|
88
|
+
list(options?: { page?, limit?, sort?, order?, ...filters }): Promise<TRecord[]>
|
|
89
|
+
get(id: string): Promise<TRecord | null>
|
|
90
|
+
getOrThrow(id: string): Promise<TRecord>
|
|
91
|
+
create(data: TCreate): Promise<TRecord>
|
|
92
|
+
update(id: string, data: TUpdate): Promise<TRecord>
|
|
93
|
+
delete(id: string): Promise<{ deleted: boolean; id: string; message? }>
|
|
94
|
+
// Advanced query with filters/pagination
|
|
95
|
+
query(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
|
|
96
|
+
query.mine(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
|
|
97
|
+
bulkCreate(records: TCreate[], options?: { sample?: boolean }): Promise<TRecord[]>
|
|
98
|
+
aggregate(pipeline: unknown[]): Promise<unknown[]>
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// QueryOptions
|
|
102
|
+
type QueryOptions<TRecord> = {
|
|
103
|
+
where?: { [K in keyof TRecord]?: TRecord[K] | FieldOperator }
|
|
104
|
+
// FieldOperator: { eq, ne, gt, gte, lt, lte, contains, like, startsWith, endsWith, in, notIn }
|
|
105
|
+
search?: string
|
|
106
|
+
page?: { number?: number; size?: number }
|
|
107
|
+
orderBy?: Partial<Record<keyof TRecord | string, 'asc' | 'desc'>>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// QueryResult
|
|
111
|
+
type QueryResult<T> = {
|
|
112
|
+
items: T[]
|
|
113
|
+
page: { number, size, total, totalPages, hasNext, hasPrev }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// EntityRecord base
|
|
117
|
+
type EntityRecord = {
|
|
118
|
+
id: string
|
|
119
|
+
createdDate?: string
|
|
120
|
+
updatedDate?: string
|
|
121
|
+
createdById?: string
|
|
122
|
+
isSample?: boolean
|
|
123
|
+
[key: string]: unknown
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## AI Action — complete signatures
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// Define a typed action
|
|
133
|
+
defineAiAction(id: string, config?: {
|
|
134
|
+
inputSchema?: z.ZodType<TInput>
|
|
135
|
+
outputSchema?: z.ZodType<TOutput>
|
|
136
|
+
mode?: 'run' | 'stream' | 'events'
|
|
137
|
+
}): AiActionDefinition<TInput, TOutput>
|
|
138
|
+
|
|
139
|
+
// Group actions
|
|
140
|
+
defineAiActions({ [name]: AiActionDefinition, ... }): actions
|
|
141
|
+
|
|
142
|
+
// Bind to client
|
|
143
|
+
withAiActions(client, actions): client & { ai: { [name]: AiActionClient } }
|
|
144
|
+
|
|
145
|
+
// AiActionClient methods
|
|
146
|
+
howone.ai.<actionName>.run(inputs?, options?): Promise<TOutput>
|
|
147
|
+
howone.ai.<actionName>.stream(inputs?, options?): AiSession
|
|
148
|
+
howone.ai.<actionName>.events(inputs?, options?): AsyncIterable<AiEvent>
|
|
149
|
+
|
|
150
|
+
// AiSession
|
|
151
|
+
type AiSession = {
|
|
152
|
+
result: Promise<AiResult>
|
|
153
|
+
cancel(): void
|
|
154
|
+
signal: AbortSignal
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Reserved names — do NOT use as action names: run, stream, events
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## React: HowOneProvider & hooks
|
|
163
|
+
|
|
164
|
+
`@howone/sdk/react` exports exactly: `HowOneProvider`, `useHowoneContext`, `FloatingButton`, `Loading`, `LoadingSpinner`.
|
|
165
|
+
|
|
166
|
+
**There are no `useEntity`, `useQuery`, `useAi`, or other data-fetching hooks.** Entity and AI calls are plain async functions — call them directly in components with `useEffect`/`useState` or any data-fetching library (SWR, React Query, etc.).
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
// Wrap app root — handles auth, theme, toasts, floating button
|
|
170
|
+
<HowOneProvider
|
|
171
|
+
projectId={...} // optional if client is already configured
|
|
172
|
+
auth="optional" // 'required' | 'optional' | 'none'
|
|
173
|
+
brand="visible" // 'visible' | 'hidden'
|
|
174
|
+
theme="inherit" // 'dark' | 'light' | 'system' | 'inherit'
|
|
175
|
+
showBrandButton={true}
|
|
176
|
+
>
|
|
177
|
+
<App />
|
|
178
|
+
</HowOneProvider>
|
|
179
|
+
|
|
180
|
+
// Auth context hook — the only hook in the package
|
|
181
|
+
const { user, token, isAuthenticated, logout } = useHowoneContext()
|
|
182
|
+
// user shape: { id, email, name, avatar } | null
|
|
183
|
+
|
|
184
|
+
// Loading components
|
|
185
|
+
<Loading size="md" tone="brand" label="..." description="..." fullScreen />
|
|
186
|
+
<LoadingSpinner size="sm" tone="neutral" />
|
|
187
|
+
// size: 'sm' | 'md' | 'lg' tone: 'brand' | 'neutral' | 'inverse'
|
|
188
|
+
```
|
|
189
|
+
|
|
3
190
|
## App SDK Entry
|
|
4
191
|
|
|
5
192
|
Preferred Vite app entry shape:
|
|
@@ -120,20 +307,19 @@ for await (const event of howone.ai.generateStory.events(input)) {
|
|
|
120
307
|
}
|
|
121
308
|
```
|
|
122
309
|
|
|
123
|
-
## AI Output Validation
|
|
310
|
+
## AI Output Validation
|
|
124
311
|
|
|
125
|
-
|
|
312
|
+
`run()` validates input with `inputSchema`, calls the workflow, then validates the **raw `ExecutionResult`** (the full SSE envelope) with `outputSchema`. It does **not** automatically unwrap `result.finalResult`.
|
|
126
313
|
|
|
127
|
-
|
|
314
|
+
If you want to type the final result only, either:
|
|
315
|
+
1. Define `outputSchema` to match the full `ExecutionResult` shape, or
|
|
316
|
+
2. Omit `outputSchema` and unwrap manually:
|
|
128
317
|
|
|
129
318
|
```ts
|
|
130
|
-
const result = await
|
|
131
|
-
const
|
|
132
|
-
return parseAiValue(definition.id, 'output', output, definition.outputSchema)
|
|
319
|
+
const result = await howone.ai.generateStory.run(input) // returns AiResult
|
|
320
|
+
const finalResult = result.finalResult as GenerateStoryOutput
|
|
133
321
|
```
|
|
134
322
|
|
|
135
|
-
If the SDK still validates the whole `ExecutionResult`, either fix the SDK first or avoid generating final-result `outputSchema` in app code that will immediately run.
|
|
136
|
-
|
|
137
323
|
## AI Result Persistence
|
|
138
324
|
|
|
139
325
|
For AI-generated data that should be saved:
|
package/templates/vite/AGENTS.md
CHANGED
|
@@ -1,11 +1,97 @@
|
|
|
1
|
-
|
|
1
|
+
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This file defines project-specific instructions for coding agents.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
Read this file once when entering the project.
|
|
6
|
+
Follow it during implementation.
|
|
7
|
+
Do not repeatedly reread it unless it changes or the current task requires checking project rules again.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
```
|
|
9
|
+
## Multi-turn Policy
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
After reading this file, maintain a concise project policy summary for the active workspace session.
|
|
12
|
+
Use that summary across turns instead of rereading this file or relying on old chat history.
|
|
13
|
+
|
|
14
|
+
The project policy summary should stay short and include only durable rules:
|
|
15
|
+
|
|
16
|
+
- package manager and common commands
|
|
17
|
+
- trusted libraries and framework assumptions
|
|
18
|
+
- context-loading rules
|
|
19
|
+
- validation rules
|
|
20
|
+
- project-specific constraints
|
|
21
|
+
|
|
22
|
+
Do not store transient command output, temporary reasoning, full file contents, or step-by-step logs in the project policy.
|
|
23
|
+
|
|
24
|
+
Maintain a separate short task state summary while implementing a user request:
|
|
25
|
+
|
|
26
|
+
- current goal
|
|
27
|
+
- current phase: explore, implement, validate, fix, or done
|
|
28
|
+
- files already read
|
|
29
|
+
- files changed
|
|
30
|
+
- last validation command and result
|
|
31
|
+
- known blockers or open questions
|
|
32
|
+
|
|
33
|
+
Use task state to avoid repeating exploration or rereading unchanged files. Reset or replace it when the user starts a new unrelated task.
|
|
34
|
+
|
|
35
|
+
Do not reread this file unless:
|
|
36
|
+
|
|
37
|
+
- this file changed
|
|
38
|
+
- the project policy summary is unavailable
|
|
39
|
+
- the task enters a nested project with its own `AGENTS.md`
|
|
40
|
+
- validation errors suggest a project rule was missed
|
|
41
|
+
|
|
42
|
+
## Library Trust Policy
|
|
43
|
+
|
|
44
|
+
For common public libraries already known to modern coding models, prefer model knowledge and package metadata over reading local source files.
|
|
45
|
+
|
|
46
|
+
This project may include generated or vendored library-style files, such as shadcn/ui components under `src/components/ui/*`.
|
|
47
|
+
|
|
48
|
+
Do not inspect these files during ordinary feature work just to confirm standard APIs.
|
|
49
|
+
|
|
50
|
+
Examples of trusted public libraries:
|
|
51
|
+
|
|
52
|
+
- React
|
|
53
|
+
- Vite
|
|
54
|
+
- TypeScript
|
|
55
|
+
- Tailwind CSS
|
|
56
|
+
- shadcn/ui
|
|
57
|
+
- lucide-react
|
|
58
|
+
- Radix UI
|
|
59
|
+
- clsx
|
|
60
|
+
- class-variance-authority
|
|
61
|
+
|
|
62
|
+
When implementing ordinary usage of these libraries:
|
|
63
|
+
|
|
64
|
+
1. Use standard public APIs first.
|
|
65
|
+
2. Read `package.json`, `components.json`, `tsconfig.json`, or alias config only when needed.
|
|
66
|
+
3. Implement the feature.
|
|
67
|
+
4. Run build/typecheck.
|
|
68
|
+
5. Inspect the smallest relevant local file only if validation fails or the API is genuinely unclear.
|
|
69
|
+
|
|
70
|
+
Only read local component or library-style source files when:
|
|
71
|
+
|
|
72
|
+
- build/typecheck fails
|
|
73
|
+
- imports cannot be resolved from `package.json`, `tsconfig.json`, or `components.json`
|
|
74
|
+
- the component API is unclear
|
|
75
|
+
- the task requires modifying the component implementation
|
|
76
|
+
- the project has custom wrappers, custom variants, or unusual exports
|
|
77
|
+
- the user explicitly asks to follow local component conventions
|
|
78
|
+
|
|
79
|
+
Prefer failure-driven inspection over speculative context loading.
|
|
80
|
+
|
|
81
|
+
## Context Budget Policy
|
|
82
|
+
|
|
83
|
+
Start with the smallest useful context:
|
|
84
|
+
|
|
85
|
+
1. Identify the app root and relevant scripts.
|
|
86
|
+
2. Read the smallest file that directly controls the requested behavior.
|
|
87
|
+
3. Prefer package metadata, config files, and public API usage before local library internals.
|
|
88
|
+
4. Expand to additional files only when implementation, validation, or ambiguity requires it.
|
|
89
|
+
|
|
90
|
+
Avoid broad project scans unless the user asks for a repository-wide change or the relevant files are genuinely unknown.
|
|
91
|
+
|
|
92
|
+
## Validation Policy
|
|
93
|
+
|
|
94
|
+
After meaningful code changes, run the narrowest relevant validation command available in this project.
|
|
95
|
+
Prefer build or typecheck before deeper investigation into library internals.
|
|
96
|
+
|
|
97
|
+
If validation fails, inspect the smallest file or error location needed to fix the failure.
|