weifuwu 0.5.0 → 0.6.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 +118 -5
- package/dist/index.d.ts +6 -0
- package/dist/index.js +11392 -4
- package/dist/postgres/types.d.ts +1 -1
- package/dist/queue/index.d.ts +2 -0
- package/dist/queue/types.d.ts +32 -0
- package/dist/redis/index.d.ts +3 -0
- package/dist/redis/types.d.ts +16 -0
- package/dist/user/client.d.ts +2 -0
- package/dist/user/index.d.ts +2 -0
- package/dist/user/migrate.d.ts +6 -0
- package/dist/user/oauth2.d.ts +20 -0
- package/dist/user/types.d.ts +54 -0
- package/dist/workflow/engine.d.ts +1 -1
- package/dist/workflow/llm.d.ts +1 -1
- package/dist/workflow/route.d.ts +1 -1
- package/dist/workflow/types.d.ts +2 -2
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -20,6 +20,9 @@ Everything follows the same `(req, ctx) => Response` contract. The Router handle
|
|
|
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
22
|
- **PostgreSQL** — `postgres()` — zod-to-DDL, auto-migration, 6 CRUD methods, `ctx.sql` escape hatch
|
|
23
|
+
- **Redis** — `redis()` — ioredis client, `ctx.redis`, middleware
|
|
24
|
+
- **Queue** — `queue()` — Redis-backed job queue with immediate, delayed, and cron scheduling
|
|
25
|
+
- **Auth** — `user()` — register/login/JWT + OAuth2 Server (authorization code + PKCE + client_credentials)
|
|
23
26
|
- **Static files** — `serveStatic()` with ETag, 304, MIME, directory index
|
|
24
27
|
- **Cookie** — `getCookies()`, `setCookie()`, `deleteCookie()` — immutable
|
|
25
28
|
- **Error handling** — global `onError()`
|
|
@@ -258,14 +261,109 @@ await pg.close() // explicit close
|
|
|
258
261
|
| `id: z.string().uuid().optional()` | `UUID PRIMARY KEY DEFAULT gen_random_uuid()` |
|
|
259
262
|
| `id: z.string()` | `TEXT PRIMARY KEY` (you pass the value) |
|
|
260
263
|
|
|
261
|
-
##
|
|
264
|
+
## Authentication
|
|
265
|
+
|
|
266
|
+
Built-in user management — password login, JWT, and OAuth2 Server. Zero config beyond PostgreSQL and a secret key.
|
|
262
267
|
|
|
263
268
|
```ts
|
|
269
|
+
import { serve, Router, postgres, user } from 'weifuwu'
|
|
270
|
+
|
|
264
271
|
const app = new Router()
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
272
|
+
const pg = postgres()
|
|
273
|
+
await pg.migrate()
|
|
274
|
+
|
|
275
|
+
const auth = user({ pg, jwtSecret: process.env.JWT_SECRET! })
|
|
276
|
+
|
|
277
|
+
// POST /auth/register { email, password, name }
|
|
278
|
+
// POST /auth/login { email, password }
|
|
279
|
+
// GET /auth/oauth/authorize?client_id=...&redirect_uri=...&response_type=code
|
|
280
|
+
// POST /auth/oauth/consent
|
|
281
|
+
// POST /auth/oauth/token (grant_type=authorization_code|client_credentials)
|
|
282
|
+
app.use('/auth', auth.router())
|
|
283
|
+
|
|
284
|
+
// Protected routes — verifies JWT, sets ctx.user
|
|
285
|
+
app.get('/me', auth.middleware(), async (req, ctx) => {
|
|
286
|
+
return Response.json(ctx.user)
|
|
287
|
+
// { id, email, name, role }
|
|
288
|
+
})
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
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()`.
|
|
292
|
+
|
|
293
|
+
### OAuth2 Server
|
|
294
|
+
|
|
295
|
+
Enable OAuth2 Server to let third-party apps (SPA, mobile, microservices) authenticate users through your app.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const auth = user({
|
|
299
|
+
pg,
|
|
300
|
+
jwtSecret: process.env.JWT_SECRET!,
|
|
301
|
+
oauth2: { server: true },
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
await auth.migrate() // creates _users + _oauth2_clients + _oauth2_codes + _oauth2_tokens
|
|
305
|
+
|
|
306
|
+
// Register a client app (programmatic — CLI, admin UI, seed script)
|
|
307
|
+
const client = await auth.registerClient({
|
|
308
|
+
name: 'My SPA',
|
|
309
|
+
redirectUris: ['https://myapp.com/callback'],
|
|
310
|
+
})
|
|
311
|
+
// → { clientId, clientSecret, name, redirectUris }
|
|
312
|
+
|
|
313
|
+
// Use auth middleware to protect routes — OAuth2 JWT tokens work seamlessly
|
|
314
|
+
app.get('/api/data', auth.middleware(), handler)
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
#### Supported Grant Types
|
|
318
|
+
|
|
319
|
+
| Grant | Use Case | PKCE |
|
|
320
|
+
|-------|----------|------|
|
|
321
|
+
| `authorization_code` (with client_secret) | Server-side apps | Optional |
|
|
322
|
+
| `authorization_code` (with `code_challenge`/`code_verifier`) | SPA / Mobile apps | Required |
|
|
323
|
+
| `client_credentials` | Machine-to-machine | — |
|
|
324
|
+
|
|
325
|
+
#### Flow (Authorization Code + PKCE)
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
1. 第三方 App 引导用户:
|
|
329
|
+
GET /oauth/authorize?client_id=xxx&redirect_uri=https://app.com/cb
|
|
330
|
+
&response_type=code&code_challenge=S256&state=yyy
|
|
331
|
+
|
|
332
|
+
2. 用户未登录 → 302 到 /login?redirect=... → 登录后自动回到授权页
|
|
333
|
+
|
|
334
|
+
3. 用户确认授权 → POST /oauth/consent { approve: true, client_id, ... }
|
|
335
|
+
302 redirect_uri?code=xxx&state=yyy
|
|
336
|
+
|
|
337
|
+
4. 第三方 App POST /oauth/token
|
|
338
|
+
{ grant_type: authorization_code, code, client_id, client_secret,
|
|
339
|
+
redirect_uri, code_verifier }
|
|
340
|
+
→ { access_token, token_type: "Bearer", expires_in, refresh_token }
|
|
341
|
+
|
|
342
|
+
5. access_token 是标准 JWT,auth.middleware() 和 auth.verify() 直接可用
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
#### Client Management
|
|
346
|
+
|
|
347
|
+
```ts
|
|
348
|
+
const client = await auth.registerClient({ name, redirectUris })
|
|
349
|
+
const found = await auth.getClient(client.clientId)
|
|
350
|
+
await auth.revokeClient(client.clientId)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
#### Using OAuth2 Tokens with the Built-in Auth Middleware
|
|
354
|
+
|
|
355
|
+
OAuth2 Server 签发的 `access_token` 与密码登录的 JWT 使用同一 `jwtSecret`,payload 向下兼容(`sub`、`email`、`role`),所以 `auth()` 无需任何修改即可验证 OAuth2 签发的 token:
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
import { auth } from 'weifuwu'
|
|
359
|
+
|
|
360
|
+
// 同一个 auth() 中间件同时支持密码登录 JWT 和 OAuth2 JWT
|
|
361
|
+
app.get('/api', auth({ verify: (token) => auth.verify(token) }), handler)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
For `client_credentials` tokens (machine-to-machine), `verify()` returns `null` since no user is associated.
|
|
365
|
+
|
|
366
|
+
## WebSocket
|
|
269
367
|
message(ws, ctx, data) {
|
|
270
368
|
ws.send(`echo: ${data}`)
|
|
271
369
|
},
|
|
@@ -654,6 +752,18 @@ const app = new Router()
|
|
|
654
752
|
|
|
655
753
|
Returns `{ stop, port, hostname, ready }`.
|
|
656
754
|
|
|
755
|
+
### `user(options)`
|
|
756
|
+
|
|
757
|
+
| Option | Default | Description |
|
|
758
|
+
|--------|---------|-------------|
|
|
759
|
+
| `pg` | — | PostgreSQL client from `postgres()` |
|
|
760
|
+
| `jwtSecret` | — | Secret key for JWT signing |
|
|
761
|
+
| `table` | `'_users'` | Users table name |
|
|
762
|
+
| `expiresIn` | `'24h'` | JWT expiration |
|
|
763
|
+
| `oauth2.server` | `false` | Enable OAuth2 Server |
|
|
764
|
+
|
|
765
|
+
Returns `UserModule` — `{ router, middleware, migrate, register, login, verify, registerClient, getClient, revokeClient, close }`.
|
|
766
|
+
|
|
657
767
|
### `tsx(options)`
|
|
658
768
|
|
|
659
769
|
| Option | Default | Description |
|
|
@@ -690,6 +800,9 @@ Returns `Promise<Router>`.
|
|
|
690
800
|
| Import | Description |
|
|
691
801
|
|--------|-------------|
|
|
692
802
|
| `postgres(options?)` | PostgreSQL connection + auto-migration + 6 CRUD methods |
|
|
803
|
+
| `redis(options?)` | Redis client (ioredis) — injects `ctx.redis` |
|
|
804
|
+
| `queue(options?)` | Redis-backed job queue — immediate, delayed, cron scheduling |
|
|
805
|
+
| `user(options)` | Built-in authentication (password + OAuth2 Server + JWT, middleware) |
|
|
693
806
|
| `graphql(handler)` | GraphQL endpoint (GET/POST + GraphiQL) |
|
|
694
807
|
| `ai(handler)` | AI streaming endpoint (POST) |
|
|
695
808
|
| `workflow(handler)` | Workflow engine (POST + SSE) |
|
package/dist/index.d.ts
CHANGED
|
@@ -27,3 +27,9 @@ 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';
|