@oj-module/cli 0.2.28 → 0.2.30
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-FYt9CjFd.js} +54 -22
- 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/templates/src/system/web/entry.ts +5 -2
- 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.30",
|
|
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.30",
|
|
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,14 +231,58 @@ 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
|
+
repatchShellRoutes();
|
|
239
|
+
});
|
|
240
240
|
});
|
|
241
241
|
/**
|
|
242
|
+
* 宿主路由根 id:patchRoutes 重登记的 parentId(与 runtime 的 ROOT_ROUTE_ID
|
|
243
|
+
* 同名无碍——各自作用于各自 router 实例)。
|
|
244
|
+
*/
|
|
245
|
+
var SHELL_ROOT_ID = "shell-root";
|
|
246
|
+
/** Boot 建表后持有的宿主 router 实例;token 变化时按新角色快照重登记其路由表。 */
|
|
247
|
+
var shellRouter = null;
|
|
248
|
+
/**
|
|
249
|
+
* 宿主路由表 children:index 重定向 + 模块路由(getHostRoutes 同源重写)+
|
|
250
|
+
* catch-all 兜底。Boot 建表与登录后重登记共用同一构建口,保证两处同源。
|
|
251
|
+
*/
|
|
252
|
+
function buildShellChildren() {
|
|
253
|
+
const hostRoutes = getHostRoutes();
|
|
254
|
+
return [
|
|
255
|
+
{
|
|
256
|
+
index: true,
|
|
257
|
+
element: /* @__PURE__ */ jsx(Navigate, {
|
|
258
|
+
to: hostRoutes[0]?.path ?? "/",
|
|
259
|
+
replace: true
|
|
260
|
+
})
|
|
261
|
+
},
|
|
262
|
+
...hostRoutes,
|
|
263
|
+
{
|
|
264
|
+
path: "*",
|
|
265
|
+
element: /* @__PURE__ */ jsx(CatchAll, {})
|
|
266
|
+
}
|
|
267
|
+
];
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* 按当前角色快照重登记宿主路由表(B16 回归,2026-10-24)。
|
|
271
|
+
*
|
|
272
|
+
* setAccessStore 内部的 router.patchRoutes 打的是 runtime 单例 router,而宿主
|
|
273
|
+
* 渲染的是本文件 Boot 里自建的 router——仅调 setAccessStore 只会更新菜单
|
|
274
|
+
* (access store),路由表保持 Boot 期快照。后果:Boot 期 user-info 失败
|
|
275
|
+
* (后端闪断/过期 token 刷新失败)→ 角色空 → requiredRoles 门禁模块被过滤出
|
|
276
|
+
* 路由表;随后 SPA 登录(不刷新页面)菜单回来了,但 /system/* 仍不在路由表里,
|
|
277
|
+
* 直达恒落 catch-all 404「返回首页」,须硬刷新才恢复。
|
|
278
|
+
*/
|
|
279
|
+
function repatchShellRoutes() {
|
|
280
|
+
if (!shellRouter) return;
|
|
281
|
+
shellRouter.patchRoutes(SHELL_ROOT_ID, buildShellChildren());
|
|
282
|
+
const { pathname, search } = shellRouter.state.location;
|
|
283
|
+
shellRouter.navigate(`${pathname}${search}`, { replace: true }).catch(() => {});
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
242
286
|
* 直链兜底页(catch-all 路由元素)。无匹配路由时渲染框架 `PageError`,
|
|
243
287
|
* 把 title 设为框架 404 文案(`exception.notFoundTitle` = "404"),
|
|
244
288
|
* 观感与无权限面板同构,替代 React Router 默认的「Unexpected Application Error!」。
|
|
@@ -300,27 +344,14 @@ function Boot() {
|
|
|
300
344
|
await hydrateUser();
|
|
301
345
|
await loadAll(manifest);
|
|
302
346
|
if (cancelled) return;
|
|
303
|
-
|
|
304
|
-
setRouter(createBrowserRouter([{
|
|
347
|
+
shellRouter = createBrowserRouter([{
|
|
305
348
|
path: "/",
|
|
349
|
+
id: SHELL_ROOT_ID,
|
|
306
350
|
element: /* @__PURE__ */ jsxs(ErrorBoundary, {
|
|
307
351
|
FallbackComponent: PageError,
|
|
308
352
|
children: [/* @__PURE__ */ jsx(LayoutEffects, {}), /* @__PURE__ */ jsx(Outlet, {})]
|
|
309
353
|
}),
|
|
310
|
-
children:
|
|
311
|
-
{
|
|
312
|
-
index: true,
|
|
313
|
-
element: /* @__PURE__ */ jsx(Navigate, {
|
|
314
|
-
to: hostRoutes[0]?.path ?? "/",
|
|
315
|
-
replace: true
|
|
316
|
-
})
|
|
317
|
-
},
|
|
318
|
-
...hostRoutes,
|
|
319
|
-
{
|
|
320
|
-
path: "*",
|
|
321
|
-
element: /* @__PURE__ */ jsx(CatchAll, {})
|
|
322
|
-
}
|
|
323
|
-
]
|
|
354
|
+
children: buildShellChildren()
|
|
324
355
|
}], {
|
|
325
356
|
/**
|
|
326
357
|
* 子路径部署(oj `mounts: [{ prefix: /oj, web: dist, spa: true }]`):
|
|
@@ -331,7 +362,8 @@ function Boot() {
|
|
|
331
362
|
*
|
|
332
363
|
* 浏览器 URL 不受影响:react-router 只是在匹配/生成时剥/补前缀。
|
|
333
364
|
*/
|
|
334
|
-
basename: base })
|
|
365
|
+
basename: base });
|
|
366
|
+
setRouter(shellRouter);
|
|
335
367
|
} catch (e) {
|
|
336
368
|
if (!cancelled) setError(e instanceof Error ? e.message : String(e));
|
|
337
369
|
}
|
|
@@ -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.30",
|
|
308
308
|
"license": "MIT"
|
|
309
309
|
},
|
|
310
|
-
"lastBuildTime": "2026-10-24
|
|
310
|
+
"lastBuildTime": "2026-10-24 23:41:26"
|
|
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-6NpMECPEhWQb/Ob12W+5HQ=='; 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="6NpMECPEhWQb/Ob12W+5HQ==">{
|
|
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-FYt9CjFd.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.30",
|
|
11
|
+
"@oj-module/runtime/contract": "0.2.30",
|
|
12
|
+
"@oj-module/runtime/contract/errors": "0.2.30",
|
|
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
|
});
|
|
@@ -73,8 +73,11 @@ export default defineModule({
|
|
|
73
73
|
peerRuntime: ">=0.0.0",
|
|
74
74
|
// 路由级门禁(B16):非系统管理员不注入 /system 路由、菜单不可见;
|
|
75
75
|
// API 级 403 由 assertSystemAdmin + service 层硬 enforcement 兜底。
|
|
76
|
-
// 角色口径对齐后端 assertSystemAdmin(access.ts:
|
|
77
|
-
// admin
|
|
76
|
+
// 角色口径对齐后端 assertSystemAdmin(access.ts:87)——superadmin **或**
|
|
77
|
+
// admin 均可,两者必须同时保留:D12(2026-10-22)起账号名=角色名,admin 与
|
|
78
|
+
// superadmin 是两个独立账号(seed.sql),只留 ["admin"] 会把 superadmin 挡在
|
|
79
|
+
// 门外(注册期过滤 → 路由消失 → 登录后 404 兜底)。改这两个值前先跑
|
|
80
|
+
// tests/system-guard.regression.spec.ts(只留 ["admin"] 会立刻变红)。
|
|
78
81
|
config: { requiredRoles: ["admin", "superadmin"] },
|
|
79
82
|
routes,
|
|
80
83
|
i18n: {
|
|
@@ -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.30",
|
|
12
|
+
"@oj-module/runtime/contract": "0.2.30",
|
|
13
|
+
"@oj-module/runtime/contract/errors": "0.2.30",
|
|
14
14
|
"@plane/kit": "0.1.20",
|
|
15
15
|
"@plane/editor": "0.1.20",
|
|
16
16
|
"antd": "6.6.1",
|