weifuwu 0.5.1 → 0.7.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 CHANGED
@@ -19,7 +19,12 @@ Everything follows the same `(req, ctx) => Response` contract. The Router handle
19
19
  - **GraphQL** — `graphql(handler)` sub-Router with GraphiQL IDE
20
20
  - **AI streaming** — `ai(handler)` sub-Router via Vercel AI SDK
21
21
  - **AI workflows** — `workflow(handler)` sub-Router — intent-to-execution pipelines with `tool()` + SSE
22
- - **PostgreSQL** — `postgres()` — zod-to-DDL, auto-migration, 6 CRUD methods, `ctx.sql` escape hatch
22
+ - **AI Agent** — `agent()` — server-side AI agents with chat/workflow/knowledge types, OpenAI-compatible, Ollama-ready
23
+ - **Messaging** — `messager()` — real-time chat with channels, WebSocket, agent routing, webhook support
24
+ - **Tenant BaaS** — `tenant()` — multi-tenant dynamic tables, auto REST + GraphQL, row-level isolation, pgvector/HNSW
25
+ - **Redis** — `redis()` — ioredis client, `ctx.redis`, middleware
26
+ - **Queue** — `queue()` — Redis-backed job queue with immediate, delayed, and cron scheduling
27
+ - **Auth** — `user()` — register/login/JWT + OAuth2 Server (authorization code + PKCE + client_credentials)
23
28
  - **Static files** — `serveStatic()` with ETag, 304, MIME, directory index
24
29
  - **Cookie** — `getCookies()`, `setCookie()`, `deleteCookie()` — immutable
25
30
  - **Error handling** — global `onError()`
@@ -258,14 +263,366 @@ await pg.close() // explicit close
258
263
  | `id: z.string().uuid().optional()` | `UUID PRIMARY KEY DEFAULT gen_random_uuid()` |
259
264
  | `id: z.string()` | `TEXT PRIMARY KEY` (you pass the value) |
260
265
 
261
- ## WebSocket
266
+ ## Authentication
267
+
268
+ Built-in user management — password login, JWT, and OAuth2 Server. Zero config beyond PostgreSQL and a secret key.
262
269
 
263
270
  ```ts
271
+ import { serve, Router, postgres, user } from 'weifuwu'
272
+
264
273
  const app = new Router()
265
- .ws('/chat/:room', {
266
- open(ws, ctx) {
267
- ws.send(`Connected to room: ${ctx.params.room}`)
268
- },
274
+ const pg = postgres()
275
+ await pg.migrate()
276
+
277
+ const auth = user({ pg, jwtSecret: process.env.JWT_SECRET! })
278
+
279
+ // POST /auth/register { email, password, name }
280
+ // POST /auth/login { email, password }
281
+ // GET /auth/oauth/authorize?client_id=...&redirect_uri=...&response_type=code
282
+ // POST /auth/oauth/consent
283
+ // POST /auth/oauth/token (grant_type=authorization_code|client_credentials)
284
+ app.use('/auth', auth.router())
285
+
286
+ // Protected routes — verifies JWT, sets ctx.user
287
+ app.get('/me', auth.middleware(), async (req, ctx) => {
288
+ return Response.json(ctx.user)
289
+ // { id, email, name, role }
290
+ })
291
+ ```
292
+
293
+ Password hashing uses `crypto.scryptSync` + `timingSafeEqual` (Node.js built-in, zero deps). JWT tokens use the `jsonwebtoken` package. The users table (`_users` by default) is auto-created on first `migrate()`.
294
+
295
+ ### OAuth2 Server
296
+
297
+ Enable OAuth2 Server to let third-party apps (SPA, mobile, microservices) authenticate users through your app.
298
+
299
+ ```ts
300
+ const auth = user({
301
+ pg,
302
+ jwtSecret: process.env.JWT_SECRET!,
303
+ oauth2: { server: true },
304
+ })
305
+
306
+ await auth.migrate() // creates _users + _oauth2_clients + _oauth2_codes + _oauth2_tokens
307
+
308
+ // Register a client app (programmatic — CLI, admin UI, seed script)
309
+ const client = await auth.registerClient({
310
+ name: 'My SPA',
311
+ redirectUris: ['https://myapp.com/callback'],
312
+ })
313
+ // → { clientId, clientSecret, name, redirectUris }
314
+
315
+ // Use auth middleware to protect routes — OAuth2 JWT tokens work seamlessly
316
+ app.get('/api/data', auth.middleware(), handler)
317
+ ```
318
+
319
+ #### Supported Grant Types
320
+
321
+ | Grant | Use Case | PKCE |
322
+ |-------|----------|------|
323
+ | `authorization_code` (with client_secret) | Server-side apps | Optional |
324
+ | `authorization_code` (with `code_challenge`/`code_verifier`) | SPA / Mobile apps | Required |
325
+ | `client_credentials` | Machine-to-machine | — |
326
+
327
+ #### Flow (Authorization Code + PKCE)
328
+
329
+ ```
330
+ 1. 第三方 App 引导用户:
331
+ GET /oauth/authorize?client_id=xxx&redirect_uri=https://app.com/cb
332
+ &response_type=code&code_challenge=S256&state=yyy
333
+
334
+ 2. 用户未登录 → 302 到 /login?redirect=... → 登录后自动回到授权页
335
+
336
+ 3. 用户确认授权 → POST /oauth/consent { approve: true, client_id, ... }
337
+ 302 redirect_uri?code=xxx&state=yyy
338
+
339
+ 4. 第三方 App POST /oauth/token
340
+ { grant_type: authorization_code, code, client_id, client_secret,
341
+ redirect_uri, code_verifier }
342
+ → { access_token, token_type: "Bearer", expires_in, refresh_token }
343
+
344
+ 5. access_token 是标准 JWT,auth.middleware() 和 auth.verify() 直接可用
345
+ ```
346
+
347
+ #### Client Management
348
+
349
+ ```ts
350
+ const client = await auth.registerClient({ name, redirectUris })
351
+ const found = await auth.getClient(client.clientId)
352
+ await auth.revokeClient(client.clientId)
353
+ ```
354
+
355
+ #### Using OAuth2 Tokens with the Built-in Auth Middleware
356
+
357
+ OAuth2 Server 签发的 `access_token` 与密码登录的 JWT 使用同一 `jwtSecret`,payload 向下兼容(`sub`、`email`、`role`),所以 `auth()` 无需任何修改即可验证 OAuth2 签发的 token:
358
+
359
+ ```ts
360
+ import { auth } from 'weifuwu'
361
+
362
+ // 同一个 auth() 中间件同时支持密码登录 JWT 和 OAuth2 JWT
363
+ app.get('/api', auth({ verify: (token) => auth.verify(token) }), handler)
364
+ ```
365
+
366
+ For `client_credentials` tokens (machine-to-machine), `verify()` returns `null` since no user is associated.
367
+
368
+ ## Tenant BaaS
369
+
370
+ Built-in multi-tenant backend-as-a-service — define tables at runtime via API, get RESTful CRUD + GraphQL automatically, with row-level tenant isolation.
371
+
372
+ ```ts
373
+ import { serve, Router, postgres, user, tenant } from 'weifuwu'
374
+
375
+ const pg = postgres()
376
+ const u = user({ pg, jwtSecret: process.env.JWT_SECRET! })
377
+ const t = tenant({ pg, usersTable: '_users' })
378
+
379
+ await pg.migrate()
380
+ await u.migrate()
381
+ await t.migrate() // creates _tenants, _tenant_members, _user_tables
382
+
383
+ const app = new Router()
384
+ app.use('/auth', u.router())
385
+ app.use('/api', u.middleware()) // → ctx.user
386
+ app.use('/api', t.middleware()) // → ctx.tenant
387
+ app.use('/api', t.router()) // → management + data CRUD
388
+ app.use('/graphql', t.graphql()) // → dynamic GraphQL
389
+ ```
390
+
391
+ ### System tables
392
+
393
+ | Table | Purpose |
394
+ |-------|---------|
395
+ | `_tenants` | Tenant records (`id TEXT PK DEFAULT gen_random_uuid()`, `name`, `created_at`) |
396
+ | `_tenant_members` | User-tenant membership (`tenant_id`, `user_id`, `role`) |
397
+ | `_user_tables` | Dynamic table definitions (`tenant_id`, `slug`, `fields JSONB`) |
398
+
399
+ ### Dynamic table API
400
+
401
+ Create a table at runtime:
402
+
403
+ ```json
404
+ POST /api/tables
405
+ {
406
+ "slug": "articles",
407
+ "fields": [
408
+ { "name": "title", "type": "string", "required": true },
409
+ { "name": "content", "type": "text" },
410
+ { "name": "status", "type": "enum", "options": ["draft", "published"], "default": "draft" },
411
+ { "name": "views", "type": "integer", "default": 0 },
412
+ { "name": "embedding", "type": "vector", "dimensions": 1536, "index": "hnsw" }
413
+ ]
414
+ }
415
+ ```
416
+
417
+ → Creates a PostgreSQL table with `id SERIAL PK`, `tenant_id TEXT NOT NULL`, and the specified columns, plus indexes. The table name is internally scoped to the tenant.
418
+
419
+ ### Field types
420
+
421
+ | type | PostgreSQL | Index support |
422
+ |------|-----------|---------------|
423
+ | `string` | `TEXT` | `true`, `unique` |
424
+ | `integer` | `INTEGER` | `true`, `desc`, `unique` |
425
+ | `float` | `DOUBLE PRECISION` | `true`, `desc` |
426
+ | `boolean` | `BOOLEAN` | `true` |
427
+ | `text` | `TEXT` | `true` |
428
+ | `datetime` | `TIMESTAMPTZ` | `true`, `desc` |
429
+ | `date` | `DATE` | `true`, `desc` |
430
+ | `enum` | `TEXT` (with validation) | `true` |
431
+ | `json` | `JSONB` | `gin` |
432
+ | `vector` | `vector(n)` (pgvector) | `hnsw` (HNSW, vector_cosine_ops) |
433
+
434
+ ### Relationships
435
+
436
+ Declare a foreign key via the `relation` field:
437
+
438
+ ```json
439
+ { "name": "article_id", "type": "integer", "relation": { "table": "articles", "onDelete": "cascade" } }
440
+ ```
441
+
442
+ Supported relationship patterns:
443
+
444
+ | Pattern | Detection | REST | GraphQL |
445
+ |---------|-----------|------|---------|
446
+ | **belongs_to** | Field with `relation` | — | `comment.article` resolver |
447
+ | **has_many** | Another table has a relation pointing here | `GET /api/articles/:id/comments` | `article.comments` resolver |
448
+ | **M2M** | Junction table with exactly two relation fields | `GET /api/articles/:id/tags` (bypasses junction) | `article.tags` / `tag.articles` resolver |
449
+ | **Self-ref** | Relation field pointing to same table | — | With depth control |
450
+
451
+ ### RESTful API
452
+
453
+ All routes require `ctx.tenant` (set by `t.middleware()`). All queries automatically filter by `tenant_id`.
454
+
455
+ | Route | Method | Description |
456
+ |-------|--------|-------------|
457
+ | `/sys/tenants` | POST | Create tenant, caller becomes admin |
458
+ | `/sys/tenants` | GET | List user's tenants |
459
+ | `/sys/tenants/invite` | POST | Invite user by email (admin) |
460
+ | `/sys/tenants/members/:userId` | DELETE | Remove member (admin) |
461
+ | `/sys/tables` | POST/GET | Create / list dynamic tables |
462
+ | `/sys/tables/:slug` | GET/PATCH/DELETE | Get schema / add fields / drop table |
463
+ | `/:slug` | GET | List rows (limit, offset, sort) |
464
+ | `/:slug` | POST | Create row |
465
+ | `/:slug/:id` | GET/PATCH/DELETE | Get / update / delete row |
466
+ | `/:slug/:id/:_nested` | GET | List related rows (has_many / M2M) |
467
+ | `/:slug/:id/:_nested` | POST | Create related row (auto-fills relation field) |
468
+
469
+ ### Vector search
470
+
471
+ ```http
472
+ GET /api/articles?search_vector=[0.1,0.2,...]&search_field=embedding&search_limit=10
473
+ ```
474
+
475
+ Returns rows ordered by cosine distance (`<=>`), includes `_distance` field. Supports `l2` (`<->`) and `ip` (`<#>`):
476
+
477
+ ```http
478
+ GET /api/articles?search_vector=[...]&search_field=embedding&search_distance=l2
479
+ ```
480
+
481
+ ### GraphQL
482
+
483
+ Dynamic GraphQL schema generated per-request based on the authenticated tenant's tables:
484
+
485
+ ```graphql
486
+ type Article {
487
+ id: ID!
488
+ title: String!
489
+ content: String
490
+ status: String
491
+ comments(limit: Int, offset: Int): [Comment!]!
492
+ }
493
+
494
+ type Query {
495
+ articles(limit: Int, offset: Int): [Article!]!
496
+ getArticle(id: ID!): Article
497
+ }
498
+
499
+ type Mutation {
500
+ createArticle(data: CreateArticleInput!): Article!
501
+ updateArticle(id: ID!, data: PatchArticleInput!): Article!
502
+ deleteArticle(id: ID!): Boolean!
503
+ }
504
+ ```
505
+
506
+ Built with `graphql-js` native constructors (`GraphQLObjectType`), no SDL generation, no `makeExecutableSchema`.
507
+
508
+ ### Middleware
509
+
510
+ `t.middleware()` extracts the tenant context:
511
+
512
+ 1. Requires `ctx.user` (from `u.middleware()`)
513
+ 2. Looks up user's tenant memberships
514
+ 3. Single tenant → automatically set `ctx.tenant`
515
+ 4. Multiple tenants → require `X-Tenant-ID` header, return 300 with tenant list if missing
516
+ 5. No tenants → 403
517
+
518
+ ### Tenant lifecycle
519
+
520
+ ```ts
521
+ const t = tenant({ pg, usersTable: '_users' })
522
+
523
+ // Create a tenant — the caller becomes admin
524
+ const tenant = await (await fetch('http://localhost/api/sys/tenants', {
525
+ method: 'POST',
526
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer <jwt>' },
527
+ body: JSON.stringify({ name: 'Acme Corp' }),
528
+ })).json()
529
+ // → { id: "uuid", name: "Acme Corp", created_at: "..." }
530
+
531
+ // Invite a member
532
+ await fetch('http://localhost/api/sys/tenants/invite', {
533
+ method: 'POST',
534
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer <jwt>' },
535
+ body: JSON.stringify({ email: 'colleague@acme.com', role: 'member' }),
536
+ })
537
+ ```
538
+
539
+ ## AI Agent
540
+
541
+ Server-side AI agents with OpenAI-compatible API. Built-in chat, workflow (tool-calling), and knowledge (RAG) types. Works out of the box with Ollama or any OpenAI-compatible provider.
542
+
543
+ ```ts
544
+ import { agent } from 'weifuwu'
545
+
546
+ const agents = agent({ pg })
547
+
548
+ await agents.migrate()
549
+ app.use('/api', agents.router())
550
+ ```
551
+
552
+ | Type | Description | Execution |
553
+ |------|-------------|-----------|
554
+ | `chat` | Pure conversation | `streamText()` / `generateText()` |
555
+ | `workflow` | Tool-calling agent | `streamText({ tools })` |
556
+
557
+ ### Knowledge (RAG)
558
+
559
+ Add documents to any agent — `searchKnowledge` tool auto-injected:
560
+
561
+ ```ts
562
+ await agents.addKnowledge(agentId, 'Title', 'Document content...')
563
+ // The agent automatically calls searchKnowledge when answering
564
+ ```
565
+
566
+ ### Streaming
567
+
568
+ ```http
569
+ POST /agents/:id/run { input: "hello", stream: true }
570
+ → event-stream (fullStream SSE: text-delta, tool-call, tool-result, finish)
571
+ ```
572
+
573
+ ### Programmatic API
574
+
575
+ ```ts
576
+ const result = await agents.run(agentId, { input: 'hello', stream: false })
577
+ // { output: "Hello!", elapsed: 1234 }
578
+ ```
579
+
580
+ ## Messager
581
+
582
+ Real-time chat with channels, WebSocket, and agent routing.
583
+
584
+ ```ts
585
+ import { messager, agent } from 'weifuwu'
586
+
587
+ const agents = agent({ pg })
588
+ const msg = messager({ pg, agents })
589
+
590
+ await msg.migrate()
591
+ app.use('/api', msg.router())
592
+ app.ws('/ws', u.middleware(), msg.wsHandler())
593
+ ```
594
+
595
+ ### Channels
596
+
597
+ ```http
598
+ POST /channels name, type (channel|dm), members
599
+ GET /channels
600
+ GET /channels/:id
601
+ ```
602
+
603
+ ### Messages
604
+
605
+ ```http
606
+ GET /channels/:id/messages ?limit=50&before={id}
607
+ POST /channels/:id/messages content, sender_type, type
608
+ POST /channels/:id/read last_message_id
609
+ ```
610
+
611
+ ### WebSocket
612
+
613
+ ```json
614
+ { "type": "message", "channel_id": 1, "content": "Hi" }
615
+ { "type": "typing", "channel_id": 1, "is_typing": true }
616
+ { "type": "read", "channel_id": 1, "last_message_id": 42 }
617
+ ```
618
+
619
+ ### Programmatic send
620
+
621
+ ```ts
622
+ await msg.send(channelId, 'System message', { sender_type: 'system' })
623
+ ```
624
+
625
+ ## WebSocket
269
626
  message(ws, ctx, data) {
270
627
  ws.send(`echo: ${data}`)
271
628
  },
@@ -654,6 +1011,48 @@ const app = new Router()
654
1011
 
655
1012
  Returns `{ stop, port, hostname, ready }`.
656
1013
 
1014
+ ### `user(options)`
1015
+
1016
+ | Option | Default | Description |
1017
+ |--------|---------|-------------|
1018
+ | `pg` | — | PostgreSQL client from `postgres()` |
1019
+ | `jwtSecret` | — | Secret key for JWT signing |
1020
+ | `table` | `'_users'` | Users table name |
1021
+ | `expiresIn` | `'24h'` | JWT expiration |
1022
+ | `oauth2.server` | `false` | Enable OAuth2 Server |
1023
+
1024
+ Returns `UserModule` — `{ router, middleware, migrate, register, login, verify, registerClient, getClient, revokeClient, close }`.
1025
+
1026
+ ### `tenant(options)`
1027
+
1028
+ | Option | Default | Description |
1029
+ |--------|---------|-------------|
1030
+ | `pg` | — | PostgreSQL client from `postgres()` |
1031
+ | `usersTable` | — | Users table name (matching the `table` option passed to `user()`) |
1032
+
1033
+ Returns `TenantModule` — `{ migrate, middleware, router, graphql, close }`.
1034
+
1035
+ ### `agent(options)`
1036
+
1037
+ | Option | Default | Description |
1038
+ |--------|---------|-------------|
1039
+ | `pg` | — | PostgreSQL client from `postgres()` |
1040
+ | `model` | env `OPENAI_MODEL` → Ollama | `LanguageModel` from ai SDK |
1041
+ | `embeddingModel` | env `OPENAI_EMBEDDING_MODEL` → Ollama | `EmbeddingModel` for knowledge RAG |
1042
+ | `embeddingDimension` | `1024` | Vector dimension for pgvector |
1043
+ | `tools` | — | Tools for workflow-type agents (ai SDK `Tool` objects) |
1044
+
1045
+ Returns `AgentModule` — `{ migrate, router, run, addKnowledge, close }`.
1046
+
1047
+ ### `messager(options)`
1048
+
1049
+ | Option | Default | Description |
1050
+ |--------|---------|-------------|
1051
+ | `pg` | — | PostgreSQL client from `postgres()` |
1052
+ | `agents` | — | `AgentModule` instance (enables agent message routing) |
1053
+
1054
+ Returns `MessagerModule` — `{ migrate, router, wsHandler, send, close }`.
1055
+
657
1056
  ### `tsx(options)`
658
1057
 
659
1058
  | Option | Default | Description |
@@ -690,6 +1089,12 @@ Returns `Promise<Router>`.
690
1089
  | Import | Description |
691
1090
  |--------|-------------|
692
1091
  | `postgres(options?)` | PostgreSQL connection + auto-migration + 6 CRUD methods |
1092
+ | `redis(options?)` | Redis client (ioredis) — injects `ctx.redis` |
1093
+ | `queue(options?)` | Redis-backed job queue — immediate, delayed, cron scheduling |
1094
+ | `user(options)` | Built-in authentication (password + OAuth2 Server + JWT, middleware) |
1095
+ | `tenant(options)` | Multi-tenant BaaS — dynamic tables, REST + GraphQL auto-generation, row-level isolation |
1096
+ | `agent(options)` | AI Agent — chat/workflow/knowledge, Ollama-ready, programmatic API |
1097
+ | `messager(options)` | Real-time messaging — channels, WebSocket, agent routing, webhooks |
693
1098
  | `graphql(handler)` | GraphQL endpoint (GET/POST + GraphiQL) |
694
1099
  | `ai(handler)` | AI streaming endpoint (POST) |
695
1100
  | `workflow(handler)` | Workflow engine (POST + SSE) |
@@ -0,0 +1,2 @@
1
+ import type { AgentOptions, AgentModule } from './types.ts';
2
+ export declare function agent(options: AgentOptions): AgentModule;
@@ -0,0 +1,2 @@
1
+ export { agent } from './client.ts';
2
+ export type { AgentOptions, AgentModule, AgentConfig, RunParams, RunResult } from './types.ts';
@@ -0,0 +1,6 @@
1
+ import type { Sql } from 'postgres';
2
+ export interface MigrateOptions {
3
+ sql: Sql<{}>;
4
+ embeddingDimension: number;
5
+ }
6
+ export declare function migrate(opts: MigrateOptions): Promise<void>;
@@ -0,0 +1,12 @@
1
+ import type { Sql } from 'postgres';
2
+ import { Router } from '../router.ts';
3
+ import type { RunParams } from './types.ts';
4
+ interface RestDeps {
5
+ sql: Sql<{}>;
6
+ runner: {
7
+ run: (agentId: number, params: RunParams) => Promise<any>;
8
+ addKnowledge: (agentId: number, title: string, content: string) => Promise<any>;
9
+ };
10
+ }
11
+ export declare function buildRouter(deps: RestDeps): Router;
12
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { LanguageModel, EmbeddingModel, Tool } from 'ai';
2
+ import type { Sql } from 'postgres';
3
+ import type { RunParams, RunResult, KnowledgeDoc } from './types.ts';
4
+ interface RunnerDeps {
5
+ sql: Sql<{}>;
6
+ getModel: () => LanguageModel;
7
+ getEmbeddingModel: () => EmbeddingModel;
8
+ userTools?: Record<string, Tool>;
9
+ }
10
+ export declare function createRunner(deps: RunnerDeps): {
11
+ run: (agentId: number, params: RunParams) => Promise<RunResult>;
12
+ addKnowledge: (agentId: number, title: string, content: string) => Promise<KnowledgeDoc>;
13
+ };
14
+ export {};
@@ -0,0 +1,51 @@
1
+ import type { LanguageModel, EmbeddingModel, Tool } from 'ai';
2
+ export interface AgentConfig {
3
+ id: number;
4
+ tenant_id: string | null;
5
+ name: string;
6
+ description: string;
7
+ type: 'chat' | 'workflow';
8
+ model: string;
9
+ system_prompt: string;
10
+ owner_id: number;
11
+ active: boolean;
12
+ created_at: string;
13
+ updated_at: string;
14
+ }
15
+ export interface KnowledgeDoc {
16
+ id: number;
17
+ agent_id: number;
18
+ title: string;
19
+ content: string;
20
+ embedding?: number[];
21
+ metadata: Record<string, unknown>;
22
+ created_at: string;
23
+ }
24
+ export interface RunParams {
25
+ input: string;
26
+ stream?: boolean;
27
+ messages?: Array<{
28
+ role: string;
29
+ content: string;
30
+ }>;
31
+ }
32
+ export type RunResult = {
33
+ output: string;
34
+ elapsed: number;
35
+ } | {
36
+ stream: ReadableStream<Uint8Array>;
37
+ };
38
+ export interface AgentOptions {
39
+ pg: any;
40
+ model?: LanguageModel;
41
+ embeddingModel?: EmbeddingModel;
42
+ embeddingDimension?: number;
43
+ tools?: Record<string, Tool>;
44
+ }
45
+ export interface AgentModule {
46
+ migrate: () => Promise<void>;
47
+ router: () => any;
48
+ run: (agentId: number, params: RunParams) => Promise<RunResult>;
49
+ addKnowledge: (agentId: number, title: string, content: string) => Promise<KnowledgeDoc>;
50
+ close: () => Promise<void>;
51
+ }
package/dist/index.d.ts CHANGED
@@ -27,3 +27,15 @@ export { tool, createWorkflowEngine, createSSEManager, generateWorkflow, workflo
27
27
  export type { Tool, Workflow, WorkflowEngine, WorkflowState, SSEEvent, WorkflowOptions, WorkflowHandler } from './workflow/index.ts';
28
28
  export { postgres } from './postgres/index.ts';
29
29
  export type { PostgresOptions, PostgresClient, TableProxy, ListOptions, TableBuilder } from './postgres/types.ts';
30
+ export { user } from './user/index.ts';
31
+ export type { UserOptions, UserData, UserModule, OAuth2Client } from './user/types.ts';
32
+ export { redis } from './redis/index.ts';
33
+ export type { RedisOptions, RedisClient } from './redis/types.ts';
34
+ export { queue } from './queue/index.ts';
35
+ export type { QueueOptions, QueueJob, Queue } from './queue/types.ts';
36
+ export { tenant } from './tenant/index.ts';
37
+ export type { TenantOptions, TenantModule, TenantContext, FieldDef, FieldType, RelationDef, UserTableRow } from './tenant/types.ts';
38
+ export { agent } from './agent/index.ts';
39
+ export type { AgentOptions, AgentModule, AgentConfig, RunParams, RunResult, KnowledgeDoc } from './agent/types.ts';
40
+ export { messager } from './messager/index.ts';
41
+ export type { MessagerOptions, MessagerModule, Channel, ChannelMember, Message } from './messager/types.ts';