weifuwu 0.19.10 → 0.21.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.
- package/README.md +221 -32
- package/cli/template/index.ts +1 -3
- package/cli.ts +197 -33
- package/dist/agent/rest.d.ts +1 -0
- package/dist/agent/run.d.ts +1 -0
- package/dist/cli.js +169 -29
- package/dist/client-router.d.ts +1 -1
- package/dist/csrf.d.ts +4 -2
- package/dist/env.d.ts +6 -1
- package/dist/graphql.d.ts +4 -0
- package/dist/index.d.ts +11 -6
- package/dist/index.js +1254 -466
- package/dist/logger.d.ts +14 -3
- package/dist/messager/agent.d.ts +6 -1
- package/dist/postgres/client.d.ts +2 -0
- package/dist/postgres/index.d.ts +2 -2
- package/dist/postgres/module.d.ts +5 -3
- package/dist/postgres/schema/table.d.ts +8 -2
- package/dist/postgres/types.d.ts +31 -8
- package/dist/preferences.d.ts +6 -2
- package/dist/queue/types.d.ts +14 -3
- package/dist/react.d.ts +2 -0
- package/dist/react.js +57 -0
- package/dist/redis/types.d.ts +5 -3
- package/dist/request-id.d.ts +4 -2
- package/dist/router.d.ts +28 -16
- package/dist/serve.d.ts +13 -2
- package/dist/ssr.d.ts +15 -0
- package/dist/test-utils.d.ts +64 -0
- package/dist/trace.d.ts +15 -0
- package/dist/types.d.ts +3 -3
- package/dist/use-agent-stream.d.ts +27 -0
- package/dist/user/index.d.ts +1 -1
- package/dist/user/types.d.ts +5 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,17 @@ serve(app.handler(), { port: 3000, websocket: app.websocketHandler() })
|
|
|
25
25
|
npx weifuwu init my-app && cd my-app && npm run dev
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## CLI
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx weifuwu init my-app # Full project (SSR + i18n + theme + WS demo)
|
|
32
|
+
npx weifuwu init my-api --minimal # Minimal HTTP project (2 files)
|
|
33
|
+
npx weifuwu init my-api --skip-install # Skip npm install
|
|
34
|
+
npx weifuwu dev # Start dev server (auto-detect index.ts)
|
|
35
|
+
npx weifuwu generate module my-mod # Scaffold middleware module + test
|
|
36
|
+
npx weifuwu version # Print version
|
|
37
|
+
```
|
|
38
|
+
|
|
28
39
|
---
|
|
29
40
|
|
|
30
41
|
## Core Concepts
|
|
@@ -42,11 +53,14 @@ await server.ready
|
|
|
42
53
|
| `hostname` | `string` | `'0.0.0.0'` | Listen address |
|
|
43
54
|
| `signal` | `AbortSignal` | — | Shutdown on abort |
|
|
44
55
|
| `websocket` | `WsUpgradeHandler` | — | WebSocket upgrade handler |
|
|
45
|
-
| `maxBodySize` | `number` |
|
|
56
|
+
| `maxBodySize` | `number` | `10MB` | Max body bytes (0 = unlimited) |
|
|
57
|
+
| `timeout` | `number` | `30_000` | Socket inactivity timeout (ms) |
|
|
58
|
+
| `keepAliveTimeout` | `number` | `5_000` | Keep-Alive idle timeout (ms) |
|
|
59
|
+
| `headersTimeout` | `number` | `6_000` | Headers read timeout (ms) |
|
|
46
60
|
| `shutdown` | `boolean` | `true` | Auto SIGTERM/SIGINT |
|
|
47
61
|
|
|
48
62
|
```ts
|
|
49
|
-
interface Server { stop: () => void
|
|
63
|
+
interface Server { stop: () => Promise<void>; readonly port: number; readonly hostname: string; ready: Promise<void> }
|
|
50
64
|
const { server, url } = await createTestServer(handler)
|
|
51
65
|
```
|
|
52
66
|
|
|
@@ -58,9 +72,24 @@ app.get('/hello/:name', (req, ctx) => Response.json({ message: `Hello, ${ctx.par
|
|
|
58
72
|
app.post('/data', async (req, ctx) => { const body = await req.json(); return Response.json(body, { status: 201 }) })
|
|
59
73
|
app.use('/admin', authMW) // path-scoped middleware
|
|
60
74
|
app.use('/admin', adminRouter) // sub-router (flattened into parent trie)
|
|
61
|
-
app.ws('/echo', {
|
|
75
|
+
app.ws('/echo', {
|
|
76
|
+
open(ws, ctx) { ctx.ws.json({ type: 'connected' }) },
|
|
77
|
+
message(ws, ctx, data) { ctx.ws.json({ echo: data.toString() }) },
|
|
78
|
+
})
|
|
79
|
+
app.ws('/chat', {
|
|
80
|
+
open(ws, ctx) { ctx.ws.join('room') },
|
|
81
|
+
message(ws, ctx, data) { ctx.ws.sendRoom('room', JSON.parse(data.toString())) },
|
|
82
|
+
})
|
|
62
83
|
app.onError((err, req, ctx) => Response.json({ error: err.message }, { status: 500 }))
|
|
63
84
|
|
|
85
|
+
// Debug: list all registered routes
|
|
86
|
+
console.log(app.routes())
|
|
87
|
+
// [ 'GET /hello/:name', 'POST /data', 'WS /echo', 'WS /chat' ]
|
|
88
|
+
|
|
89
|
+
// Cross-process WebSocket broadcast (Redis)
|
|
90
|
+
import { createHub } from 'weifuwu'
|
|
91
|
+
app.wsHub(createHub({ redis: redis() }))
|
|
92
|
+
|
|
64
93
|
const handler = app.handler()
|
|
65
94
|
const wsHandler = app.websocketHandler()
|
|
66
95
|
serve(handler, { port: 3000, websocket: wsHandler })
|
|
@@ -126,6 +155,25 @@ The `ctx` object accumulates properties as it passes through the middleware chai
|
|
|
126
155
|
| `compiledTailwindCss` | `ssr()` internal | `string` | Compiled CSS content (internal) |
|
|
127
156
|
| `tailwindCssUrl` | `ssr()` internal | `string` | Compiled CSS route URL (internal) |
|
|
128
157
|
|
|
158
|
+
### Type-Safe Context
|
|
159
|
+
|
|
160
|
+
Middleware-injected properties are **automatically typed** through chained `use()` calls:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const app = new Router()
|
|
164
|
+
.use(csrf()) // → Router<Context & { csrfToken: string }>
|
|
165
|
+
.use(requestId()) // → Router<Context & { csrfToken, requestId }>
|
|
166
|
+
.use(postgres()) // → Router<Context & { csrfToken, requestId, sql }>
|
|
167
|
+
|
|
168
|
+
app.get('/me', (_req, ctx) => {
|
|
169
|
+
ctx.csrfToken // ✅ string (IDE autocomplete)
|
|
170
|
+
ctx.requestId // ✅ string
|
|
171
|
+
ctx.sql`SELECT 1` // ✅ Sql<{}>
|
|
172
|
+
})
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Each module exports an `XxxInjected` type (e.g. `PostgresInjected`, `UserInjected`) for composing custom context types. `Context` is an interface — modules augment it via `declare module` for ambient compatibility.
|
|
176
|
+
|
|
129
177
|
---
|
|
130
178
|
|
|
131
179
|
## Module Patterns
|
|
@@ -165,6 +213,98 @@ app.use('/', a) // dashboard
|
|
|
165
213
|
|
|
166
214
|
---
|
|
167
215
|
|
|
216
|
+
## Request Tracing & Logging
|
|
217
|
+
|
|
218
|
+
Every request gets a **trace ID** via `AsyncLocalStorage`, injected into responses as `X-Trace-Id`. W3C `traceparent` headers are forwarded.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { currentTraceId } from 'weifuwu'
|
|
222
|
+
|
|
223
|
+
app.get('/api', (req, ctx) => {
|
|
224
|
+
console.log('Handling request', currentTraceId()) // f240a3f3-60e2-...
|
|
225
|
+
})
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Structured logging** — `logger({ format: 'json' })` outputs JSON to stderr with `traceId`, `timestamp`, `elapsed_ms`:
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{"level":"info","message":"request","method":"GET","path":"/api/users","status":200,"elapsed_ms":42,"traceId":"f240a3f3-...","timestamp":"2025-01-15T10:30:00.000Z"}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Default format is `'short'` (human-readable). `'combined'` includes query strings.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## AI Observability
|
|
239
|
+
|
|
240
|
+
Agent runs are **automatically logged** to `_agent_runs`. Dashboard endpoints provide analytics:
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
GET /agents/:id/runs?days=7 → [{ input, output, tokens_in, tokens_out, elapsed_ms, status, trace_id, ... }]
|
|
244
|
+
GET /agents/:id/runs/summary?days=7 → { total, success, error, success_rate, tokens_in, tokens_out, avg_elapsed_ms, p95_elapsed_ms }
|
|
245
|
+
GET /opencode/sessions/:id/usage → { message_count, tokens_in, tokens_out, tokens_total }
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Non-streaming runs log full token data; streaming runs log `status: 'stream'`.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Agent ↔ Messager Streaming
|
|
253
|
+
|
|
254
|
+
Agent replies in messager channels now stream **token-by-token** via WebSocket:
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
// Backend — automatic when agents are attached to messager
|
|
258
|
+
const msg = messager({ pg, agents: agent({ pg, model }) })
|
|
259
|
+
app.ws('/ws', msg.wsHandler())
|
|
260
|
+
// Agent replies stream to: hub.broadcast({ type: 'agent_stream', data: { token, full } })
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
// Frontend — React hook
|
|
265
|
+
import { useAgentStream } from 'weifuwu/react'
|
|
266
|
+
|
|
267
|
+
const { getAgentText, isAgentStreaming, stream } = useAgentStream({
|
|
268
|
+
wsPath: '/ws',
|
|
269
|
+
channelId: 1,
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Multi-round conversation context: the last 10 channel messages are automatically injected into agent calls.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Test Utilities
|
|
278
|
+
|
|
279
|
+
Chainable test helper for HTTP-level testing without starting a server:
|
|
280
|
+
|
|
281
|
+
```ts
|
|
282
|
+
import { testApp } from 'weifuwu'
|
|
283
|
+
|
|
284
|
+
const app = testApp()
|
|
285
|
+
app.use(postgres({ connection: TEST_DB }))
|
|
286
|
+
app.get('/users/:id', (req, ctx) => Response.json({ id: ctx.params.id, user: ctx.user }))
|
|
287
|
+
|
|
288
|
+
const res = await app
|
|
289
|
+
.getReq('/users/42?name=Alice')
|
|
290
|
+
.withUser({ id: 1 })
|
|
291
|
+
.header('X-Custom', 'val')
|
|
292
|
+
.body({ data: 'test' })
|
|
293
|
+
.send()
|
|
294
|
+
|
|
295
|
+
assert.equal(res.status, 200)
|
|
296
|
+
assert.deepEqual(await res.json(), { id: '42', user: { id: 1 } })
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
| Method | Description |
|
|
300
|
+
|--------|-------------|
|
|
301
|
+
| `app.getReq(path)` `postReq` `putReq` `patchReq` `deleteReq` | Start building a request |
|
|
302
|
+
| `.withUser(u)` `.withTenant(t)` `.with(ctx)` | Simulate middleware injection |
|
|
303
|
+
| `.header(k,v)` `.body(data)` `.rawBody(str)` | Set request properties |
|
|
304
|
+
| `.send()` → `TestResponse` | Execute and get `{ status, headers, json(), text() }` |
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
168
308
|
## Module Reference
|
|
169
309
|
|
|
170
310
|
### agent [β]
|
|
@@ -398,6 +538,29 @@ Restart=always
|
|
|
398
538
|
|
|
399
539
|
|
|
400
540
|
|
|
541
|
+
### graphql [β]
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
const handler: GraphQLHandler = () => ({
|
|
545
|
+
schema: `type Query { hello: String }`,
|
|
546
|
+
resolvers: { Query: { hello: () => 'world' } },
|
|
547
|
+
graphiql: true, // GET / returns GraphiQL IDE
|
|
548
|
+
maxDepth: 10, // max query nesting (default 10, 0 = disable)
|
|
549
|
+
timeout: 30_000, // execution timeout in ms
|
|
550
|
+
})
|
|
551
|
+
app.use('/graphql', graphql(handler))
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
| Option | Type | Default | Description |
|
|
555
|
+
|--------|------|---------|-------------|
|
|
556
|
+
| `schema` | `string \| GraphQLSchema` | — | SDL string or pre-built schema |
|
|
557
|
+
| `resolvers` | `object` | — | Resolver map |
|
|
558
|
+
| `rootValue` | `any` | — | Root value for queries |
|
|
559
|
+
| `context` | `(req, ctx) => object` | — | Per-request context factory |
|
|
560
|
+
| `graphiql` | `boolean` | `false` | Serve GraphiQL IDE at GET / |
|
|
561
|
+
| `maxDepth` | `number` | `10` | Max query nesting depth |
|
|
562
|
+
| `timeout` | `number` | `30_000` | Execution timeout (ms) |
|
|
563
|
+
|
|
401
564
|
### health [β]
|
|
402
565
|
|
|
403
566
|
```ts
|
|
@@ -584,52 +747,70 @@ app.use(pg) // injects ctx.sql
|
|
|
584
747
|
| `ssl` | `boolean\|object` | — | SSL options |
|
|
585
748
|
| `idle_timeout` | `number` | `30` | Idle timeout (seconds) |
|
|
586
749
|
| `connect_timeout` | `number` | `30` | Connection timeout |
|
|
750
|
+
| `statementTimeout` | `number` | `30_000` | Per-statement timeout (ms, 0 = disable) |
|
|
751
|
+
| `onQuery` | `(query, ms, rows) => void` | — | Query logging callback |
|
|
587
752
|
|
|
588
753
|
```ts
|
|
589
754
|
// Raw SQL via tagged template
|
|
590
755
|
await pg.sql`SELECT * FROM users WHERE email = ${email}`
|
|
591
756
|
|
|
592
|
-
//
|
|
593
|
-
import {
|
|
757
|
+
// Define a table — one API, sql pre-bound
|
|
758
|
+
import { serial, text, boolean, timestamps } from 'weifuwu'
|
|
594
759
|
|
|
595
|
-
const users =
|
|
760
|
+
const users = pg.table('_users', {
|
|
596
761
|
id: serial('id').primaryKey(),
|
|
597
762
|
name: text('name').notNull(),
|
|
598
763
|
email: text('email').unique().notNull(),
|
|
599
764
|
active: boolean('active').default(true),
|
|
600
765
|
...timestamps(),
|
|
601
766
|
})
|
|
602
|
-
await users.create(
|
|
603
|
-
await users.createIndex(
|
|
604
|
-
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
await
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
767
|
+
await users.create() // DDL — no need to pass sql
|
|
768
|
+
await users.createIndex('email')
|
|
769
|
+
|
|
770
|
+
// CRUD — sql already bound
|
|
771
|
+
await users.insert({ name: 'Alice' })
|
|
772
|
+
const { count, data } = await users.readMany({ role: 'admin' }, { orderBy: { name: 'asc' }, limit: 10 })
|
|
773
|
+
await users.upsert({ email: 'alice@test.com' }, 'email')
|
|
774
|
+
|
|
775
|
+
// Reuse schema without redefining fields
|
|
776
|
+
import { pgTable } from 'weifuwu'
|
|
777
|
+
const usersSchema = pgTable('_users', { id: serial('id'), name: text('name') }) // define once
|
|
778
|
+
const users = pg.table(usersSchema) // bind — no field duplication
|
|
779
|
+
|
|
780
|
+
// Transactions — with auto-retry on deadlock/serialization failure
|
|
615
781
|
await pg.transaction(async (sql) => {
|
|
616
|
-
const
|
|
617
|
-
return
|
|
618
|
-
})
|
|
782
|
+
const txUsers = users.withSql(sql)
|
|
783
|
+
return txUsers.insert({ name: 'Bob' })
|
|
784
|
+
}, { maxRetries: 3 })
|
|
619
785
|
|
|
620
786
|
// Soft delete — automatic if deleted_at column exists
|
|
621
|
-
await
|
|
622
|
-
await
|
|
623
|
-
await
|
|
787
|
+
await users.delete(1) // SET deleted_at = NOW()
|
|
788
|
+
await users.hardDelete(1) // DELETE FROM
|
|
789
|
+
await users.read(1) // auto-filters deleted_at IS NULL (use withDeleted: true to include)
|
|
624
790
|
|
|
625
791
|
// JSONB queries
|
|
626
792
|
const logs = pg.table('logs', { meta: jsonb<{ service: string }>('meta') })
|
|
627
793
|
await logs.readMany(contains('meta', { service: 'auth' }))
|
|
628
794
|
|
|
795
|
+
// Connection pool visibility
|
|
796
|
+
console.log(pg.poolStats()) // { active: 3, idle: 7, waiting: 0, max: 10 }
|
|
797
|
+
|
|
798
|
+
// Migration tracking
|
|
799
|
+
await pg.migrate() // creates _weifuwu_migrations
|
|
800
|
+
await pg.markMigrated('myModule') // idempotent
|
|
801
|
+
const done = await pg.isMigrated('myModule')
|
|
802
|
+
|
|
629
803
|
// Partitioned tables
|
|
630
804
|
await logs.create({ partitionBy: partitionBy('range', 'created_at') })
|
|
631
805
|
```
|
|
632
806
|
|
|
807
|
+
**When to use pgTable vs pg.table:**
|
|
808
|
+
| API | Use when |
|
|
809
|
+
|-----|---------|
|
|
810
|
+
| `pg.table('t', cols)` | You have `pg` available (factory, handler, migrate) |
|
|
811
|
+
| `pg.table(schema)` | Reusing a schema without duplicating field definitions |
|
|
812
|
+
| `pgTable('t', cols)` | No `pg` reference (utility modules, standalone schema files) |
|
|
813
|
+
|
|
633
814
|
| Column builder | Type | Notes |
|
|
634
815
|
|---------------|------|-------|
|
|
635
816
|
| `serial(name)` | `number` | Auto-increment |
|
|
@@ -644,27 +825,27 @@ await logs.create({ partitionBy: partitionBy('range', 'created_at') })
|
|
|
644
825
|
|
|
645
826
|
**Column modifiers:** `.primaryKey()`, `.notNull()`, `.nullable()`, `.default(val)`, `.unique()`, `.references(table, column?, onDelete?)`.
|
|
646
827
|
|
|
647
|
-
**
|
|
828
|
+
**CRUD methods:**
|
|
648
829
|
|
|
649
830
|
| Method | Description |
|
|
650
831
|
|--------|-------------|
|
|
651
832
|
| `insert(data)` | INSERT + RETURNING \*, returns the inserted row |
|
|
652
833
|
| `insertMany(data)` | Bulk INSERT + RETURNING \*, returns rows |
|
|
653
|
-
| `read(id, opts?)` | SELECT by primary key
|
|
834
|
+
| `read(id, opts?)` | SELECT by detected primary key + auto soft-delete filter |
|
|
654
835
|
| `readMany(where?, opts?)` | Filtered query with `{ count, data }` — auto-filters soft-deleted |
|
|
655
|
-
| `update(id, data)` | UPDATE by
|
|
836
|
+
| `update(id, data)` | UPDATE by primary key + RETURNING \*, returns updated row |
|
|
656
837
|
| `updateMany(where, data)` | Bulk UPDATE, returns affected row count |
|
|
657
838
|
| `delete(id)` | Soft delete if `deleted_at` exists, else hard delete |
|
|
658
839
|
| `hardDelete(id)` | Always DELETE FROM |
|
|
659
840
|
| `deleteMany(where)` | Soft bulk delete if `deleted_at` exists |
|
|
660
841
|
| `hardDeleteMany(where)` | Always DELETE FROM |
|
|
661
842
|
| `upsert(data, conflict)` | INSERT ON CONFLICT DO UPDATE, returns row |
|
|
662
|
-
| `count(where?)` | SELECT COUNT(\*) |
|
|
843
|
+
| `count(where?)` | SELECT COUNT(\*) — auto-filters soft-deleted |
|
|
663
844
|
| `create(opts?)` | CREATE TABLE IF NOT EXISTS |
|
|
664
845
|
| `drop(opts?)` | DROP TABLE IF EXISTS |
|
|
665
846
|
| `createIndex(columns, opts?)` | CREATE INDEX |
|
|
666
847
|
| `createUniqueIndex(columns)` | CREATE UNIQUE INDEX |
|
|
667
|
-
| `withSql(sql)` | Returns
|
|
848
|
+
| `withSql(sql)` | Returns copy bound to a different sql (for transactions) |
|
|
668
849
|
|
|
669
850
|
**Where helpers** — composable query conditions:
|
|
670
851
|
|
|
@@ -1120,7 +1301,8 @@ Every public symbol can be imported from `'weifuwu'`:
|
|
|
1120
1301
|
```ts
|
|
1121
1302
|
serve, createTestServer, Router, ssr,
|
|
1122
1303
|
Context, Handler, Middleware, ErrorHandler, ServeOptions, Server,
|
|
1123
|
-
loadEnv
|
|
1304
|
+
loadEnv, testApp, TestApp, TestRequest, TestResponse,
|
|
1305
|
+
currentTraceId, currentTrace, runWithTrace, traceElapsed, TraceContext,
|
|
1124
1306
|
```
|
|
1125
1307
|
|
|
1126
1308
|
### Middleware modules
|
|
@@ -1136,6 +1318,7 @@ preferences, serveStatic
|
|
|
1136
1318
|
postgres, PostgresOptions, PostgresClient,
|
|
1137
1319
|
redis, RedisOptions, RedisClient,
|
|
1138
1320
|
queue, QueueOptions, QueueJob, Queue,
|
|
1321
|
+
PostgresInjected, RedisInjected, QueueInjected,
|
|
1139
1322
|
// Schema helpers — importable alongside postgres:
|
|
1140
1323
|
pgTable, SQL, sql,
|
|
1141
1324
|
ColumnBuilder, serial, uuid, text, integer, boolean, boolean_, timestamptz, jsonb, textArray, vector,
|
|
@@ -1151,8 +1334,10 @@ TsxContext, useLoaderData,
|
|
|
1151
1334
|
useWebsocket, useAction, useFetch, useQueryState, createStore,
|
|
1152
1335
|
Link, useNavigate, useNavigating, addInterceptor,
|
|
1153
1336
|
useLocale, useTheme, applyTheme, useFlashMessage,
|
|
1337
|
+
useAgentStream,
|
|
1154
1338
|
Head
|
|
1155
1339
|
```
|
|
1340
|
+
export type { UseAgentStreamOptions, UseAgentStreamReturn, AgentStreamState } from 'weifuwu/react'
|
|
1156
1341
|
|
|
1157
1342
|
### AI SDK (re-exported from `ai`)
|
|
1158
1343
|
|
|
@@ -1169,8 +1354,12 @@ preferences, health, analytics, seo, seoMiddleware, seoTags,
|
|
|
1169
1354
|
user, mailer, graphql, aiStream, runWorkflow,
|
|
1170
1355
|
logdb, messager, agent, iii, createWorker, registerWorker,
|
|
1171
1356
|
opencode, deploy, defineConfig,
|
|
1357
|
+
testApp, TestApp, TestRequest, TestResponse,
|
|
1172
1358
|
getCookies, setCookie, deleteCookie,
|
|
1173
|
-
createSSEStream, formatSSE, formatSSEData
|
|
1359
|
+
createSSEStream, formatSSE, formatSSEData,
|
|
1360
|
+
currentTraceId, currentTrace, runWithTrace, traceElapsed,
|
|
1361
|
+
createHub, Hub, HubOptions,
|
|
1362
|
+
DEFAULT_MAX_BODY, MIGRATIONS_TABLE,
|
|
1174
1363
|
```
|
|
1175
1364
|
|
|
1176
1365
|
---
|
package/cli/template/index.ts
CHANGED
|
@@ -3,6 +3,4 @@ import { app } from './app.ts'
|
|
|
3
3
|
|
|
4
4
|
loadEnv()
|
|
5
5
|
const port = Number(process.env.PORT) || 3000
|
|
6
|
-
|
|
7
|
-
await server.ready
|
|
8
|
-
console.log(`Listening on http://localhost:${server.port}`)
|
|
6
|
+
serve(app.handler(), { port, websocket: app.websocketHandler() })
|