@oj-module/cli 0.2.28 → 0.2.29
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 +2 -2
- package/shell-dist/assets/{index-CtTVbohp.js → index-CnJsHOe-.js} +4 -5
- package/shell-dist/assets/runtime.js +4 -3
- package/shell-dist/index.html +3 -3
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/listen-on-free-port.test.ts +39 -0
- package/src/build.ts +1 -0
- package/src/static-handler.ts +18 -3
- package/vendor/host-versions.json +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oj-module/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.29",
|
|
5
5
|
"description": "React Antd 模块工程命令行工具(含预构建宿主 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.2.
|
|
52
|
+
"@oj-module/runtime": "0.2.29",
|
|
53
53
|
"@redocly/cli": "^2.51.0",
|
|
54
54
|
"@tailwindcss/vite": "^4.3.0",
|
|
55
55
|
"cac": "^6.7.14",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StyleProvider } from "@ant-design/cssinjs";
|
|
2
|
-
import { AntdApp, ErrorBoundary, LayoutEffects, PageError, getHostRoutes, loadAll, setupI18n, useAuthStore, usePreferences, useUserStore } from "@oj-module/runtime";
|
|
2
|
+
import { AntdApp, ErrorBoundary, LayoutEffects, PageError, getHostRoutes, getRoutes, loadAll, setupI18n, useAccessStore, useAuthStore, usePreferences, useUserStore } from "@oj-module/runtime";
|
|
3
3
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
4
4
|
import { ConfigProvider, theme } from "antd";
|
|
5
5
|
import { useEffect, useState } from "react";
|
|
@@ -231,12 +231,11 @@ async function hydrateUser() {
|
|
|
231
231
|
/**
|
|
232
232
|
* 登录/登出都会经 auth store reset() 清空 user store(宿主链无 AuthGuard 重新
|
|
233
233
|
* 拉取),token 变化即重新定角色。
|
|
234
|
-
*
|
|
235
|
-
* 已知偏差:角色变化只影响渲染期判断,侧栏菜单是 Boot 期按当时角色登记的,
|
|
236
|
-
* 不登录直接进站再登录的场景菜单需刷新一次才对(后端 403 硬兜底,不是权限泄漏)。
|
|
237
234
|
*/
|
|
238
235
|
useAuthStore.subscribe((state, prev) => {
|
|
239
|
-
if (state.token !== prev.token) hydrateUser()
|
|
236
|
+
if (state.token !== prev.token) hydrateUser().then(() => {
|
|
237
|
+
useAccessStore.getState().setAccessStore(getRoutes());
|
|
238
|
+
});
|
|
240
239
|
});
|
|
241
240
|
/**
|
|
242
241
|
* 直链兜底页(catch-all 路由元素)。无匹配路由时渲染框架 `PageError`,
|
|
@@ -304,10 +304,10 @@ function getAppInfo() {
|
|
|
304
304
|
return {
|
|
305
305
|
"pkg": {
|
|
306
306
|
"name": "@oj-module/runtime",
|
|
307
|
-
"version": "0.2.
|
|
307
|
+
"version": "0.2.29",
|
|
308
308
|
"license": "MIT"
|
|
309
309
|
},
|
|
310
|
-
"lastBuildTime": "2026-10-24
|
|
310
|
+
"lastBuildTime": "2026-10-24 20:31:54"
|
|
311
311
|
};
|
|
312
312
|
}
|
|
313
313
|
var init_get_app_info = __esmMin((() => {}));
|
|
@@ -28190,6 +28190,7 @@ init_layout_effects();
|
|
|
28190
28190
|
init_locales();
|
|
28191
28191
|
init_module_loader();
|
|
28192
28192
|
init_slots();
|
|
28193
|
+
init_access();
|
|
28193
28194
|
init_auth();
|
|
28194
28195
|
init_tabs();
|
|
28195
28196
|
init_user();
|
|
@@ -28203,4 +28204,4 @@ init_ri();
|
|
|
28203
28204
|
init_menu_icons();
|
|
28204
28205
|
init_tree();
|
|
28205
28206
|
//#endregion
|
|
28206
|
-
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, bindingDiff, canAssignRole, canDeleteRole, canEditRoleBindings, defineModule, fetchAddMenuItem, fetchAddRoleItem, fetchAsyncRoutes, fetchChangePassword, fetchDeleteMenuItem, fetchDeleteRoleItem, fetchLdapLogin, fetchLogin, fetchLoginMethods, fetchLogout, fetchMenuByRoleId, fetchMenuList, fetchRbacAdminResetPassword, fetchRbacContactDetail, fetchRbacContacts, fetchRbacCreateRole, fetchRbacCreateUser, fetchRbacDeleteRole, fetchRbacOplog, fetchRbacOplogPost, fetchRbacPermissionList, fetchRbacRoleList, fetchRbacSetForbidden, fetchRbacSettings, fetchRbacUpdateBindings, fetchRbacUpdateSetting, fetchRbacUpdateUserRoles, fetchRbacUserList, fetchRefreshToken, fetchRoleList, fetchRoleMenu, fetchSolutionRoutes, fetchUpdateMenuItem, fetchUpdateRoleItem, fetchUserInfo, filterTree, getAllExpandedKeys, getAppInfo, getBooleanOptions, getHostRoutes, getModule, getModuleRoutePrefix, getModules, getRedirectPath, getRegisteredApiPrefix, getRegisteredStore, getRoutes, getYesNoOptions, groupByModule, groupSettingsByModule, handleTree, loadAll, mapTree, menuIcons, notify, permissionPrefix, request, resolveSiteBase, roleLabel, setupI18n, traverseTreeValues, unloadModule, useAccess, useAuthStore, usePreferences, useSlotNodes, useSolutionRoutes, useTabKey, useTabsStore, useUserStore, withSiteBase, external_exports as z };
|
|
28207
|
+
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, bindingDiff, canAssignRole, canDeleteRole, canEditRoleBindings, defineModule, fetchAddMenuItem, fetchAddRoleItem, fetchAsyncRoutes, fetchChangePassword, fetchDeleteMenuItem, fetchDeleteRoleItem, fetchLdapLogin, fetchLogin, fetchLoginMethods, fetchLogout, fetchMenuByRoleId, fetchMenuList, fetchRbacAdminResetPassword, fetchRbacContactDetail, fetchRbacContacts, fetchRbacCreateRole, fetchRbacCreateUser, fetchRbacDeleteRole, fetchRbacOplog, fetchRbacOplogPost, fetchRbacPermissionList, fetchRbacRoleList, fetchRbacSetForbidden, fetchRbacSettings, fetchRbacUpdateBindings, fetchRbacUpdateSetting, fetchRbacUpdateUserRoles, fetchRbacUserList, fetchRefreshToken, fetchRoleList, fetchRoleMenu, fetchSolutionRoutes, fetchUpdateMenuItem, fetchUpdateRoleItem, fetchUserInfo, filterTree, getAllExpandedKeys, getAppInfo, getBooleanOptions, getHostRoutes, getModule, getModuleRoutePrefix, getModules, getRedirectPath, getRegisteredApiPrefix, getRegisteredStore, getRoutes, getYesNoOptions, groupByModule, groupSettingsByModule, handleTree, loadAll, mapTree, menuIcons, notify, permissionPrefix, request, resolveSiteBase, roleLabel, setupI18n, traverseTreeValues, unloadModule, useAccess, useAccessStore, useAuthStore, usePreferences, useSlotNodes, useSolutionRoutes, useTabKey, useTabsStore, useUserStore, withSiteBase, external_exports as z };
|
package/shell-dist/index.html
CHANGED
|
@@ -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-
|
|
8
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-5zLHUGQHePNQzqOPB7RBQA=='; 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="
|
|
10
|
+
<script type="importmap" nonce="5zLHUGQHePNQzqOPB7RBQA==">{
|
|
11
11
|
"imports": {
|
|
12
12
|
"react": "/assets/react.js",
|
|
13
13
|
"react/jsx-runtime": "/assets/jsx-runtime.js",
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
"dayjs/locale/zh-cn": "/assets/ojm-dayjs-locale-zh-cn.js"
|
|
134
134
|
}
|
|
135
135
|
}</script>
|
|
136
|
-
<script type="module" crossorigin src="/assets/index-
|
|
136
|
+
<script type="module" crossorigin src="/assets/index-CnJsHOe-.js"></script>
|
|
137
137
|
</head>
|
|
138
138
|
<body>
|
|
139
139
|
<div id="root"></div>
|
package/shell-dist/versions.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
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.2.
|
|
11
|
-
"@oj-module/runtime/contract": "0.2.
|
|
12
|
-
"@oj-module/runtime/contract/errors": "0.2.
|
|
10
|
+
"@oj-module/runtime": "0.2.29",
|
|
11
|
+
"@oj-module/runtime/contract": "0.2.29",
|
|
12
|
+
"@oj-module/runtime/contract/errors": "0.2.29",
|
|
13
13
|
"@plane/kit": "0.1.20",
|
|
14
14
|
"@plane/editor": "0.1.20",
|
|
15
15
|
"antd": "6.6.1",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Server } from "node:http";
|
|
2
|
+
import type { AddressInfo } from "node:net";
|
|
3
|
+
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
import { listenOnFreePort } from "../static-handler";
|
|
8
|
+
|
|
9
|
+
// 回归:listen(port, cb) 的 cb 在重试成功后以旧端口先 resolve——
|
|
10
|
+
// 日志「改用 5175」与「已启动 5174」并存且实际监听在 5175(2026-10-24)。
|
|
11
|
+
describe("listenOnFreePort", () => {
|
|
12
|
+
const cleanup: Server[] = [];
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
for (const s of cleanup.splice(0))
|
|
16
|
+
s.close();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("占用首端口时顺延,返回端口与实际监听端口一致", async () => {
|
|
20
|
+
const occupier = http.createServer(() => {}).listen(0);
|
|
21
|
+
cleanup.push(occupier);
|
|
22
|
+
await new Promise<void>(r => occupier.on("listening", r));
|
|
23
|
+
const busy = (occupier.address() as AddressInfo).port;
|
|
24
|
+
|
|
25
|
+
const server = http.createServer(() => {});
|
|
26
|
+
cleanup.push(server);
|
|
27
|
+
const port = await listenOnFreePort(server, busy);
|
|
28
|
+
expect(port).toBe(busy + 1);
|
|
29
|
+
// 旧 bug 在此暴露:resolve 的是 busy,实际却监听在 busy+1
|
|
30
|
+
expect((server.address() as AddressInfo).port).toBe(port);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("首端口空闲时原样监听", async () => {
|
|
34
|
+
const server = http.createServer(() => {});
|
|
35
|
+
cleanup.push(server);
|
|
36
|
+
const port = await listenOnFreePort(server, 0);
|
|
37
|
+
expect((server.address() as AddressInfo).port).toBe(port);
|
|
38
|
+
});
|
|
39
|
+
});
|
package/src/build.ts
CHANGED
|
@@ -106,6 +106,7 @@ export const accessControlCodes = _obj;
|
|
|
106
106
|
export const AccessControlRoles = _obj;
|
|
107
107
|
export const permissionPrefix = "permission:button";
|
|
108
108
|
// store
|
|
109
|
+
export const useAccessStore = _fn;
|
|
109
110
|
export const useAuthStore = _fn;
|
|
110
111
|
// 方案路由归并 store(token 就绪自动重拉,R21)
|
|
111
112
|
export const useSolutionRoutes = _fn;
|
package/src/static-handler.ts
CHANGED
|
@@ -229,7 +229,14 @@ export function createStaticHandler(opts: StaticHandlerOptions): (req: http.Inco
|
|
|
229
229
|
export function listenOnFreePort(server: http.Server, startPort: number, maxTries = 10): Promise<number> {
|
|
230
230
|
return new Promise((resolve, reject) => {
|
|
231
231
|
const attempt = (port: number) => {
|
|
232
|
-
|
|
232
|
+
// 回调手动挂/摘(listen(port, cb) 的 cb 摘不掉前次失败的滞留闭包,
|
|
233
|
+
// 重试成功时会以旧端口先 resolve——日志与实listen端口漂移,2026-10-24 实测)
|
|
234
|
+
function cleanup() {
|
|
235
|
+
server.off("error", onError);
|
|
236
|
+
server.off("listening", onListen);
|
|
237
|
+
}
|
|
238
|
+
function onError(err: NodeJS.ErrnoException) {
|
|
239
|
+
cleanup();
|
|
233
240
|
if (err.code === "EADDRINUSE" && port - startPort < maxTries) {
|
|
234
241
|
console.warn(`[ojm] 端口 ${port} 已被占用,改用 ${port + 1}`);
|
|
235
242
|
attempt(port + 1);
|
|
@@ -237,8 +244,16 @@ export function listenOnFreePort(server: http.Server, startPort: number, maxTrie
|
|
|
237
244
|
else {
|
|
238
245
|
reject(err);
|
|
239
246
|
}
|
|
240
|
-
}
|
|
241
|
-
|
|
247
|
+
}
|
|
248
|
+
function onListen() {
|
|
249
|
+
cleanup();
|
|
250
|
+
// 取实绑端口(startPort=0 时 OS 自分随机端口,闭包 port 不可信)
|
|
251
|
+
const addr = server.address();
|
|
252
|
+
resolve(typeof addr === "object" && addr ? addr.port : port);
|
|
253
|
+
}
|
|
254
|
+
server.once("error", onError);
|
|
255
|
+
server.once("listening", onListen);
|
|
256
|
+
server.listen(port);
|
|
242
257
|
};
|
|
243
258
|
attempt(startPort);
|
|
244
259
|
});
|
|
@@ -8,9 +8,9 @@
|
|
|
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.2.
|
|
12
|
-
"@oj-module/runtime/contract": "0.2.
|
|
13
|
-
"@oj-module/runtime/contract/errors": "0.2.
|
|
11
|
+
"@oj-module/runtime": "0.2.29",
|
|
12
|
+
"@oj-module/runtime/contract": "0.2.29",
|
|
13
|
+
"@oj-module/runtime/contract/errors": "0.2.29",
|
|
14
14
|
"@plane/kit": "0.1.20",
|
|
15
15
|
"@plane/editor": "0.1.20",
|
|
16
16
|
"antd": "6.6.1",
|