howone 0.1.10 → 0.1.11
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
|
@@ -12,21 +12,78 @@ This skill is the normal source of truth for HowOne SDK usage in generated apps.
|
|
|
12
12
|
## Workflow
|
|
13
13
|
|
|
14
14
|
1. Establish the app root. All `.howone/*` metadata and `src/lib/sdk.ts` work belongs inside that app root.
|
|
15
|
-
2. Read `
|
|
16
|
-
3. Read
|
|
17
|
-
4.
|
|
18
|
-
5. For
|
|
19
|
-
6.
|
|
20
|
-
7.
|
|
15
|
+
2. Read `node_modules/@howone/sdk/dist/index.d.ts` and `node_modules/@howone/sdk/dist/react.d.ts` to get the complete, always-up-to-date type signatures and public exports.
|
|
16
|
+
3. Read `references/usage-patterns.md` for generation recipes, usage examples, and known traps that aren't in the type declarations.
|
|
17
|
+
4. Read the existing app SDK entry, usually `src/lib/sdk.ts`, before editing. Preserve its imports and local style.
|
|
18
|
+
5. For Entity bindings, read `.howone/database/manifest.json`.
|
|
19
|
+
6. For AI action bindings, read `.howone/ai/manifest.json`.
|
|
20
|
+
7. Generate source code from the manifests, not from memory or tool-call summaries.
|
|
21
|
+
8. Keep sync tools and app-code edits separate. `sync_schema_artifacts` and `sync_ai_artifacts` write metadata only; the coding agent edits `src/lib/sdk.ts`.
|
|
22
|
+
|
|
23
|
+
## Quick SDK Contract
|
|
24
|
+
|
|
25
|
+
See `/sdk/dist/index.d.ts` and `/sdk/dist/react.d.ts` for the full type signatures. The minimal app wiring looks like:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import {
|
|
29
|
+
createClient,
|
|
30
|
+
defineAiAction,
|
|
31
|
+
defineAiActions,
|
|
32
|
+
defineEntities,
|
|
33
|
+
type EntityRecord,
|
|
34
|
+
withAiActions,
|
|
35
|
+
withEntities,
|
|
36
|
+
} from '@howone/sdk'
|
|
37
|
+
import { HowOneProvider, useHowoneContext } from '@howone/sdk/react'
|
|
38
|
+
import { z } from 'zod'
|
|
39
|
+
|
|
40
|
+
const client = createClient({
|
|
41
|
+
projectId: import.meta.env.VITE_HOWONE_PROJECT_ID,
|
|
42
|
+
env: import.meta.env.VITE_HOWONE_ENV,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
export const entities = defineEntities({
|
|
46
|
+
Todo: client.entity<Todo, TodoCreate, TodoUpdate>('Todo'),
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
export const ai = defineAiActions({
|
|
50
|
+
summarizeTodo: defineAiAction('summarizeTodo', {
|
|
51
|
+
inputSchema: z.object({ title: z.string() }),
|
|
52
|
+
}),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const howone = withAiActions(withEntities(client, entities), ai)
|
|
56
|
+
export default howone
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Entity calls are plain async SDK calls:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
await howone.entities.Todo.list()
|
|
63
|
+
await howone.entities.Todo.create({ title: 'Ship it', completed: false })
|
|
64
|
+
await howone.entities.Todo.update(id, { completed: true })
|
|
65
|
+
await howone.entities.Todo.delete(id)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
AI action calls are bound by action name:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const result = await howone.ai.summarizeTodo.run({ title })
|
|
72
|
+
const session = howone.ai.summarizeTodo.stream({ title })
|
|
73
|
+
for await (const event of howone.ai.summarizeTodo.events({ title })) {
|
|
74
|
+
// handle event
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
React integration provides provider/auth/loading UI only: `HowOneProvider`, `useHowoneContext`, `FloatingButton`, `Loading`, and `LoadingSpinner`. It does not provide entity/query/AI data hooks. Use `useEffect`/`useState` or a data-fetching library around plain async SDK calls.
|
|
21
79
|
|
|
22
80
|
## Source Order
|
|
23
81
|
|
|
24
82
|
Use this order when deciding what to read:
|
|
25
83
|
|
|
26
|
-
1.
|
|
27
|
-
2.
|
|
28
|
-
3.
|
|
29
|
-
4. SDK source or declaration files, only as a narrow fallback for a missing or disputed API.
|
|
84
|
+
1. `packages/sdk/dist/index.d.ts` and `packages/sdk/dist/react.d.ts` — complete public API.
|
|
85
|
+
2. `references/usage-patterns.md` — generation recipes, examples, traps.
|
|
86
|
+
3. Current app files: `src/lib/sdk.ts`, relevant UI files, and generated manifests.
|
|
30
87
|
|
|
31
88
|
## Rules
|
|
32
89
|
|
|
@@ -42,4 +99,5 @@ Use this order when deciding what to read:
|
|
|
42
99
|
|
|
43
100
|
## References
|
|
44
101
|
|
|
45
|
-
Read `
|
|
102
|
+
Read `packages/sdk/dist/index.d.ts` and `packages/sdk/dist/react.d.ts` for the full SDK type surface.
|
|
103
|
+
Read `references/usage-patterns.md` for generation recipes, usage examples, and known traps.
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
# HowOne SDK Usage Patterns
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Reading Strategy
|
|
6
|
-
|
|
7
|
-
Use this file as the working SDK manual for normal app generation. It intentionally includes the public imports, client shape, entity methods, AI action bindings, React exports, app SDK entry shape, and known validation caveats.
|
|
8
|
-
|
|
9
|
-
Do not inspect `node_modules/@howone/sdk` for the same information unless:
|
|
10
|
-
|
|
11
|
-
- This file does not cover the exact API needed.
|
|
12
|
-
- TypeScript or runtime verification contradicts this file.
|
|
13
|
-
- You are intentionally updating the SDK package itself, not an app that consumes it.
|
|
14
|
-
|
|
15
|
-
When source fallback is necessary, keep it narrow: inspect the exact exported symbol or declaration that is missing, then return to app code. Do not glob or read the whole SDK package to relearn the basic usage below.
|
|
3
|
+
This file covers what the type declarations don't: generation recipes, usage examples, and known traps. For the complete public API (all types, method signatures, exports), read `node_modules/@howone/sdk/dist/index.d.ts` and `node_modules/@howone/sdk/dist/react.d.ts` first.
|
|
16
4
|
|
|
17
5
|
## SDK Mental Model
|
|
18
6
|
|
|
@@ -23,191 +11,6 @@ When source fallback is necessary, keep it narrow: inspect the exact exported sy
|
|
|
23
11
|
- `@howone/sdk/react` provides auth/theme/loading UI primitives only. It does not provide entity, query, or AI data hooks.
|
|
24
12
|
- `.howone/database/manifest.json` and `.howone/ai/manifest.json` are the generated contracts. App source should be generated from those manifests, not from memory.
|
|
25
13
|
|
|
26
|
-
## Import Reference
|
|
27
|
-
|
|
28
|
-
```ts
|
|
29
|
-
// @howone/sdk — all public exports
|
|
30
|
-
import {
|
|
31
|
-
createClient,
|
|
32
|
-
defineAiAction,
|
|
33
|
-
defineAiActions,
|
|
34
|
-
defineEntities,
|
|
35
|
-
withAiActions,
|
|
36
|
-
withEntities,
|
|
37
|
-
type CreateClientOptions,
|
|
38
|
-
type EntityRecord,
|
|
39
|
-
type EntityClient,
|
|
40
|
-
type EntityBindings,
|
|
41
|
-
type QueryOptions,
|
|
42
|
-
type QueryResult,
|
|
43
|
-
type PageInfo,
|
|
44
|
-
type DeleteResult,
|
|
45
|
-
type AiClient,
|
|
46
|
-
type AiActionDefinition,
|
|
47
|
-
type AiActionClient,
|
|
48
|
-
type AiActionConfig,
|
|
49
|
-
type AiResult, // = ExecutionResult
|
|
50
|
-
type AiSession, // { result: Promise<AiResult>, cancel(): void, signal: AbortSignal }
|
|
51
|
-
type AiEvent, // SSE event payload
|
|
52
|
-
type AiOptions,
|
|
53
|
-
type UserProfile,
|
|
54
|
-
AiSchemaValidationError,
|
|
55
|
-
} from '@howone/sdk'
|
|
56
|
-
|
|
57
|
-
// @howone/sdk/react — React components and hooks
|
|
58
|
-
import {
|
|
59
|
-
HowOneProvider,
|
|
60
|
-
useHowoneContext,
|
|
61
|
-
FloatingButton,
|
|
62
|
-
Loading,
|
|
63
|
-
LoadingSpinner,
|
|
64
|
-
type HowOneProviderProps,
|
|
65
|
-
type HowOneAuthMode,
|
|
66
|
-
type HowOneThemeMode,
|
|
67
|
-
type HowOneBrandMode,
|
|
68
|
-
} from '@howone/sdk/react'
|
|
69
|
-
|
|
70
|
-
import { z } from 'zod'
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
---
|
|
74
|
-
|
|
75
|
-
## createClient
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
const client = createClient({
|
|
79
|
-
projectId: import.meta.env.VITE_HOWONE_PROJECT_ID, // required in Vite apps
|
|
80
|
-
env: import.meta.env.VITE_HOWONE_ENV, // 'local' | 'dev' | 'prod'
|
|
81
|
-
// Optional advanced options (rarely needed):
|
|
82
|
-
// apiUrl, aiUrl, caseStyle ('camel'|'snake'), auth: { mode, getToken }
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
// client shape:
|
|
86
|
-
client.entity<TRecord, TCreate, TUpdate>(entityName: string): EntityClient<...>
|
|
87
|
-
client.entities: Record<string, EntityClient>
|
|
88
|
-
client.ai: AiClient // low-level; prefer withAiActions bindings
|
|
89
|
-
client.me(): Promise<UserProfile | null>
|
|
90
|
-
client.requireMe(): Promise<UserProfile>
|
|
91
|
-
client.auth.setToken(t: string | null): void
|
|
92
|
-
client.auth.getToken(): string | null
|
|
93
|
-
client.auth.isAuthenticated(): boolean
|
|
94
|
-
client.auth.login(redirect?: string): void
|
|
95
|
-
client.auth.logout(): void
|
|
96
|
-
client.upload.file(file, options?): Promise<{ url, thumbnailUrl?, id?, size?, mimeType? }>
|
|
97
|
-
client.upload.image(file): Promise<{ url }>
|
|
98
|
-
client.upload.batch({ files, concurrent?, onProgress?, onFileComplete? }): Promise<BatchUploadResponse>
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## EntityClient
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
type EntityClient<TRecord, TCreate, TUpdate> = {
|
|
107
|
-
name: string
|
|
108
|
-
// Basic CRUD
|
|
109
|
-
list(options?: { page?, limit?, sort?, order?, ...filters }): Promise<TRecord[]>
|
|
110
|
-
get(id: string): Promise<TRecord | null>
|
|
111
|
-
getOrThrow(id: string): Promise<TRecord>
|
|
112
|
-
create(data: TCreate): Promise<TRecord>
|
|
113
|
-
update(id: string, data: TUpdate): Promise<TRecord>
|
|
114
|
-
delete(id: string): Promise<{ deleted: boolean; id: string; message? }>
|
|
115
|
-
// Advanced query with filters/pagination
|
|
116
|
-
query(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
|
|
117
|
-
query.mine(options?: QueryOptions<TRecord>): Promise<QueryResult<TRecord>>
|
|
118
|
-
bulkCreate(records: TCreate[], options?: { sample?: boolean }): Promise<TRecord[]>
|
|
119
|
-
aggregate(pipeline: unknown[]): Promise<unknown[]>
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// QueryOptions
|
|
123
|
-
type QueryOptions<TRecord> = {
|
|
124
|
-
where?: { [K in keyof TRecord]?: TRecord[K] | FieldOperator }
|
|
125
|
-
// FieldOperator: { eq, ne, gt, gte, lt, lte, contains, like, startsWith, endsWith, in, notIn }
|
|
126
|
-
search?: string
|
|
127
|
-
page?: { number?: number; size?: number }
|
|
128
|
-
orderBy?: Partial<Record<keyof TRecord | string, 'asc' | 'desc'>>
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// QueryResult
|
|
132
|
-
type QueryResult<T> = {
|
|
133
|
-
items: T[]
|
|
134
|
-
page: { number, size, total, totalPages, hasNext, hasPrev }
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// EntityRecord base
|
|
138
|
-
type EntityRecord = {
|
|
139
|
-
id: string
|
|
140
|
-
createdDate?: string
|
|
141
|
-
updatedDate?: string
|
|
142
|
-
createdById?: string
|
|
143
|
-
isSample?: boolean
|
|
144
|
-
[key: string]: unknown
|
|
145
|
-
}
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## AI Action
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
// Define a typed action
|
|
154
|
-
defineAiAction(id: string, config?: {
|
|
155
|
-
inputSchema?: z.ZodType<TInput>
|
|
156
|
-
outputSchema?: z.ZodType<TOutput>
|
|
157
|
-
mode?: 'run' | 'stream' | 'events'
|
|
158
|
-
}): AiActionDefinition<TInput, TOutput>
|
|
159
|
-
|
|
160
|
-
// Group actions
|
|
161
|
-
defineAiActions({ [name]: AiActionDefinition, ... }): actions
|
|
162
|
-
|
|
163
|
-
// Bind to client
|
|
164
|
-
withAiActions(client, actions): client & { ai: { [name]: AiActionClient } }
|
|
165
|
-
|
|
166
|
-
// AiActionClient methods
|
|
167
|
-
howone.ai.<actionName>.run(inputs?, options?): Promise<TOutput>
|
|
168
|
-
howone.ai.<actionName>.stream(inputs?, options?): AiSession
|
|
169
|
-
howone.ai.<actionName>.events(inputs?, options?): AsyncIterable<AiEvent>
|
|
170
|
-
|
|
171
|
-
// AiSession
|
|
172
|
-
type AiSession = {
|
|
173
|
-
result: Promise<AiResult>
|
|
174
|
-
cancel(): void
|
|
175
|
-
signal: AbortSignal
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// Reserved names — do NOT use as action names: run, stream, events
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## React: HowOneProvider & hooks
|
|
184
|
-
|
|
185
|
-
`@howone/sdk/react` exports exactly: `HowOneProvider`, `useHowoneContext`, `FloatingButton`, `Loading`, `LoadingSpinner`.
|
|
186
|
-
|
|
187
|
-
**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.).
|
|
188
|
-
|
|
189
|
-
```tsx
|
|
190
|
-
// Wrap app root — handles auth, theme, toasts, floating button
|
|
191
|
-
<HowOneProvider
|
|
192
|
-
projectId={...} // optional if client is already configured
|
|
193
|
-
auth="optional" // 'required' | 'optional' | 'none'
|
|
194
|
-
brand="visible" // 'visible' | 'hidden'
|
|
195
|
-
theme="inherit" // 'dark' | 'light' | 'system' | 'inherit'
|
|
196
|
-
showBrandButton={true}
|
|
197
|
-
>
|
|
198
|
-
<App />
|
|
199
|
-
</HowOneProvider>
|
|
200
|
-
|
|
201
|
-
// Auth context hook — the only hook in the package
|
|
202
|
-
const { user, token, isAuthenticated, logout } = useHowoneContext()
|
|
203
|
-
// user shape: { id, email, name, avatar } | null
|
|
204
|
-
|
|
205
|
-
// Loading components
|
|
206
|
-
<Loading size="md" tone="brand" label="..." description="..." fullScreen />
|
|
207
|
-
<LoadingSpinner size="sm" tone="neutral" />
|
|
208
|
-
// size: 'sm' | 'md' | 'lg' tone: 'brand' | 'neutral' | 'inverse'
|
|
209
|
-
```
|
|
210
|
-
|
|
211
14
|
## App SDK Entry
|
|
212
15
|
|
|
213
16
|
Preferred Vite app entry shape:
|
|
@@ -401,37 +204,6 @@ await howone.entities.Story.create({
|
|
|
401
204
|
})
|
|
402
205
|
```
|
|
403
206
|
|
|
404
|
-
## Do Not Generate
|
|
405
|
-
|
|
406
|
-
Avoid these patterns unless the SDK has explicitly added them:
|
|
407
|
-
|
|
408
|
-
```ts
|
|
409
|
-
// No data hooks in @howone/sdk/react
|
|
410
|
-
const todos = useEntity('Todo')
|
|
411
|
-
const query = useQuery(...)
|
|
412
|
-
const result = useAi(...)
|
|
413
|
-
|
|
414
|
-
// Wrong AI binding shape
|
|
415
|
-
await howone.ai.run.generateStory(input)
|
|
416
|
-
|
|
417
|
-
// Too-loose create payload
|
|
418
|
-
type StoryCreate = Omit<StoryRecord, 'id' | 'createdDate' | 'updatedDate'>
|
|
419
|
-
|
|
420
|
-
// Generated files do not belong under .howone
|
|
421
|
-
// .howone stores synced manifests only.
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
## When To Read SDK Source
|
|
425
|
-
|
|
426
|
-
Read SDK source or declaration files only for details not covered above, for example:
|
|
427
|
-
|
|
428
|
-
- A newly added public method not listed here.
|
|
429
|
-
- A TypeScript error proving a signature drifted.
|
|
430
|
-
- A runtime error that points to a specific SDK helper.
|
|
431
|
-
- Work that intentionally modifies `packages/sdk` itself.
|
|
432
|
-
|
|
433
|
-
For app generation, do not inspect SDK source to rediscover `createClient`, entity CRUD, AI action binding shape, React exports, or Vite env setup.
|
|
434
|
-
|
|
435
207
|
## Generated Code Checklist
|
|
436
208
|
|
|
437
209
|
- `src/lib/sdk.ts` imports only APIs it uses.
|