@arrislink/axon 1.2.0 → 1.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrislink/axon",
3
- "version": "1.2.0",
3
+ "version": "1.5.0",
4
4
  "description": "AI-Powered Development Operating System with unified LLM provider support",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,240 +0,0 @@
1
- ---
2
- name: RESTful CRUD API
3
- description: 实现标准 RESTful CRUD 接口
4
- tags: [api, rest, crud, typescript]
5
- models: [claude-sonnet-4, gpt-4]
6
- tokens_avg: 2200
7
- difficulty: easy
8
- last_updated: 2026-02-09
9
- ---
10
-
11
- ## Context
12
-
13
- 实现标准的 RESTful CRUD API,包括列表、详情、创建、更新和删除操作。
14
-
15
- ## Prerequisites
16
-
17
- - Hono / Express / Fastify
18
- - TypeScript
19
- - 数据验证库 (Zod)
20
-
21
- ## Implementation
22
-
23
- ### 1. 路由结构
24
-
25
- | 方法 | 路径 | 描述 |
26
- |------|------|------|
27
- | GET | /api/items | 获取列表 (分页) |
28
- | GET | /api/items/:id | 获取详情 |
29
- | POST | /api/items | 创建 |
30
- | PUT | /api/items/:id | 完整更新 |
31
- | PATCH | /api/items/:id | 部分更新 |
32
- | DELETE | /api/items/:id | 删除 |
33
-
34
- ### 2. 使用 Hono 实现
35
-
36
- ```typescript
37
- // src/routes/items.ts
38
- import { Hono } from 'hono';
39
- import { zValidator } from '@hono/zod-validator';
40
- import { z } from 'zod';
41
-
42
- const app = new Hono();
43
-
44
- // 验证 Schema
45
- const createItemSchema = z.object({
46
- name: z.string().min(1).max(100),
47
- description: z.string().optional(),
48
- price: z.number().positive(),
49
- category: z.enum(['electronics', 'clothing', 'food']),
50
- });
51
-
52
- const updateItemSchema = createItemSchema.partial();
53
-
54
- const querySchema = z.object({
55
- page: z.coerce.number().min(1).default(1),
56
- limit: z.coerce.number().min(1).max(100).default(20),
57
- sort: z.enum(['newest', 'oldest', 'price_asc', 'price_desc']).default('newest'),
58
- category: z.string().optional(),
59
- });
60
-
61
- // GET /items - 列表
62
- app.get('/', zValidator('query', querySchema), async (c) => {
63
- const { page, limit, sort, category } = c.req.valid('query');
64
- const offset = (page - 1) * limit;
65
-
66
- const items = await db.query.items.findMany({
67
- where: category ? eq(items.category, category) : undefined,
68
- limit,
69
- offset,
70
- orderBy: getSortOrder(sort),
71
- });
72
-
73
- const total = await db.select({ count: count() }).from(items);
74
-
75
- return c.json({
76
- data: items,
77
- pagination: {
78
- page,
79
- limit,
80
- total: total[0].count,
81
- totalPages: Math.ceil(total[0].count / limit),
82
- },
83
- });
84
- });
85
-
86
- // GET /items/:id - 详情
87
- app.get('/:id', async (c) => {
88
- const id = c.req.param('id');
89
- const item = await db.query.items.findFirst({
90
- where: eq(items.id, id),
91
- });
92
-
93
- if (!item) {
94
- return c.json({ error: 'Item not found' }, 404);
95
- }
96
-
97
- return c.json({ data: item });
98
- });
99
-
100
- // POST /items - 创建
101
- app.post('/', zValidator('json', createItemSchema), async (c) => {
102
- const data = c.req.valid('json');
103
-
104
- const [item] = await db.insert(items).values(data).returning();
105
-
106
- return c.json({ data: item }, 201);
107
- });
108
-
109
- // PUT /items/:id - 完整更新
110
- app.put('/:id', zValidator('json', createItemSchema), async (c) => {
111
- const id = c.req.param('id');
112
- const data = c.req.valid('json');
113
-
114
- const [item] = await db
115
- .update(items)
116
- .set({ ...data, updatedAt: new Date() })
117
- .where(eq(items.id, id))
118
- .returning();
119
-
120
- if (!item) {
121
- return c.json({ error: 'Item not found' }, 404);
122
- }
123
-
124
- return c.json({ data: item });
125
- });
126
-
127
- // PATCH /items/:id - 部分更新
128
- app.patch('/:id', zValidator('json', updateItemSchema), async (c) => {
129
- const id = c.req.param('id');
130
- const data = c.req.valid('json');
131
-
132
- const [item] = await db
133
- .update(items)
134
- .set({ ...data, updatedAt: new Date() })
135
- .where(eq(items.id, id))
136
- .returning();
137
-
138
- if (!item) {
139
- return c.json({ error: 'Item not found' }, 404);
140
- }
141
-
142
- return c.json({ data: item });
143
- });
144
-
145
- // DELETE /items/:id - 删除
146
- app.delete('/:id', async (c) => {
147
- const id = c.req.param('id');
148
-
149
- const [item] = await db
150
- .delete(items)
151
- .where(eq(items.id, id))
152
- .returning();
153
-
154
- if (!item) {
155
- return c.json({ error: 'Item not found' }, 404);
156
- }
157
-
158
- return c.json({ message: 'Deleted successfully' });
159
- });
160
-
161
- export default app;
162
- ```
163
-
164
- ### 3. 响应格式规范
165
-
166
- ```typescript
167
- // 成功响应
168
- {
169
- "data": { ... } | [ ... ],
170
- "pagination": { ... } // 仅列表接口
171
- }
172
-
173
- // 错误响应
174
- {
175
- "error": "Error message",
176
- "code": "ERROR_CODE",
177
- "details": { ... } // 可选
178
- }
179
- ```
180
-
181
- ### 4. HTTP 状态码规范
182
-
183
- | 状态码 | 含义 | 使用场景 |
184
- |--------|------|----------|
185
- | 200 | OK | GET, PUT, PATCH 成功 |
186
- | 201 | Created | POST 成功 |
187
- | 204 | No Content | DELETE 成功 (无响应体) |
188
- | 400 | Bad Request | 请求参数错误 |
189
- | 401 | Unauthorized | 未认证 |
190
- | 403 | Forbidden | 无权限 |
191
- | 404 | Not Found | 资源不存在 |
192
- | 409 | Conflict | 资源冲突 (如重复) |
193
- | 422 | Unprocessable | 验证失败 |
194
- | 500 | Internal Error | 服务器错误 |
195
-
196
- ## Tests
197
-
198
- ```typescript
199
- // tests/routes/items.test.ts
200
- import { describe, test, expect } from 'bun:test';
201
- import app from '../../src/routes/items';
202
-
203
- describe('Items API', () => {
204
- test('GET /items returns list', async () => {
205
- const res = await app.request('/');
206
- expect(res.status).toBe(200);
207
-
208
- const data = await res.json();
209
- expect(data.data).toBeArray();
210
- expect(data.pagination).toBeDefined();
211
- });
212
-
213
- test('POST /items creates item', async () => {
214
- const res = await app.request('/', {
215
- method: 'POST',
216
- headers: { 'Content-Type': 'application/json' },
217
- body: JSON.stringify({
218
- name: 'Test Item',
219
- price: 99.99,
220
- category: 'electronics',
221
- }),
222
- });
223
-
224
- expect(res.status).toBe(201);
225
- const data = await res.json();
226
- expect(data.data.name).toBe('Test Item');
227
- });
228
-
229
- test('GET /items/:id returns 404 for missing', async () => {
230
- const res = await app.request('/non-existent-id');
231
- expect(res.status).toBe(404);
232
- });
233
- });
234
- ```
235
-
236
- ## Related Skills
237
-
238
- - api/pagination.md
239
- - api/error-handling.md
240
- - api/rate-limiting.md
@@ -1,186 +0,0 @@
1
- ---
2
- name: JWT Authentication Implementation
3
- description: 实现基于 JWT 的用户认证系统
4
- tags: [auth, jwt, security, typescript]
5
- models: [claude-sonnet-4, gpt-4]
6
- tokens_avg: 2500
7
- difficulty: medium
8
- last_updated: 2026-02-09
9
- ---
10
-
11
- ## Context
12
-
13
- 实现一个安全的 JWT 认证系统,包括 token 生成、验证和刷新机制。
14
-
15
- ## Prerequisites
16
-
17
- - Node.js >= 18 或 Bun
18
- - jsonwebtoken 库
19
- - 环境变量: JWT_SECRET, JWT_EXPIRES_IN
20
-
21
- ## Implementation
22
-
23
- ### 1. 安装依赖
24
-
25
- ```bash
26
- bun add jsonwebtoken
27
- bun add -d @types/jsonwebtoken
28
- ```
29
-
30
- ### 2. Token 生成工具
31
-
32
- ```typescript
33
- // src/auth/jwt.ts
34
- import jwt from 'jsonwebtoken';
35
-
36
- const JWT_SECRET = process.env.JWT_SECRET!;
37
- const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';
38
-
39
- export interface TokenPayload {
40
- userId: string;
41
- email?: string;
42
- role?: string;
43
- }
44
-
45
- export function generateToken(payload: TokenPayload): string {
46
- return jwt.sign(payload, JWT_SECRET, {
47
- expiresIn: JWT_EXPIRES_IN,
48
- });
49
- }
50
-
51
- export function verifyToken(token: string): TokenPayload {
52
- return jwt.verify(token, JWT_SECRET) as TokenPayload;
53
- }
54
-
55
- export function decodeToken(token: string): TokenPayload | null {
56
- const decoded = jwt.decode(token);
57
- return decoded as TokenPayload | null;
58
- }
59
- ```
60
-
61
- ### 3. 认证中间件
62
-
63
- ```typescript
64
- // src/auth/middleware.ts
65
- import type { Request, Response, NextFunction } from 'express';
66
- import { verifyToken } from './jwt';
67
-
68
- export function authenticateToken(
69
- req: Request,
70
- res: Response,
71
- next: NextFunction
72
- ) {
73
- const authHeader = req.headers['authorization'];
74
- const token = authHeader?.split(' ')[1];
75
-
76
- if (!token) {
77
- return res.status(401).json({ error: 'Token required' });
78
- }
79
-
80
- try {
81
- const payload = verifyToken(token);
82
- req.user = payload;
83
- next();
84
- } catch (error) {
85
- return res.status(403).json({ error: 'Invalid token' });
86
- }
87
- }
88
- ```
89
-
90
- ### 4. 登录接口示例
91
-
92
- ```typescript
93
- // src/routes/auth.ts
94
- import { Router } from 'express';
95
- import { generateToken } from '../auth/jwt';
96
-
97
- const router = Router();
98
-
99
- router.post('/login', async (req, res) => {
100
- const { email, password } = req.body;
101
-
102
- // 验证用户 (示例)
103
- const user = await validateUser(email, password);
104
- if (!user) {
105
- return res.status(401).json({ error: 'Invalid credentials' });
106
- }
107
-
108
- // 生成 token
109
- const token = generateToken({
110
- userId: user.id,
111
- email: user.email,
112
- role: user.role,
113
- });
114
-
115
- res.json({ token, expiresIn: process.env.JWT_EXPIRES_IN || '7d' });
116
- });
117
-
118
- export default router;
119
- ```
120
-
121
- ## Tests
122
-
123
- ```typescript
124
- // tests/auth/jwt.test.ts
125
- import { describe, test, expect, beforeAll } from 'bun:test';
126
- import { generateToken, verifyToken, decodeToken } from '../../src/auth/jwt';
127
-
128
- beforeAll(() => {
129
- process.env.JWT_SECRET = 'test-secret-key';
130
- });
131
-
132
- describe('JWT Authentication', () => {
133
- test('generates valid token', () => {
134
- const payload = { userId: 'user123', email: 'test@example.com' };
135
- const token = generateToken(payload);
136
-
137
- expect(token).toBeDefined();
138
- expect(typeof token).toBe('string');
139
- expect(token.split('.')).toHaveLength(3);
140
- });
141
-
142
- test('verifies valid token', () => {
143
- const payload = { userId: 'user123' };
144
- const token = generateToken(payload);
145
- const decoded = verifyToken(token);
146
-
147
- expect(decoded.userId).toBe('user123');
148
- });
149
-
150
- test('rejects invalid token', () => {
151
- expect(() => {
152
- verifyToken('invalid-token');
153
- }).toThrow();
154
- });
155
-
156
- test('decodes token without verification', () => {
157
- const payload = { userId: 'user123' };
158
- const token = generateToken(payload);
159
- const decoded = decodeToken(token);
160
-
161
- expect(decoded?.userId).toBe('user123');
162
- });
163
- });
164
- ```
165
-
166
- ## Security Considerations
167
-
168
- 1. **使用强随机 SECRET** - 至少 256 位随机字符串
169
- 2. **设置合理的过期时间** - 建议 15 分钟到 7 天
170
- 3. **使用 HTTPS** - 防止 token 被截获
171
- 4. **Token 刷新机制** - 实现 refresh token 延长会话
172
- 5. **黑名单机制** - 支持主动撤销 token
173
-
174
- ## Environment Variables
175
-
176
- ```bash
177
- # .env
178
- JWT_SECRET=your-256-bit-secret-key-here
179
- JWT_EXPIRES_IN=7d
180
- ```
181
-
182
- ## Related Skills
183
-
184
- - auth/refresh-token.md
185
- - auth/oauth-integration.md
186
- - security/input-validation.md
@@ -1,161 +0,0 @@
1
- ---
2
- name: PostgreSQL Schema Design
3
- description: PostgreSQL 数据库表结构设计最佳实践
4
- tags: [database, postgresql, schema, sql]
5
- models: [claude-sonnet-4, gpt-4]
6
- tokens_avg: 2000
7
- difficulty: medium
8
- last_updated: 2026-02-09
9
- ---
10
-
11
- ## Context
12
-
13
- 设计 PostgreSQL 数据库表结构,遵循最佳实践和规范。
14
-
15
- ## Prerequisites
16
-
17
- - PostgreSQL >= 14
18
- - 数据库迁移工具 (如 Drizzle, Prisma, Knex)
19
-
20
- ## Implementation
21
-
22
- ### 1. 基础表结构模板
23
-
24
- ```sql
25
- -- 启用 UUID 扩展
26
- CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
27
-
28
- -- 用户表
29
- CREATE TABLE users (
30
- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
31
- email VARCHAR(255) NOT NULL UNIQUE,
32
- password_hash VARCHAR(255) NOT NULL,
33
- username VARCHAR(50) NOT NULL UNIQUE,
34
- display_name VARCHAR(100),
35
- avatar_url TEXT,
36
- role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('user', 'admin', 'moderator')),
37
- status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'banned')),
38
- email_verified_at TIMESTAMP WITH TIME ZONE,
39
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
40
- updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
41
- );
42
-
43
- -- 创建更新时间触发器
44
- CREATE OR REPLACE FUNCTION update_updated_at_column()
45
- RETURNS TRIGGER AS $$
46
- BEGIN
47
- NEW.updated_at = NOW();
48
- RETURN NEW;
49
- END;
50
- $$ language 'plpgsql';
51
-
52
- CREATE TRIGGER update_users_updated_at
53
- BEFORE UPDATE ON users
54
- FOR EACH ROW
55
- EXECUTE FUNCTION update_updated_at_column();
56
- ```
57
-
58
- ### 2. 索引策略
59
-
60
- ```sql
61
- -- 常用查询索引
62
- CREATE INDEX idx_users_email ON users(email);
63
- CREATE INDEX idx_users_status ON users(status) WHERE status != 'active';
64
- CREATE INDEX idx_users_created_at ON users(created_at DESC);
65
-
66
- -- 复合索引 (按查询模式设计)
67
- CREATE INDEX idx_users_role_status ON users(role, status);
68
- ```
69
-
70
- ### 3. 关联表设计
71
-
72
- ```sql
73
- -- 会话表 (一对多)
74
- CREATE TABLE sessions (
75
- id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
76
- user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
77
- token VARCHAR(255) NOT NULL UNIQUE,
78
- user_agent TEXT,
79
- ip_address INET,
80
- expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
81
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
82
- );
83
-
84
- CREATE INDEX idx_sessions_user_id ON sessions(user_id);
85
- CREATE INDEX idx_sessions_expires_at ON sessions(expires_at);
86
-
87
- -- 标签表 (多对多)
88
- CREATE TABLE tags (
89
- id SERIAL PRIMARY KEY,
90
- name VARCHAR(50) NOT NULL UNIQUE,
91
- slug VARCHAR(50) NOT NULL UNIQUE,
92
- created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
93
- );
94
-
95
- CREATE TABLE post_tags (
96
- post_id UUID NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
97
- tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
98
- PRIMARY KEY (post_id, tag_id)
99
- );
100
- ```
101
-
102
- ### 4. JSONB 字段使用
103
-
104
- ```sql
105
- -- 灵活的元数据存储
106
- ALTER TABLE users ADD COLUMN metadata JSONB DEFAULT '{}';
107
-
108
- -- JSONB 索引 (GIN)
109
- CREATE INDEX idx_users_metadata ON users USING GIN (metadata);
110
-
111
- -- 查询 JSONB
112
- SELECT * FROM users WHERE metadata->>'theme' = 'dark';
113
- SELECT * FROM users WHERE metadata @> '{"preferences": {"newsletter": true}}';
114
- ```
115
-
116
- ### 5. Drizzle ORM 示例
117
-
118
- ```typescript
119
- // src/db/schema.ts
120
- import { pgTable, uuid, varchar, timestamp, text, jsonb } from 'drizzle-orm/pg-core';
121
-
122
- export const users = pgTable('users', {
123
- id: uuid('id').primaryKey().defaultRandom(),
124
- email: varchar('email', { length: 255 }).notNull().unique(),
125
- passwordHash: varchar('password_hash', { length: 255 }).notNull(),
126
- username: varchar('username', { length: 50 }).notNull().unique(),
127
- displayName: varchar('display_name', { length: 100 }),
128
- avatarUrl: text('avatar_url'),
129
- role: varchar('role', { length: 20 }).default('user'),
130
- status: varchar('status', { length: 20 }).default('active'),
131
- emailVerifiedAt: timestamp('email_verified_at', { withTimezone: true }),
132
- metadata: jsonb('metadata').default({}),
133
- createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
134
- updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
135
- });
136
-
137
- export const sessions = pgTable('sessions', {
138
- id: uuid('id').primaryKey().defaultRandom(),
139
- userId: uuid('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
140
- token: varchar('token', { length: 255 }).notNull().unique(),
141
- userAgent: text('user_agent'),
142
- ipAddress: varchar('ip_address', { length: 45 }),
143
- expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
144
- createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
145
- });
146
- ```
147
-
148
- ## Best Practices
149
-
150
- 1. **使用 UUID 作为主键** - 分布式友好,无法猜测
151
- 2. **始终添加 created_at/updated_at** - 审计和调试必需
152
- 3. **使用 CHECK 约束** - 确保数据完整性
153
- 4. **索引策略** - 根据查询模式设计,避免过度索引
154
- 5. **使用 ON DELETE CASCADE** - 简化级联删除
155
- 6. **分区大表** - 超过 1000 万行考虑分区
156
-
157
- ## Related Skills
158
-
159
- - database/migrations.md
160
- - database/query-optimization.md
161
- - database/backup-strategy.md