@oj-module/cli 0.1.14 → 0.1.15

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.
@@ -19,7 +19,7 @@
19
19
 
20
20
  > ⚠️ 那两份 guide 有**已知陈旧处**,以源码为准:
21
21
  > dev 端口实际是 **3333**(guide 写的 5173 已过时);包版本以
22
- > `packages/*/package.json` 为准(guide 内部 0.1.6 / 0.1.8 不一致,实际 **0.1.8**)。
22
+ > `packages/*/package.json` 为准(guide 内部 0.1.6 / 0.1.8 不一致,实际 **0.1.15**)。
23
23
 
24
24
  ## §2 两包结构与依赖方向
25
25
 
@@ -132,7 +132,7 @@ pnpm test tests/shell # 宿主全量
132
132
  **一键发布**:`node scripts/publish-packages.mjs`(lockstep 四包校验 → 构建 → 守卫测试 →
133
133
  runtime → cli → registry 复核;`--dry-run` 只演练)。下面的手动步骤是它的展开参考。
134
134
 
135
- - 两包**同版本号**(当前 `0.1.8`),后续发版保持 lockstep。
135
+ - 两包**同版本号**(当前 `0.1.15`),后续发版保持 lockstep。
136
136
  - **必须 `pnpm publish`**——用 `npm publish` 会漏出 `workspace:*` / `catalog:` 字面量。
137
137
  - **顺序:先 `runtime` 后 `cli`**。`runtime` 未公开时,新 `cli` 的精确依赖会悬空,
138
138
  消费者直接装不上。
package/devkit/manual.md CHANGED
@@ -227,11 +227,42 @@ export default defineModule({
227
227
  `react-countup`、`ahooks`、`ky`、`clsx`、`tailwind-merge`、`pinyin-pro`。
228
228
  查实际矩阵:`pnpm exec ojm info`。
229
229
 
230
+ ### 2.7 本版本共享依赖钉版(0.1.15 快照)
231
+
232
+ 宿主经 importmap 提供以下单例(模块 `devDependencies` 须对齐,供 `tsc` 用);完整 66 项矩阵以
233
+ `pnpm exec ojm info` 或 `packages/cli/shell-dist/versions.json`(构建期生成)为准。
234
+
235
+ | 包 | 钉版 |
236
+ | --- | --- |
237
+ | `react` / `react-dom` | 19.2.8 |
238
+ | `react-router` | 7.18.2 |
239
+ | `@tanstack/react-query` | 5.102.8 |
240
+ | `antd` | 6.6.1 |
241
+ | `@ant-design/icons` | 6.3.2 |
242
+ | `@ant-design/pro-components` | 3.1.12-0 |
243
+ | `i18next` / `react-i18next` | 26.4.0 / 17.0.12 |
244
+ | `zustand` | 5.0.15 |
245
+ | `dayjs` | 1.11.23 |
246
+ | `echarts` / `echarts-for-react` | 6.1.0 / 3.0.6 |
247
+ | `motion` | 12.43.0 |
248
+ | `@dnd-kit/core` | 6.3.1 |
249
+ | `keepalive-for-react` | 5.0.11 |
250
+ | `simplebar-react` | 3.3.2 |
251
+ | `nprogress` | 0.2.0 |
252
+ | `react-countup` | 6.5.3 |
253
+ | `ahooks` | 3.9.7 |
254
+ | `ky` | 2.0.2 |
255
+ | `clsx` / `tailwind-merge` | 2.1.1 / 3.6.0 |
256
+ | `pinyin-pro` | 3.29.3 |
257
+
258
+ 框架包版本:`@oj-module/runtime` / `@oj-module/cli` / `@plane/kit` / `@plane/editor` 均为 `0.1.15`
259
+ (lockstep);`oj` 二进制最低版本门禁 `MIN_OJ_VERSION = 0.1.50`。
260
+
230
261
  > **`@oj-module/runtime` 到底导出哪些东西?** 权威清单随包发布在
231
262
  > `node_modules/@oj-module/runtime/dist/index.d.ts`——直接 Read 它,或在编辑器里
232
263
  > 对 `from "@oj-module/runtime"` 用「跳转到定义 / 自动补全」。**别靠猜**:
233
264
  > `BasicContent` / `BasicTable` / `AccessControl` / `useAuthStore` / `useUserStore` /
234
- > `usePreferences` 都在里面(详见 §6.3)。猜不到的常见后果是白白退回 antd 原生
265
+ > `usePreferences` / `useTabsStore` 都在里面(详见 §6.3)。猜不到的常见后果是白白退回 antd 原生
235
266
  > `Table` 重新造轮子。
236
267
 
237
268
  ---
@@ -857,6 +888,29 @@ t("menu.books") // ❌ 会去 common namespace 找
857
888
  | `AccessControl` | 按角色/权限控制按钮可见性 |
858
889
  | `window.$message` | 全局 toast(runtime 的 antd-app 注入,模块内直接用,**无需 import**) |
859
890
  | `useAuthStore` / `useUserStore` / `usePreferences` | 读 token / 用户 / 偏好 |
891
+ | `useTabsStore` | 页签(`setTableTitle(routePath, title)` / `resetTableTitle(routePath)`) |
892
+
893
+ **页签标题跟随内容**:页签文案默认取路由 `handle.title`(静态 i18n key),要让它跟随当前文档名等
894
+ **运行期数据**,在页面里把数据拿到后覆盖:
895
+
896
+ ```tsx
897
+ import { useTabsStore } from "@oj-module/runtime";
898
+
899
+ const setTableTitle = useTabsStore(s => s.setTableTitle);
900
+ const { pathname } = useLocation();
901
+
902
+ useEffect(() => {
903
+ if (doc?.name) setTableTitle(pathname, doc.name);
904
+ }, [doc?.name, pathname, setTableTitle]);
905
+ ```
906
+
907
+ 三点约束:
908
+
909
+ 1. 路径必须与导航路径**逐字一致**——页签 key 是 `removeTrailingSlash(location.pathname)` 归一后的值;
910
+ 2. `setTableTitle` 只改**已打开**的页签,故要在页面渲染后(数据就绪时)调用,不能提前于路由挂载;
911
+ 3. 只在页签 key 与内容**一一对应**时这样用(如 `/doc/:id`——一个 id 一个页签)。若同一路径会被
912
+ 复用展示不同内容(列表页/`index` 路由),离开时必须 `resetTableTitle(pathname)`,否则再进来看到
913
+ 上一个内容的标题。
860
914
 
861
915
  推荐形态(照 `web/src/home/pages/`、`web/src/personal-center/pages/my-profile/` 抄):
862
916
  `BasicContent` 包一层 → 搜索区 + `BasicTable` → 新增/编辑用 antd `Modal` + `Form`
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@oj-module/cli",
3
3
  "type": "module",
4
- "version": "0.1.14",
4
+ "version": "0.1.15",
5
5
  "description": "React Antd Admin 模块工程命令行工具(含预构建宿主 shell-dist)",
6
6
  "license": "MIT",
7
7
  "exports": {
@@ -49,7 +49,7 @@
49
49
  ],
50
50
  "dependencies": {
51
51
  "@faker-js/faker": "^10.4.0",
52
- "@oj-module/runtime": "0.1.14",
52
+ "@oj-module/runtime": "0.1.15",
53
53
  "@redocly/cli": "^2.51.0",
54
54
  "@tailwindcss/vite": "^4.3.0",
55
55
  "esbuild": "^0.28.2",
@@ -225,10 +225,10 @@ function getAppInfo() {
225
225
  return {
226
226
  "pkg": {
227
227
  "name": "@oj-module/runtime",
228
- "version": "0.1.14",
228
+ "version": "0.1.15",
229
229
  "license": "MIT"
230
230
  },
231
- "lastBuildTime": "2026-10-12 10:52:03"
231
+ "lastBuildTime": "2026-10-12 19:08:32"
232
232
  };
233
233
  }
234
234
  var init_get_app_info = __esmMin((() => {}));
@@ -8711,11 +8711,10 @@ function ensureReq() {
8711
8711
  /** ky HTTPError → ContractApiError(错误体为信封时取 code/msg);契约违例与原错误原样透传 */
8712
8712
  async function toApiError(e) {
8713
8713
  if (e instanceof ContractApiError) return e;
8714
- const res = e?.response;
8715
- if (res instanceof Response) try {
8716
- const env = await res.clone().json();
8717
- if (env && typeof env.code === "number") return new ContractApiError(env.code, env.msg ?? res.statusText);
8718
- } catch {}
8714
+ const err = e;
8715
+ const res = err?.response;
8716
+ const d = err?.data;
8717
+ if (res instanceof Response && d && typeof d.code === "number") return new ContractApiError(d.code, d.msg ?? res.statusText);
8719
8718
  return e;
8720
8719
  }
8721
8720
  async function fetchAddRoleItem$1(body) {
@@ -27407,6 +27406,7 @@ init_locales();
27407
27406
  init_module_loader();
27408
27407
  init_slots();
27409
27408
  init_auth();
27409
+ init_tabs();
27410
27410
  init_user();
27411
27411
  init_get_app_info();
27412
27412
  init_get_redirect_path();
@@ -27416,4 +27416,4 @@ init_ri();
27416
27416
  init_menu_icons();
27417
27417
  init_tree();
27418
27418
  //#endregion
27419
- export { AccessControl, AccessControlRoles, AntdApp, BasicButton, BasicContent, BasicTable, EmbeddedIcon, ErrorBoundary, ExternalIcon, FormAvatarItem, FormTreeItem, Iframe, LayoutCenterIcon, LayoutEffects, LayoutLeftIcon, LayoutRightIcon, MixedNavigationIcon, OutsidePageIcon, PageError, ProfileCardIcon, RiAccountCircleLine, RiContrastFill, RiFullscreenExitLine, RiFullscreenLine, RiMailCheckLine, RiMoonIcon, RiReactjsLine, RiSunIcon, RiUserSettingsLine, ServerErrorIcon, SideNavigationIcon, TopNavigationIcon, TwoColumnNavigationIcon, accessControlCodes, defineModule, fetchAddMenuItem, fetchAddRoleItem, fetchAsyncRoutes, fetchDeleteMenuItem, fetchDeleteRoleItem, fetchLogin, fetchLogout, fetchMenuByRoleId, fetchMenuList, fetchRefreshToken, fetchRoleList, fetchRoleMenu, fetchUpdateMenuItem, fetchUpdateRoleItem, fetchUserInfo, filterTree, getAllExpandedKeys, getAppInfo, getBooleanOptions, getModule, getModules, getRedirectPath, getRegisteredApiPrefix, getRegisteredStore, getRoutes, getYesNoOptions, handleTree, loadAll, mapTree, menuIcons, permissionPrefix, setupI18n, traverseTreeValues, unloadModule, useAccess, useAuthStore, usePreferences, useSlotNodes, useUserStore, external_exports as z };
27419
+ export { AccessControl, AccessControlRoles, AntdApp, BasicButton, BasicContent, BasicTable, EmbeddedIcon, ErrorBoundary, ExternalIcon, FormAvatarItem, FormTreeItem, Iframe, LayoutCenterIcon, LayoutEffects, LayoutLeftIcon, LayoutRightIcon, MixedNavigationIcon, OutsidePageIcon, PageError, ProfileCardIcon, RiAccountCircleLine, RiContrastFill, RiFullscreenExitLine, RiFullscreenLine, RiMailCheckLine, RiMoonIcon, RiReactjsLine, RiSunIcon, RiUserSettingsLine, ServerErrorIcon, SideNavigationIcon, TopNavigationIcon, TwoColumnNavigationIcon, accessControlCodes, defineModule, fetchAddMenuItem, fetchAddRoleItem, fetchAsyncRoutes, fetchDeleteMenuItem, fetchDeleteRoleItem, fetchLogin, fetchLogout, fetchMenuByRoleId, fetchMenuList, fetchRefreshToken, fetchRoleList, fetchRoleMenu, fetchUpdateMenuItem, fetchUpdateRoleItem, fetchUserInfo, filterTree, getAllExpandedKeys, getAppInfo, getBooleanOptions, getModule, getModules, getRedirectPath, getRegisteredApiPrefix, getRegisteredStore, getRoutes, getYesNoOptions, handleTree, loadAll, mapTree, menuIcons, permissionPrefix, setupI18n, traverseTreeValues, unloadModule, useAccess, useAuthStore, usePreferences, useSlotNodes, useTabsStore, useUserStore, external_exports as z };
@@ -5,9 +5,9 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" href="/favicon.ico" />
7
7
  <title>React Antd Admin · Shell</title>
8
- <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-ZmMlBNnCqyPnmo1SvWejxA=='; script-src-attr 'none'; connect-src 'self' data: https://modules.cdn.example.com; style-src 'self' https://modules.cdn.example.com 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; frame-src https://ant.design https://react.dev https://condorheroblog.github.io; form-action 'none'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests" />
8
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-BbpdKqCvQY8/k+rypZmAnw=='; script-src-attr 'none'; connect-src 'self' data: https://modules.cdn.example.com; style-src 'self' https://modules.cdn.example.com 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; frame-src https://ant.design https://react.dev https://condorheroblog.github.io; form-action 'none'; base-uri 'none'; object-src 'none'; upgrade-insecure-requests" />
9
9
 
10
- <script type="importmap" nonce="ZmMlBNnCqyPnmo1SvWejxA==">{
10
+ <script type="importmap" nonce="BbpdKqCvQY8/k+rypZmAnw==">{
11
11
  "imports": {
12
12
  "react": "/assets/react.js",
13
13
  "react/jsx-runtime": "/assets/jsx-runtime.js",
@@ -7,11 +7,11 @@
7
7
  "react-router": "7.18.2",
8
8
  "react-router/dom": "7.18.2",
9
9
  "@tanstack/react-query": "5.102.8",
10
- "@oj-module/runtime": "0.1.14",
11
- "@oj-module/runtime/contract": "0.1.14",
12
- "@oj-module/runtime/contract/errors": "0.1.14",
13
- "@plane/kit": "0.1.14",
14
- "@plane/editor": "0.1.14",
10
+ "@oj-module/runtime": "0.1.15",
11
+ "@oj-module/runtime/contract": "0.1.15",
12
+ "@oj-module/runtime/contract/errors": "0.1.15",
13
+ "@plane/kit": "0.1.15",
14
+ "@plane/editor": "0.1.15",
15
15
  "antd": "6.6.1",
16
16
  "antd/locale/en_US": "6.6.1",
17
17
  "antd/locale/zh_CN": "6.6.1",
package/src/build.ts CHANGED
@@ -72,6 +72,7 @@ export const permissionPrefix = "permission:button";
72
72
  // store
73
73
  export const useAuthStore = _fn;
74
74
  export const useUserStore = _fn;
75
+ export const useTabsStore = _fn;
75
76
  // 图标
76
77
  export const menuIcons = _obj;
77
78
  export const EmbeddedIcon = _fn;
@@ -286,15 +286,13 @@ ${binding}
286
286
  async function toApiError(e: unknown): Promise<unknown> {
287
287
  if (e instanceof ContractApiError)
288
288
  return e;
289
- const res = (e as { response?: Response } | null)?.response;
290
- if (res instanceof Response) {
291
- try {
292
- const env = await res.clone().json() as { code?: number, msg?: string } | null;
293
- if (env && typeof env.code === "number")
294
- return new ContractApiError(env.code, env.msg ?? res.statusText);
295
- }
296
- catch { /* 非 JSON 错误体——回退原错误 */ }
297
- }
289
+ // ky 2.x 构造 HTTPError 时已用 getReader() 消费掉原 response 体(res.clone().json() 按规范抛 TypeError,
290
+ // 体方法一律失效),解析好的错误体在公开字段 error.data——故读 error.data,勿改回 clone().json()。
291
+ const err = e as { data?: { code?: unknown, msg?: string }, response?: Response } | null;
292
+ const res = err?.response;
293
+ const d = err?.data;
294
+ if (res instanceof Response && d && typeof d.code === "number")
295
+ return new ContractApiError(d.code, d.msg ?? res.statusText);
298
296
  return e;
299
297
  }`;
300
298
  }
@@ -54,15 +54,13 @@ function ensureReq(): ScopedRequestLike {
54
54
  async function toApiError(e: unknown): Promise<unknown> {
55
55
  if (e instanceof ContractApiError)
56
56
  return e;
57
- const res = (e as { response?: Response } | null)?.response;
58
- if (res instanceof Response) {
59
- try {
60
- const env = await res.clone().json() as { code?: number, msg?: string } | null;
61
- if (env && typeof env.code === "number")
62
- return new ContractApiError(env.code, env.msg ?? res.statusText);
63
- }
64
- catch { /* 非 JSON 错误体——回退原错误 */ }
65
- }
57
+ // ky 2.x 构造 HTTPError 时已用 getReader() 消费掉原 response 体(res.clone().json() 按规范抛 TypeError,
58
+ // 体方法一律失效),解析好的错误体在公开字段 error.data——故读 error.data,勿改回 clone().json()。
59
+ const err = e as { data?: { code?: unknown, msg?: string }, response?: Response } | null;
60
+ const res = err?.response;
61
+ const d = err?.data;
62
+ if (res instanceof Response && d && typeof d.code === "number")
63
+ return new ContractApiError(d.code, d.msg ?? res.statusText);
66
64
  return e;
67
65
  }
68
66
 
@@ -8,11 +8,11 @@
8
8
  "react-router": "7.18.2",
9
9
  "react-router/dom": "7.18.2",
10
10
  "@tanstack/react-query": "5.102.8",
11
- "@oj-module/runtime": "0.1.14",
12
- "@oj-module/runtime/contract": "0.1.14",
13
- "@oj-module/runtime/contract/errors": "0.1.14",
14
- "@plane/kit": "0.1.14",
15
- "@plane/editor": "0.1.14",
11
+ "@oj-module/runtime": "0.1.15",
12
+ "@oj-module/runtime/contract": "0.1.15",
13
+ "@oj-module/runtime/contract/errors": "0.1.15",
14
+ "@plane/kit": "0.1.15",
15
+ "@plane/editor": "0.1.15",
16
16
  "antd": "6.6.1",
17
17
  "antd/locale/en_US": "6.6.1",
18
18
  "antd/locale/zh_CN": "6.6.1",