@oj-module/cli 0.2.49 → 0.2.53
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/devkit/README.md +8 -6
- package/devkit/SKILL.md +32 -12
- package/devkit/manual.md +6 -3
- package/devkit/wecom-daikaifa.md +95 -1
- package/devkit/wecom-internal-app.md +750 -0
- package/package.json +2 -2
- package/shell-dist/assets/{index-FYt9CjFd.js → index-e_Mp2mb5.js} +5 -1
- package/shell-dist/assets/runtime.js +24 -3
- package/shell-dist/index.html +9 -12
- package/shell-dist/versions.json +3 -3
- package/src/build.ts +19 -2
- package/src/init.ts +5 -4
- package/src/shared-deps.ts +27 -9
- package/src/site-base.ts +1 -1
- package/templates/config.yaml +28 -6
- package/templates/init.include.yaml +4 -7
- package/templates/openapi.json +2636 -2356
- package/templates/src/_platform/api/_shared/service/domain/users.ts +40 -4
- package/templates/src/auth/api/_shared/wecom/admin.ts +91 -7
- package/templates/src/auth/api/_shared/wecom/client.ts +9 -2
- package/templates/src/auth/api/_shared/wecom/config.ts +256 -46
- package/templates/src/auth/api/_shared/wecom/contacts.ts +7 -1
- package/templates/src/auth/api/_shared/wecom/events.ts +28 -6
- package/templates/src/auth/api/_shared/wecom/login.ts +21 -13
- package/templates/src/auth/api/_shared/wecom/store.ts +61 -12
- package/templates/src/auth/api/_shared/wecom/sync.ts +11 -1
- package/templates/src/auth/api/_shared/wecom/tenant-admin.ts +194 -0
- package/templates/src/auth/api/migrations/0003__credential_kind.mysql.sql +3 -0
- package/templates/src/auth/api/migrations/0003__credential_kind.pg.sql +3 -0
- package/templates/src/auth/api/migrations/0003__credential_kind.sql +9 -0
- package/templates/src/auth/api/schema.yaml +2 -0
- package/templates/src/auth/api/wecom/admin/api.ts +112 -11
- package/templates/src/auth/api/wecom/admin/tenant-admin/api.ts +41 -0
- package/templates/src/auth/api/wecom/admin/tenant-admin/password/api.ts +66 -0
- package/templates/src/auth/api/wecom/api.ts +102 -48
- package/templates/src/auth/api/wecom/sync/api.ts +21 -5
- package/templates/src/auth/web/__client/api.schemas.ts +22 -1
- package/templates/src/auth/web/__client/api.ts +47 -1
- package/templates/src/login/web/pages/login.tsx +54 -24
- package/templates/src/system/api/settings/api.ts +3 -3
- package/templates/src/system/web/entry.ts +4 -4
- package/templates/src/system/web/locales/en-US.json +38 -1
- package/templates/src/system/web/locales/zh-CN.json +38 -1
- package/templates/src/system/web/pages/departments/sync-bar.tsx +32 -7
- package/templates/src/system/web/pages/users/index.tsx +7 -4
- package/templates/src/system/web/pages/users/roles.tsx +14 -3
- package/templates/src/system/web/pages/wecom/index.tsx +292 -45
- package/templates/tests/wecom-admin.spec.ts +7 -7
- package/templates/tests/wecom-connector.spec.ts +7 -6
- package/templates/tests/wecom-corp.spec.ts +523 -0
- package/templates/tests/wecom-endpoints.spec.ts +10 -4
- package/templates/tests/wecom-org-sync.spec.ts +7 -1
- package/templates/tsconfig.paths.json +0 -1
- package/templates/web.config.ts +1 -2
- package/vendor/host-versions.json +3 -3
- package/shell-dist/assets/echarts-charts.js +0 -58571
- package/shell-dist/assets/echarts-features.js +0 -24057
- package/shell-dist/assets/echarts-for-react.js +0 -704
- package/shell-dist/assets/echarts.js +0 -82916
- package/shell-dist/assets/editor.js +0 -161457
- package/shell-dist/assets/vditor-index-css.js +0 -7
- package/shell-dist/assets/vditor.js +0 -15223
- package/templates/src/demo/api/manifest.yaml +0 -5
- package/templates/src/demo/api/migrations/0001__create_todos.sql +0 -9
- package/templates/src/demo/api/migrations/0002__tenant.mysql.sql +0 -2
- package/templates/src/demo/api/migrations/0002__tenant.sql +0 -2
- package/templates/src/demo/api/schema.yaml +0 -12
- package/templates/src/demo/api/seed.sql +0 -5
- package/templates/src/demo/api/todos/api.ts +0 -59
- package/templates/src/demo/web/__client/api.schemas.ts +0 -20
- package/templates/src/demo/web/__client/api.ts +0 -89
- package/templates/src/demo/web/entry.ts +0 -42
- package/templates/src/demo/web/locales/en-US.json +0 -10
- package/templates/src/demo/web/locales/zh-CN.json +0 -10
- package/templates/src/demo/web/pages/index.tsx +0 -45
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.53",
|
|
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.53",
|
|
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, getRoutes, loadAll, setupI18n, useAccessStore, useAuthStore, usePreferences, useUserStore } from "@oj-module/runtime";
|
|
2
|
+
import { AntdApp, ErrorBoundary, LayoutEffects, PageError, getHostRoutes, getRoutes, loadAll, resolveApiBase, 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";
|
|
@@ -312,6 +312,10 @@ function Boot() {
|
|
|
312
312
|
let cancelled = false;
|
|
313
313
|
(async () => {
|
|
314
314
|
try {
|
|
315
|
+
if (typeof navigator !== "undefined" && /wxwork/i.test(navigator.userAgent) && location.pathname.endsWith("/login") && !new URLSearchParams(location.search).get("wecom_ticket")) {
|
|
316
|
+
window.location.assign(resolveApiBase() + "/auth/wecom/login");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
315
319
|
ensureI18n();
|
|
316
320
|
const base = resolveSiteBase();
|
|
317
321
|
const [res, versionsRes] = await Promise.all([fetch(`${base}modules.json`), fetch(`${base}versions.json`).catch(() => null)]);
|
|
@@ -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.53",
|
|
308
308
|
"license": "MIT"
|
|
309
309
|
},
|
|
310
|
-
"lastBuildTime": "2026-11-
|
|
310
|
+
"lastBuildTime": "2026-11-02 15:46:13"
|
|
311
311
|
};
|
|
312
312
|
}
|
|
313
313
|
var init_get_app_info = __esmMin((() => {}));
|
|
@@ -7687,6 +7687,27 @@ function buildInstance(entry, definition, status, error) {
|
|
|
7687
7687
|
error
|
|
7688
7688
|
};
|
|
7689
7689
|
}
|
|
7690
|
+
/**
|
|
7691
|
+
* 按 `handle.roles` 递归过滤路由(菜单与路由表同源)。
|
|
7692
|
+
*
|
|
7693
|
+
* 模块级 `config.requiredRoles` 只能整包放行/拦截;一个模块里既有全员可见页、
|
|
7694
|
+
* 又有仅超管可见页(/system/settings、/system/wecom)时,需要路由级粒度。
|
|
7695
|
+
* 语义与前端静态路由(generateRoutesByFrontend)一致:未声明 = 不限制;
|
|
7696
|
+
* 声明了则命中任一角色才保留,否则连同子树一起剔除。
|
|
7697
|
+
*/
|
|
7698
|
+
function filterRoutesByRoles(routes, roles) {
|
|
7699
|
+
const out = [];
|
|
7700
|
+
for (const route of routes) {
|
|
7701
|
+
const required = route.handle?.roles;
|
|
7702
|
+
if (required?.length && !required.some((role) => roles.includes(role))) continue;
|
|
7703
|
+
const children = "children" in route && Array.isArray(route.children) ? filterRoutesByRoles(route.children, roles) : void 0;
|
|
7704
|
+
out.push(children ? {
|
|
7705
|
+
...route,
|
|
7706
|
+
children
|
|
7707
|
+
} : route);
|
|
7708
|
+
}
|
|
7709
|
+
return out;
|
|
7710
|
+
}
|
|
7690
7711
|
function getRoutes() {
|
|
7691
7712
|
const { roles, permissions = [] } = useUserStore.getState();
|
|
7692
7713
|
const routes = [];
|
|
@@ -7696,7 +7717,7 @@ function getRoutes() {
|
|
|
7696
7717
|
if (requiredRoles?.length && !requiredRoles.some((role) => roles.includes(role))) continue;
|
|
7697
7718
|
const requiredPermissions = instance.definition.config?.requiredPermissions;
|
|
7698
7719
|
if (requiredPermissions?.length && !requiredPermissions.every((perm) => permissions.includes(perm))) continue;
|
|
7699
|
-
if (instance.definition.routes.length > 0) routes.push(...resolveRouteLayouts(tagModuleRoutes(instance.definition.routes, instance.definition.name)));
|
|
7720
|
+
if (instance.definition.routes.length > 0) routes.push(...filterRoutesByRoles(resolveRouteLayouts(tagModuleRoutes(instance.definition.routes, instance.definition.name)), roles));
|
|
7700
7721
|
}
|
|
7701
7722
|
return addRouteIdByPath(routes);
|
|
7702
7723
|
}
|
package/shell-dist/index.html
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
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-
|
|
9
|
-
|
|
10
|
-
<script type="importmap" nonce="E48VJYAFCfSkkLa0nv6GVw==">{
|
|
8
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://modules.cdn.example.com 'wasm-unsafe-eval' 'nonce-vlbkVLVjOGWbsP3B+GCfRg=='; 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
|
+
<script type="importmap" nonce="vlbkVLVjOGWbsP3B+GCfRg==">{
|
|
11
10
|
"imports": {
|
|
12
11
|
"react": "/assets/react.js",
|
|
13
12
|
"react/jsx-runtime": "/assets/jsx-runtime.js",
|
|
@@ -21,7 +20,6 @@
|
|
|
21
20
|
"@oj-module/runtime/contract": "/assets/contract.js",
|
|
22
21
|
"@oj-module/runtime/contract/errors": "/assets/contract-errors.js",
|
|
23
22
|
"@plane/kit": "/assets/kit.js",
|
|
24
|
-
"@plane/editor": "/assets/editor.js",
|
|
25
23
|
"antd": "/assets/antd.js",
|
|
26
24
|
"antd/locale/en_US": "/assets/antd-locale-en_US.js",
|
|
27
25
|
"antd/locale/zh_CN": "/assets/antd-locale-zh_CN.js",
|
|
@@ -50,10 +48,6 @@
|
|
|
50
48
|
"dayjs/plugin/weekday": "/assets/dayjs-plugin-weekday.js",
|
|
51
49
|
"dayjs/plugin/weekOfYear": "/assets/dayjs-plugin-weekOfYear.js",
|
|
52
50
|
"dayjs/plugin/weekYear": "/assets/dayjs-plugin-weekYear.js",
|
|
53
|
-
"echarts": "/assets/echarts.js",
|
|
54
|
-
"echarts/charts": "/assets/echarts-charts.js",
|
|
55
|
-
"echarts/features.js": "/assets/echarts-features.js",
|
|
56
|
-
"echarts-for-react": "/assets/echarts-for-react.js",
|
|
57
51
|
"motion": "/assets/motion.js",
|
|
58
52
|
"motion/react": "/assets/motion-react.js",
|
|
59
53
|
"@dnd-kit/core": "/assets/dnd-kit-core.js",
|
|
@@ -73,8 +67,6 @@
|
|
|
73
67
|
"simplebar-react": "/assets/simplebar-react.js",
|
|
74
68
|
"spin-delay": "/assets/spin-delay.js",
|
|
75
69
|
"tailwind-merge": "/assets/tailwind-merge.js",
|
|
76
|
-
"vditor": "/assets/vditor.js",
|
|
77
|
-
"vditor/dist/index.css": "/assets/vditor-index-css.js",
|
|
78
70
|
"antd/es/modal": "/assets/ojm-antd-es-modal.js",
|
|
79
71
|
"antd/es/upload": "/assets/ojm-antd-es-upload.js",
|
|
80
72
|
"antd/es/button": "/assets/ojm-antd-es-button.js",
|
|
@@ -133,9 +125,14 @@
|
|
|
133
125
|
"dayjs/locale/zh-cn": "/assets/ojm-dayjs-locale-zh-cn.js"
|
|
134
126
|
}
|
|
135
127
|
}</script>
|
|
136
|
-
<
|
|
128
|
+
<style>
|
|
129
|
+
.boot-skeleton{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;color:#999;font-size:14px;background:#fff;z-index:9999}
|
|
130
|
+
.boot-skeleton:after{content:"";width:18px;height:18px;margin-left:8px;border:2px solid #d9d9d9;border-top-color:#1677ff;border-radius:50%;animation:bs-spin .8s linear infinite}
|
|
131
|
+
@keyframes bs-spin{to{transform:rotate(360deg)}}
|
|
132
|
+
</style>
|
|
133
|
+
<script nonce="vlbkVLVjOGWbsP3B+GCfRg==" data-ojm-entry="/assets/index-e_Mp2mb5.js">(function(){try{var ua=(navigator.userAgent||"").toLowerCase(),p=location.pathname;while(p.length>1&&p.charAt(p.length-1)==="/")p=p.slice(0,-1);if(ua.indexOf("wxwork")>=0&&p.slice(-6)==="/login"&&!new URLSearchParams(location.search).get("wecom_ticket")){var a=(typeof window.__OJ_API_BASE__==="string"&&window.__OJ_API_BASE__.trim())||"/api";while(a.length>1&&a.charAt(a.length-1)==="/")a=a.slice(0,-1);location.replace(a+"/auth/wecom/login");return}}catch(e){}var s=document.createElement("script");s.type="module";s.src=document.currentScript.getAttribute("data-ojm-entry");document.head.appendChild(s);})();</script>
|
|
137
134
|
</head>
|
|
138
135
|
<body>
|
|
139
|
-
<div id="root"></div>
|
|
136
|
+
<div id="root"><div class="boot-skeleton">加载中…</div></div>
|
|
140
137
|
</body>
|
|
141
138
|
</html>
|
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.53",
|
|
11
|
+
"@oj-module/runtime/contract": "0.2.53",
|
|
12
|
+
"@oj-module/runtime/contract/errors": "0.2.53",
|
|
13
13
|
"@plane/kit": "0.1.20",
|
|
14
14
|
"@plane/editor": "0.1.20",
|
|
15
15
|
"antd": "6.6.1",
|
package/src/build.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { ALIAS_PATHS_FILE, syncAliasPaths } from "./alias-paths";
|
|
|
16
16
|
import { assertModuleList, loadSiteConfig, mergeModuleList, resolveModuleEntry } from "./config";
|
|
17
17
|
import { moduleDir, resolveConfigPath, resolveLayout, scanModules, tryResolveLayout } from "./layout";
|
|
18
18
|
import { requireModuleRootCapability } from "./oj-caps";
|
|
19
|
-
import { isSharedDep, SHARED_DEPS } from "./shared-deps";
|
|
19
|
+
import { isPrebuiltDep, isSharedDep, SHARED_DEPS } from "./shared-deps";
|
|
20
20
|
import { normalizeSiteBase, rewriteIndexHtml } from "./site-base";
|
|
21
21
|
import { resolveOjBin } from "./vendor";
|
|
22
22
|
import { checkSharedVersions, resolveShellDist } from "./versions";
|
|
@@ -790,7 +790,7 @@ export async function buildModules(
|
|
|
790
790
|
rolldownOptions: {
|
|
791
791
|
// 只把共享依赖留给宿主 importmap;
|
|
792
792
|
// 相对路径 / 绝对路径是模块自身代码,需要打包
|
|
793
|
-
external: (id: string) => !id.startsWith(".") && !path.isAbsolute(id) &&
|
|
793
|
+
external: (id: string) => !id.startsWith(".") && !path.isAbsolute(id) && isPrebuiltDep(id),
|
|
794
794
|
output: {
|
|
795
795
|
// P7.x / e2e:模块产物内联动态 import(lazy 页面、i18n 等),
|
|
796
796
|
// 输出为**单文件**。原因:
|
|
@@ -807,6 +807,23 @@ export async function buildModules(
|
|
|
807
807
|
},
|
|
808
808
|
});
|
|
809
809
|
|
|
810
|
+
// 运行期 require 门禁:CJS 依赖 require 了 external 共享包时,rolldown 只留一个浏览器
|
|
811
|
+
// 不可用的 require 桩("Calling `require` for ..."),表现为模块加载即抛错、页面空白。
|
|
812
|
+
// 这类依赖必须移出 bundle 走宿主 importmap(shell 侧有 CJS→ESM 垫片)。
|
|
813
|
+
const builtEntry = path.join(moduleOutDir, "entry.js");
|
|
814
|
+
if (fs.existsSync(builtEntry)) {
|
|
815
|
+
const code = fs.readFileSync(builtEntry, "utf-8");
|
|
816
|
+
if (code.includes("doesn't expose the `require` function")) {
|
|
817
|
+
const specs = [...new Set([...code.matchAll(/ne\("([^"]+)"\)/g)].map(m => m[1]))];
|
|
818
|
+
throw new Error(
|
|
819
|
+
`[ojm] ${definition.name}@${definition.version} 产物含运行期 require(${specs.join(", ") || "?"})`
|
|
820
|
+
+ "——浏览器没有 require,模块加载即抛错。"
|
|
821
|
+
+ "根因:该 CJS 依赖被标为 bundle(自带副本),但它 require 的共享包被 external 了。"
|
|
822
|
+
+ "修复:把它从 SHARED_DEPS 的 bundle 列表移回共享资产,或改用该依赖的 ESM 入口。",
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
810
827
|
const prefix = `${baseUrl}/modules/${definition.name}/${definition.version}/`;
|
|
811
828
|
const chunks: ChunkEntry[] = [];
|
|
812
829
|
const css: string[] = [];
|
package/src/init.ts
CHANGED
|
@@ -193,10 +193,11 @@ export async function initProject(destDir: string, opts: InitOptions = {}): Prom
|
|
|
193
193
|
if (fs.existsSync(path.join(cliDevkit, "SKILL.md"))) {
|
|
194
194
|
const ojmSkillDir = path.join(destDir, ".claude/skills/ojm-module-dev");
|
|
195
195
|
fs.mkdirSync(ojmSkillDir, { recursive: true });
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
199
|
-
|
|
196
|
+
// 企微两本手册随之分发——它们讲的是「怎么把一个已经写好的连接器接上真实企业」,
|
|
197
|
+
// 业务工程拿到模板后自助完成对接要用,不能只留本仓:
|
|
198
|
+
// · `wecom-daikaifa.md` 企业微信代开发(服务商模板):凭据清单 + 用户/开发/部署三视角;
|
|
199
|
+
// · `wecom-internal-app.md` 企业内部应用(自建):五项 corp 凭据 + 验证并接入 + 共存。
|
|
200
|
+
for (const name of ["SKILL.md", "manual.md", "README.md", "wecom-daikaifa.md", "wecom-internal-app.md"])
|
|
200
201
|
copyIfAbsent(path.join(cliDevkit, name), path.join(ojmSkillDir, name), report);
|
|
201
202
|
}
|
|
202
203
|
else {
|
package/src/shared-deps.ts
CHANGED
|
@@ -20,6 +20,18 @@ export interface SharedDepEntry {
|
|
|
20
20
|
asset?: string
|
|
21
21
|
/** 硬共享:模块不得自带 */
|
|
22
22
|
hard: boolean
|
|
23
|
+
/**
|
|
24
|
+
* 软共享但「不进宿主首屏」:宿主 shell 不预构建该资产、importmap 不列该键,
|
|
25
|
+
* 模块若 import 它则自行打包进模块产物(设计文档 §4.3 的「软共享缺席→模块自带
|
|
26
|
+
* 副本兜底」语义)。用于**仅模块使用、宿主与共享 chunk 永不 import**的重型依赖
|
|
27
|
+
* (编辑器 / 图表 / Markdown / 拖拽 …),避免把它们 5~6MB 的体量无谓铺进
|
|
28
|
+
* shell-dist 并要求公开链路多传一堆文件。宿主侧有真实 import 的共享依赖
|
|
29
|
+
* (antd / pro-components / icons 内部依赖的 motion / react-jss / dayjs /
|
|
30
|
+
* zustand 等)绝不能标 bundle —— 否则会被 antd 等共享 chunk 经 importmap 解析
|
|
31
|
+
* 不到而 404。判定依据:宿主 host.tsx + runtime.js 的传递 import 图,以及
|
|
32
|
+
* antd/pro-components/icons 的传递依赖图,都不含这些说明符。
|
|
33
|
+
*/
|
|
34
|
+
bundle?: boolean
|
|
23
35
|
}
|
|
24
36
|
|
|
25
37
|
export const SHARED_DEPS: SharedDepEntry[] = [
|
|
@@ -58,7 +70,7 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
58
70
|
* scopes 多版本共存兜底(C7)」——缺席时模块可自带副本而不硬失败。
|
|
59
71
|
* 代价:多副本会重复约 5.4 MB 资产,故 scopes 只作兜底、默认仍走宿主。
|
|
60
72
|
*/
|
|
61
|
-
{ specifier: "@plane/editor", asset: "editor", hard: false },
|
|
73
|
+
{ specifier: "@plane/editor", asset: "editor", hard: false, bundle: true },
|
|
62
74
|
// 注:@rc-component/form(antd 6 Form 底层)曾尝试单例化以修 my-profile
|
|
63
75
|
// 崩溃(React #130),假说未证实——多副本并非充分根因,已回退;见
|
|
64
76
|
// docs/prd/202609010056-playground-full-modules-plan.md 差异项 D2。
|
|
@@ -108,10 +120,10 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
108
120
|
{ specifier: "dayjs/plugin/weekday", asset: "dayjs-plugin-weekday", hard: false },
|
|
109
121
|
{ specifier: "dayjs/plugin/weekOfYear", asset: "dayjs-plugin-weekOfYear", hard: false },
|
|
110
122
|
{ specifier: "dayjs/plugin/weekYear", asset: "dayjs-plugin-weekYear", hard: false },
|
|
111
|
-
{ specifier: "echarts", asset: "echarts", hard: false },
|
|
112
|
-
{ specifier: "echarts/charts", asset: "echarts-charts", hard: false },
|
|
113
|
-
{ specifier: "echarts/features.js", asset: "echarts-features", hard: false },
|
|
114
|
-
{ specifier: "echarts-for-react", asset: "echarts-for-react", hard: false },
|
|
123
|
+
{ specifier: "echarts", asset: "echarts", hard: false, bundle: true },
|
|
124
|
+
{ specifier: "echarts/charts", asset: "echarts-charts", hard: false, bundle: true },
|
|
125
|
+
{ specifier: "echarts/features.js", asset: "echarts-features", hard: false, bundle: true },
|
|
126
|
+
{ specifier: "echarts-for-react", asset: "echarts-for-react", hard: false, bundle: true },
|
|
115
127
|
{ specifier: "motion", asset: "motion", hard: false },
|
|
116
128
|
{ specifier: "motion/react", asset: "motion-react", hard: false },
|
|
117
129
|
{ specifier: "@dnd-kit/core", asset: "dnd-kit-core", hard: false },
|
|
@@ -127,6 +139,8 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
127
139
|
{ specifier: "react-error-boundary", asset: "react-error-boundary", hard: false },
|
|
128
140
|
{ specifier: "react-jss", asset: "react-jss", hard: false },
|
|
129
141
|
{ specifier: "clsx", asset: "clsx", hard: false },
|
|
142
|
+
// react-countup 只有 CJS 入口(main: build),其 require("react") 在模块自打包时会退化成
|
|
143
|
+
// 浏览器不可用的 require 桩 → 必须走宿主共享资产(shell 侧有 CJS→ESM 垫片)
|
|
130
144
|
{ specifier: "react-countup", asset: "react-countup", hard: false },
|
|
131
145
|
{ specifier: "simplebar-react", asset: "simplebar-react", hard: false },
|
|
132
146
|
{ specifier: "spin-delay", asset: "spin-delay", hard: false },
|
|
@@ -147,8 +161,8 @@ export const SHARED_DEPS: SharedDepEntry[] = [
|
|
|
147
161
|
* 直接 import 它们,会命中前缀 external 但无 importmap 键 → 构建期深路径报错,
|
|
148
162
|
* 属预期拦截(与 dayjs/plugin/* 同规则)。
|
|
149
163
|
*/
|
|
150
|
-
{ specifier: "vditor", asset: "vditor", hard: false },
|
|
151
|
-
{ specifier: "vditor/dist/index.css", asset: "vditor-index-css", hard: false },
|
|
164
|
+
{ specifier: "vditor", asset: "vditor", hard: false, bundle: true },
|
|
165
|
+
{ specifier: "vditor/dist/index.css", asset: "vditor-index-css", hard: false, bundle: true },
|
|
152
166
|
];
|
|
153
167
|
|
|
154
168
|
/** 判断一个裸说明符是否命中共享表(命中主包前缀的深路径也按共享处理) */
|
|
@@ -161,7 +175,7 @@ export function isSharedDep(id: string): boolean {
|
|
|
161
175
|
*/
|
|
162
176
|
export function generateShellEntries(): { name: string, pkg: string }[] {
|
|
163
177
|
return SHARED_DEPS
|
|
164
|
-
.filter(dep => dep.asset && dep.specifier !== "@oj-module/runtime")
|
|
178
|
+
.filter(dep => dep.asset && !dep.bundle && dep.specifier !== "@oj-module/runtime")
|
|
165
179
|
.map(dep => ({ name: dep.asset!, pkg: dep.specifier }));
|
|
166
180
|
}
|
|
167
181
|
|
|
@@ -172,9 +186,13 @@ export function generateShellEntries(): { name: string, pkg: string }[] {
|
|
|
172
186
|
export function generateImportmap(baseUrl = ""): Record<string, string> {
|
|
173
187
|
const map: Record<string, string> = {};
|
|
174
188
|
for (const dep of SHARED_DEPS) {
|
|
175
|
-
if (dep.asset) {
|
|
189
|
+
if (dep.asset && !dep.bundle) {
|
|
176
190
|
map[dep.specifier] = `${baseUrl}/assets/${dep.asset}.js`;
|
|
177
191
|
}
|
|
178
192
|
}
|
|
179
193
|
return map;
|
|
180
194
|
}
|
|
195
|
+
|
|
196
|
+
export function isPrebuiltDep(id: string): boolean {
|
|
197
|
+
return SHARED_DEPS.some(dep => !dep.bundle && (id === dep.specifier || id.startsWith(`${dep.specifier}/`)));
|
|
198
|
+
}
|
package/src/site-base.ts
CHANGED
|
@@ -100,7 +100,7 @@ export function rewriteIndexHtml(html: string, siteBase: string | undefined, api
|
|
|
100
100
|
out = rewriteImportmap(out, base);
|
|
101
101
|
// 属性值:只要以单个 "/" 开头(排除 "//host")。importmap 是脚本正文、非属性,
|
|
102
102
|
// 上一步已处理,二者不重叠。
|
|
103
|
-
out = out.replace(/(\b(?:href|src)=")(\/[^/"][^"]*|\/")/g, (_m, attr: string, url: string) =>
|
|
103
|
+
out = out.replace(/(\b(?:href|src|data-ojm-entry)=")(\/[^/"][^"]*|\/")/g, (_m, attr: string, url: string) =>
|
|
104
104
|
`${attr}${withSiteBase(url, base)}`);
|
|
105
105
|
globals.push(`window.__OJ_BASE__=${JSON.stringify(base)};`);
|
|
106
106
|
}
|
package/templates/config.yaml
CHANGED
|
@@ -56,8 +56,13 @@ vars:
|
|
|
56
56
|
# 故意不读请求头 Host(防伪造 Host 牵引出站):不配 = fail-closed,不会替你猜。
|
|
57
57
|
# canonical_origin: "https://your-site.example.com"
|
|
58
58
|
|
|
59
|
-
# ----
|
|
60
|
-
#
|
|
59
|
+
# ---- 企业微信(部署级常量,不进 DB)----
|
|
60
|
+
# 两种应用来源,**可同时启用**(docs/plans/20261101-2044-wecom-internal-app-plan.md):
|
|
61
|
+
# · 代开发(suite):一套代开发模板,企业扫码授权即接入,一套部署可服务多家企业;
|
|
62
|
+
# · 企业内部应用 / 自建应用(corp):企业自建应用,一套部署只服务一家企业。
|
|
63
|
+
# 两套的企业侧数据链路相同(permanent_code 就是当 corpsecret 用的),差别只在凭据来源与回调。
|
|
64
|
+
# 从代开发迁到自建时请把旧的 suite 变量清空;两套同时生效须显式开 wecom_allow_coexist。
|
|
65
|
+
# 一个部署 = 一个服务商账号下的一套代开发模板(或一家企业的自建应用),所以这些值是「部署」维度,不进 DB。
|
|
61
66
|
# 「哪个企业装了哪个应用」不写在这里:企微 create_auth 回调推 AuthCode → 换永久授权码 →
|
|
62
67
|
# 落 wecom_app_profile(主键含 agent_id,同一企业测试/正式两个应用天然并存),
|
|
63
68
|
# 新增企业只需企业管理员扫码授权,**不改配置、不重启**。
|
|
@@ -74,18 +79,35 @@ vars:
|
|
|
74
79
|
# wecom_provider_id 服务商的 corpid(服务商自己的,不是企业 corpid);**位置:服务商后台「服务商信息」页显示的 CorpID**
|
|
75
80
|
# wecom_provider_secret 服务商 provider_secret;**位置:服务商后台 → 应用管理 → 通用开发参数(点「编辑」)→ ProviderSecret 字段**,
|
|
76
81
|
# **不在「服务商信息」页**(那里只显示 CorpID),也**不是** suite_secret(suite 那个是另一套)。
|
|
77
|
-
# wecom_callback_token
|
|
78
|
-
# wecom_encoding_aes_key
|
|
79
|
-
# wecom_enc_key permanent_code
|
|
82
|
+
# wecom_callback_token 代开发「指令回调」的 Token(回调验签用)
|
|
83
|
+
# wecom_encoding_aes_key 代开发「指令回调」的 EncodingAESKey(43 字符,回调解密用)
|
|
84
|
+
# wecom_enc_key permanent_code / 应用 Secret 的落库加密密钥(hex/base64,16 或 32 字节;建议 oj secret keygen)
|
|
80
85
|
# wecom_base_url 连接器基址(绝对地址,无尾斜杠,**这是基址、不是回调 URL**),如 https://site.example.com/api/auth/wecom
|
|
81
|
-
# →
|
|
86
|
+
# → 回调 URL 填 <base>/event(必须带 /event,裸 <base> 无 handler 会 404);
|
|
82
87
|
# 网页授权 redirect_uri 用 <base>/callback
|
|
88
|
+
#
|
|
89
|
+
# 企业内部应用(corp)——一套部署一家企业:
|
|
90
|
+
# wecom_corp_id 企微后台「我的企业 → 企业信息 → 企业ID」;同时是租户键
|
|
91
|
+
# wecom_corp_secret 应用详情页「Secret」;**换过后必须到 /system/wecom 重新「验证并接入」**
|
|
92
|
+
# wecom_corp_agent_id 应用详情页「AgentId」
|
|
93
|
+
# wecom_corp_callback_token 「管理工具 → 通讯录同步 → 接收事件服务器」的 Token(可选;不配 = 不做事件增量)
|
|
94
|
+
# wecom_corp_encoding_aes_key 同上 → EncodingAESKey(可选)
|
|
95
|
+
# ⚠ 自建应用**收不到**成员通讯录变更事件(官方 90970),事件增量只能靠上面这组「通讯录同步」回调,
|
|
96
|
+
# 且企微要求该 URL 在企业主体域名下——所以它只适用于私有化单企业部署。
|
|
97
|
+
#
|
|
98
|
+
# wecom_allow_coexist 两套凭据都配齐时必须显式写 'true' 才允许共存(否则 fail-fast)
|
|
83
99
|
wecom_suite_id: ''
|
|
84
100
|
wecom_suite_secret: ''
|
|
85
101
|
wecom_provider_id: ''
|
|
86
102
|
wecom_provider_secret: ''
|
|
87
103
|
wecom_callback_token: ''
|
|
88
104
|
wecom_encoding_aes_key: ''
|
|
105
|
+
wecom_corp_id: ''
|
|
106
|
+
wecom_corp_secret: ''
|
|
107
|
+
wecom_corp_agent_id: ''
|
|
108
|
+
wecom_corp_callback_token: ''
|
|
109
|
+
wecom_corp_encoding_aes_key: ''
|
|
110
|
+
wecom_allow_coexist: ''
|
|
89
111
|
wecom_enc_key: ''
|
|
90
112
|
wecom_base_url: ''
|
|
91
113
|
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
# `pnpm dev` 时忽略产物,不进发布包、也不进用户工程。守卫:
|
|
21
21
|
# tests/cli/release-manifest.test.ts 逐条核对清单条目落在 tarball 内。
|
|
22
22
|
#
|
|
23
|
-
# 注意 web/src/{
|
|
24
|
-
#
|
|
25
|
-
#
|
|
23
|
+
# 注意 web/src/{home}/__client 不在清单:其 api 模块(api/src/home)是 demo-only
|
|
24
|
+
# 不进脚手架,client 生成物留着会指向不存在的端点,故 home 只列页面源码
|
|
25
|
+
# (entry/locales/pages),不列整棵模块目录。
|
|
26
26
|
include:
|
|
27
27
|
# —— 工程级文件 ——
|
|
28
28
|
- README.md
|
|
@@ -101,12 +101,9 @@ include:
|
|
|
101
101
|
- src/personal-center/api
|
|
102
102
|
- src/system/api
|
|
103
103
|
- src/web/api
|
|
104
|
-
# —— web 前端模块(
|
|
104
|
+
# —— web 前端模块(home 只列页面源码,__client 见顶部说明)——
|
|
105
105
|
- src/_platform/web
|
|
106
106
|
- src/auth/web
|
|
107
|
-
- src/demo/web/entry.ts
|
|
108
|
-
- src/demo/web/locales
|
|
109
|
-
- src/demo/web/pages
|
|
110
107
|
- src/home/web/entry.ts
|
|
111
108
|
- src/home/web/locales
|
|
112
109
|
- src/home/web/pages
|