@lark-apaas/coding-templates 0.1.35 → 0.1.37

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": "@lark-apaas/coding-templates",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "description": "OpenClaw project templates for mclaw CLI",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -19,7 +19,8 @@
19
19
 
20
20
  ```
21
21
  ├── client/src/ # 前端代码
22
- │ ├── app.tsx # 路由注册
22
+ │ ├── main.tsx # 入口(Provider 层级 + 样式引入,勿修改)
23
+ │ ├── app.tsx # 路由配置
23
24
  │ ├── index.css # 全局样式 + 主题变量
24
25
  │ ├── api/ # API 请求封装
25
26
  │ │ └── index.ts
@@ -34,12 +35,12 @@
34
35
  │ ├── hooks/ # 自定义 Hooks
35
36
  │ └── lib/ # 工具函数(cn() 等)
36
37
  ├── server/ # 后端代码
37
- │ ├── index.ts # Express 入口(dev: Vite HMR 中间件)
38
- │ ├── routes/ # API 路由
39
- │ │ └── index.ts # 路由注册
38
+ │ ├── index.ts # Express 入口
39
+ │ ├── routes/ # 路由
40
+ │ │ ├── index.ts # 路由注册
41
+ │ │ └── view.ts # 页面渲染(catch-all HTML 响应,勿修改)
40
42
  │ └── db/ # 数据库层
41
- │ ├── schema.ts # Drizzle schema 定义(可由工具生成)
42
- │ └── index.ts # 数据库连接
43
+ │ ├── schema.ts # Drizzle schema 定义(工具自动生成,勿手动修改)
43
44
  ├── shared/ # 前后端共享(不依赖 client 或 server)
44
45
  │ ├── types.ts # 数据模型类型
45
46
  │ └── api.interface.ts # zod schema + API 入参/出参类型
@@ -76,7 +77,7 @@ export type ListPostsResponse = Post[];
76
77
 
77
78
  ### 2. server/ — 数据库和路由
78
79
 
79
- `server/db/schema.ts` 增加表定义:
80
+ `server/db/schema.ts` 由 `npm run gen:db-schema` 自动生成,无需手动编写。运行命令后会根据数据库表结构自动生成如下定义:
80
81
 
81
82
  ```typescript
82
83
  export const posts = pgTable("posts", {
@@ -91,7 +92,7 @@ export const posts = pgTable("posts", {
91
92
 
92
93
  ```typescript
93
94
  import { Router } from "express";
94
- import { db } from "../db/index";
95
+ import { db } from "@lark-apaas/express-core";
95
96
  import { posts } from "../db/schema";
96
97
  import { createPostSchema } from "@shared/api.interface";
97
98
 
@@ -120,11 +121,12 @@ app.use("/api/posts", postsRouter);
120
121
 
121
122
  > ⚠️ **客户端所有 HTTP 请求必须使用 `axiosForBackend`**
122
123
  >
123
- > `axiosForBackend` 由 `@lark-apaas/client-toolkit-lite` 提供,内置平台鉴权和请求上下文。**禁止使用** `fetch`、`axios`、`XMLHttpRequest` 或其他 HTTP 客户端直接发起请求。
124
+ > `axiosForBackend` 由 `@lark-apaas/client-toolkit-lite` 提供,内置平台鉴权、CSRF token 注入和请求上下文。**禁止使用** `fetch`、`axios`、`XMLHttpRequest` 或其他 HTTP 客户端直接发起请求。
124
125
 
125
126
  `client/src/api/index.ts` 增加封装:
126
127
 
127
128
  ```typescript
129
+ import { axiosForBackend } from "@lark-apaas/client-toolkit-lite";
128
130
  import type { ListPostsResponse } from "@shared/api.interface";
129
131
 
130
132
  export async function listPosts(): Promise<ListPostsResponse> {
@@ -216,6 +218,8 @@ export default function DashboardPage() {
216
218
  </Route>
217
219
  ```
218
220
 
221
+ > **注意:** `BrowserRouter` 已在 `main.tsx` 中统一配置,`app.tsx` 中**禁止**再包裹 `BrowserRouter`,否则会报嵌套 Router 错误。
222
+
219
223
  **新增页面步骤:**
220
224
 
221
225
  1. 在 `client/src/pages/` 下新建页面目录(如 `SettingsPage`)和 `SettingsPage.tsx`
@@ -1,17 +1,15 @@
1
- import { BrowserRouter, Routes, Route } from "react-router-dom";
1
+ import { Routes, Route } from "react-router-dom";
2
2
  import { Layout } from "@/components/layout";
3
3
  import HomePage from "@/pages/HomePage/HomePage";
4
4
  import NotFoundPage from "@/pages/NotFoundPage/NotFoundPage";
5
5
 
6
6
  export default function App() {
7
7
  return (
8
- <BrowserRouter basename={process.env.CLIENT_BASE_PATH || '/'}>
9
- <Routes>
10
- <Route element={<Layout />}>
11
- <Route index element={<HomePage />} />
12
- <Route path="*" element={<NotFoundPage />} />
13
- </Route>
14
- </Routes>
15
- </BrowserRouter>
8
+ <Routes>
9
+ <Route element={<Layout />}>
10
+ <Route index element={<HomePage />} />
11
+ <Route path="*" element={<NotFoundPage />} />
12
+ </Route>
13
+ </Routes>
16
14
  );
17
15
  }
@@ -1,14 +1,16 @@
1
1
  import { StrictMode } from "react";
2
2
  import { createRoot } from "react-dom/client";
3
+ import { BrowserRouter } from "react-router-dom";
3
4
  import { AppContainer } from "@lark-apaas/client-toolkit-lite";
4
- import "@lark-apaas/client-toolkit-lite/styles.css";
5
5
  import App from "./app";
6
6
  import "./index.css";
7
7
 
8
8
  createRoot(document.getElementById("root")!).render(
9
9
  <StrictMode>
10
- <AppContainer>
11
- <App />
12
- </AppContainer>
10
+ <BrowserRouter basename={process.env.CLIENT_BASE_PATH || "/"}>
11
+ <AppContainer>
12
+ <App />
13
+ </AppContainer>
14
+ </BrowserRouter>
13
15
  </StrictMode>,
14
16
  );
@@ -11,11 +11,11 @@
11
11
  ]
12
12
  },
13
13
  "scripts": {
14
- "dev": "tsx --watch --watch-path server --watch-path shared server/index.ts",
15
14
  "build": "bash scripts/build.sh",
16
- "typecheck": "npm run typecheck:client",
15
+ "typecheck": "concurrently npm:typecheck:client npm:typecheck:server",
17
16
  "typecheck:client": "tsc -p tsconfig.app.json",
18
- "lint": "npm run typecheck && npm run lint:client && npm run lint:server",
17
+ "typecheck:server": "tsc --noEmit -p tsconfig.server.json",
18
+ "lint": "concurrently npm:typecheck npm:lint:client npm:lint:server",
19
19
  "lint:client": "eslint client/src",
20
20
  "lint:server": "eslint server",
21
21
  "gen:db-schema": "npx -y @lark-apaas/db-schema-sync@latest --output server/db/schema.ts"
@@ -48,8 +48,8 @@
48
48
  "@radix-ui/react-toggle": "^1.1.9",
49
49
  "@radix-ui/react-toggle-group": "^1.1.10",
50
50
  "@radix-ui/react-tooltip": "^1.1.18",
51
- "@lark-apaas/client-toolkit-lite": "^1.0.0",
52
- "@lark-apaas/express-core": "^0.0.9",
51
+ "@lark-apaas/client-toolkit-lite": "^1.1.0",
52
+ "@lark-apaas/express-core": "^1.0.0",
53
53
  "@formkit/auto-animate": "^0.9.0",
54
54
  "framer-motion": "^12.38.0",
55
55
  "class-variance-authority": "^0.7.1",
@@ -57,6 +57,8 @@
57
57
  "cmdk": "^1.1.1",
58
58
  "date-fns": "^4.1.0",
59
59
  "drizzle-orm": "0.44.6",
60
+ "echarts": "~5.6.0",
61
+ "echarts-for-react": "~3.0.2",
60
62
  "embla-carousel-react": "^8.6.0",
61
63
  "express": "^5.1.0",
62
64
  "hbs": "^4.2.0",
@@ -85,6 +87,7 @@
85
87
  "@types/node": "^24",
86
88
  "@types/react": "^19",
87
89
  "@types/react-dom": "^19",
90
+ "concurrently": "^9",
88
91
  "eslint": "^9",
89
92
  "tsc-alias": "^1.8.15",
90
93
  "tsx": "^4",
@@ -1,11 +1 @@
1
- // Drizzle schema 定义(可由工具生成)
2
- //
3
- // import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
4
- //
5
- // 使用示例:
6
- // export const posts = pgTable("posts", {
7
- // id: serial("id").primaryKey(),
8
- // title: text("title").notNull(),
9
- // content: text("content"),
10
- // createdAt: timestamp("created_at").notNull().defaultNow(),
11
- // });
1
+ /* 该文件通过 npm run gen:db-schema 自动生成*/
@@ -1,9 +1,5 @@
1
- import express, { type Request, type Response } from "express";
2
- import path from "path";
3
- import fs from "fs";
4
- import hbs from "hbs";
5
- import { setup, createViewContextMiddleware } from "@lark-apaas/express-core";
6
- import * as schema from "./db/schema";
1
+ import express from "express";
2
+ import { setup } from "@lark-apaas/express-core";
7
3
  import { registerRoutes } from "./routes/index";
8
4
 
9
5
  const port = Number(process.env.FORCE_SERVER_PORT) || 3000;
@@ -13,26 +9,12 @@ const basePath = process.env.CLIENT_BASE_PATH || "/";
13
9
  const app = express();
14
10
 
15
11
  // Platform middleware
16
- const { close } = setup(app, {
17
- database: { schema },
18
- csrf: { enabled: false },
19
- viewContext: { enabled: false },
20
- });
12
+ const { close } = setup(app);
21
13
 
22
14
  // All routes under basePath
23
15
  const router = express.Router();
24
16
  registerRoutes(router);
25
17
 
26
- const templatePath = path.resolve(__dirname, "../index.html");
27
- const template = hbs.compile(fs.readFileSync(templatePath, "utf-8"));
28
-
29
- router.get("/{*path}", createViewContextMiddleware(), (_req: Request, res: Response) => {
30
- const html = template({
31
- ...res.locals,
32
- });
33
- res.type("html").send(html);
34
- });
35
-
36
18
  app.use(basePath, router);
37
19
 
38
20
  const server = app.listen(port, host, () => {
@@ -1,9 +1,13 @@
1
1
  import type { Router } from "express";
2
+ import { registerViewRoute } from "./view";
2
3
  // import postsRouter from "./posts";
3
4
 
4
- export function registerRoutes(app: Router) {
5
+ export function registerRoutes(router: Router) {
5
6
  // 在此注册 API 路由
6
7
  //
7
8
  // 使用示例:
8
- // app.use("/api/posts", postsRouter);
9
+ // router.use("/api/posts", postsRouter);
10
+
11
+ // HTML 页面渲染(catch-all,必须放在最后)
12
+ registerViewRoute(router);
9
13
  }
@@ -0,0 +1,16 @@
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import hbs from "hbs";
4
+ import type { Request, Response, Router } from "express";
5
+
6
+ const templatePath = path.resolve(__dirname, "../../index.html");
7
+ const template = hbs.compile(fs.readFileSync(templatePath, "utf-8"));
8
+
9
+ export function registerViewRoute(router: Router) {
10
+ router.get("/{*path}", (_req: Request, res: Response) => {
11
+ const html = template({
12
+ ...res.locals,
13
+ });
14
+ res.type("html").send(html);
15
+ });
16
+ }
@@ -5,11 +5,9 @@
5
5
  "rootDir": ".",
6
6
  "module": "commonjs",
7
7
  "moduleResolution": "node",
8
- "verbatimModuleSyntax": false,
9
8
  "esModuleInterop": true,
10
9
  "noEmit": false,
11
10
  "allowImportingTsExtensions": false,
12
- "noUnusedParameters": false,
13
11
  "baseUrl": ".",
14
12
  "paths": {
15
13
  "@shared/*": ["./shared/*"]
@@ -16,7 +16,8 @@
16
16
 
17
17
  ```
18
18
  client/src/
19
- ├── app.tsx # 路由注册
19
+ ├── main.tsx # 入口(Provider 层级 + 样式引入,勿修改)
20
+ ├── app.tsx # 路由配置
20
21
  ├── index.css # 全局样式 + 主题变量
21
22
  ├── components/ # 基础 UI 组件(禁止存放业务组件)
22
23
  │ └── ui/ # shadcn/ui 内置组件(勿手动修改)
@@ -94,28 +95,26 @@ export default function DashboardPage() {
94
95
  **替换后的路由示例:**
95
96
 
96
97
  ```tsx
97
- import { BrowserRouter, Routes, Route } from "react-router-dom";
98
+ import { Routes, Route } from "react-router-dom";
98
99
  import { Layout } from "@/components/layout";
99
100
  import DashboardPage from "@/pages/DashboardPage/DashboardPage";
100
101
  import NotFoundPage from "@/pages/NotFoundPage/NotFoundPage";
101
102
 
102
- declare const __APP_BASE_PATH__: string;
103
-
104
103
  export default function App() {
105
104
  return (
106
- <BrowserRouter basename={__APP_BASE_PATH__}>
107
- <Routes>
108
- <Route element={<Layout />}>
109
- {/* index 路由指向真实的业务首页 */}
110
- <Route index element={<DashboardPage />} />
111
- <Route path="*" element={<NotFoundPage />} />
112
- </Route>
113
- </Routes>
114
- </BrowserRouter>
105
+ <Routes>
106
+ <Route element={<Layout />}>
107
+ {/* 将 index 路由指向真实的业务首页 */}
108
+ <Route index element={<DashboardPage />} />
109
+ <Route path="*" element={<NotFoundPage />} />
110
+ </Route>
111
+ </Routes>
115
112
  );
116
113
  }
117
114
  ```
118
115
 
116
+ > **注意:** `BrowserRouter` 已在 `main.tsx` 中统一配置,`app.tsx` 中**禁止**再包裹 `BrowserRouter`,否则会报嵌套 Router 错误。
117
+
119
118
  **新增页面步骤:**
120
119
 
121
120
  1. 在 `client/src/pages/` 下新建页面目录(如 `SettingsPage`)和 `SettingsPage.tsx`
@@ -1,17 +1,15 @@
1
- import { BrowserRouter, Routes, Route } from "react-router-dom";
1
+ import { Routes, Route } from "react-router-dom";
2
2
  import { Layout } from "@/components/layout";
3
3
  import HomePage from "@/pages/HomePage/HomePage";
4
4
  import NotFoundPage from "@/pages/NotFoundPage/NotFoundPage";
5
5
 
6
6
  export default function App() {
7
7
  return (
8
- <BrowserRouter basename={process.env.CLIENT_BASE_PATH || '/'}>
9
- <Routes>
10
- <Route element={<Layout />}>
11
- <Route index element={<HomePage />} />
12
- <Route path="*" element={<NotFoundPage />} />
13
- </Route>
14
- </Routes>
15
- </BrowserRouter>
8
+ <Routes>
9
+ <Route element={<Layout />}>
10
+ <Route index element={<HomePage />} />
11
+ <Route path="*" element={<NotFoundPage />} />
12
+ </Route>
13
+ </Routes>
16
14
  );
17
15
  }
@@ -1,14 +1,16 @@
1
1
  import { StrictMode } from "react";
2
2
  import { createRoot } from "react-dom/client";
3
+ import { BrowserRouter } from "react-router-dom";
3
4
  import { AppContainer } from "@lark-apaas/client-toolkit-lite";
4
- import "@lark-apaas/client-toolkit-lite/styles.css";
5
5
  import App from "./app";
6
6
  import "./index.css";
7
7
 
8
8
  createRoot(document.getElementById("root")!).render(
9
9
  <StrictMode>
10
- <AppContainer>
11
- <App />
12
- </AppContainer>
10
+ <BrowserRouter basename={process.env.CLIENT_BASE_PATH || "/"}>
11
+ <AppContainer>
12
+ <App />
13
+ </AppContainer>
14
+ </BrowserRouter>
13
15
  </StrictMode>,
14
16
  );
@@ -10,13 +10,10 @@
10
10
  ]
11
11
  },
12
12
  "scripts": {
13
- "dev": "vite",
14
13
  "build": "bash scripts/build.sh",
15
- "typecheck": "npm run typecheck:client",
16
- "typecheck:client": "tsc -p tsconfig.app.json",
17
- "lint": "npm run typecheck && npm run lint:client",
18
- "lint:client": "eslint client/src",
19
- "preview": "vite preview"
14
+ "typecheck": "tsc -p tsconfig.app.json",
15
+ "lint": "concurrently npm:typecheck npm:lint:eslint",
16
+ "lint:eslint": "eslint client/src"
20
17
  },
21
18
  "dependencies": {
22
19
  "@hookform/resolvers": "^5.2.2",
@@ -46,7 +43,7 @@
46
43
  "@radix-ui/react-toggle": "^1.1.9",
47
44
  "@radix-ui/react-toggle-group": "^1.1.10",
48
45
  "@radix-ui/react-tooltip": "^1.1.18",
49
- "@lark-apaas/client-toolkit-lite": "^1.0.0",
46
+ "@lark-apaas/client-toolkit-lite": "^1.1.0",
50
47
  "@formkit/auto-animate": "^0.9.0",
51
48
  "framer-motion": "^12.38.0",
52
49
  "class-variance-authority": "^0.7.1",
@@ -80,6 +77,7 @@
80
77
  "@types/react-dom": "^19",
81
78
  "@lark-apaas/coding-presets": "^1.0.0",
82
79
  "@lark-apaas/coding-vite-preset": "^1.0.0",
80
+ "concurrently": "^9",
83
81
  "eslint": "^9",
84
82
  "eslint-plugin-react-hooks": "^7",
85
83
  "eslint-plugin-react-refresh": "^0.5",
@@ -1 +0,0 @@
1
- DATABASE_URL=postgresql://postgres:postgres@localhost:5432/openclaw