@oj-module/cli 0.2.50 → 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.
Files changed (49) hide show
  1. package/devkit/wecom-internal-app.md +111 -4
  2. package/package.json +2 -2
  3. package/shell-dist/assets/{index-FYt9CjFd.js → index-e_Mp2mb5.js} +5 -1
  4. package/shell-dist/assets/runtime.js +24 -3
  5. package/shell-dist/index.html +9 -12
  6. package/shell-dist/versions.json +3 -3
  7. package/src/build.ts +19 -2
  8. package/src/shared-deps.ts +27 -9
  9. package/src/site-base.ts +1 -1
  10. package/templates/init.include.yaml +4 -7
  11. package/templates/openapi.json +2520 -2412
  12. package/templates/src/_platform/api/_shared/service/domain/users.ts +40 -4
  13. package/templates/src/auth/api/_shared/wecom/admin.ts +4 -0
  14. package/templates/src/auth/api/_shared/wecom/client.ts +9 -2
  15. package/templates/src/auth/api/_shared/wecom/events.ts +3 -0
  16. package/templates/src/auth/api/_shared/wecom/tenant-admin.ts +194 -0
  17. package/templates/src/auth/api/wecom/admin/tenant-admin/api.ts +41 -0
  18. package/templates/src/auth/api/wecom/admin/tenant-admin/password/api.ts +66 -0
  19. package/templates/src/login/web/pages/login.tsx +54 -24
  20. package/templates/src/system/api/settings/api.ts +3 -3
  21. package/templates/src/system/web/entry.ts +4 -4
  22. package/templates/src/system/web/locales/en-US.json +14 -0
  23. package/templates/src/system/web/locales/zh-CN.json +14 -0
  24. package/templates/src/system/web/pages/users/index.tsx +7 -4
  25. package/templates/src/system/web/pages/users/roles.tsx +14 -3
  26. package/templates/src/system/web/pages/wecom/index.tsx +130 -1
  27. package/templates/tsconfig.paths.json +0 -1
  28. package/templates/web.config.ts +1 -2
  29. package/vendor/host-versions.json +3 -3
  30. package/shell-dist/assets/echarts-charts.js +0 -58571
  31. package/shell-dist/assets/echarts-features.js +0 -24057
  32. package/shell-dist/assets/echarts-for-react.js +0 -704
  33. package/shell-dist/assets/echarts.js +0 -82916
  34. package/shell-dist/assets/editor.js +0 -161457
  35. package/shell-dist/assets/vditor-index-css.js +0 -7
  36. package/shell-dist/assets/vditor.js +0 -15223
  37. package/templates/src/demo/api/manifest.yaml +0 -5
  38. package/templates/src/demo/api/migrations/0001__create_todos.sql +0 -9
  39. package/templates/src/demo/api/migrations/0002__tenant.mysql.sql +0 -2
  40. package/templates/src/demo/api/migrations/0002__tenant.sql +0 -2
  41. package/templates/src/demo/api/schema.yaml +0 -12
  42. package/templates/src/demo/api/seed.sql +0 -5
  43. package/templates/src/demo/api/todos/api.ts +0 -59
  44. package/templates/src/demo/web/__client/api.schemas.ts +0 -20
  45. package/templates/src/demo/web/__client/api.ts +0 -89
  46. package/templates/src/demo/web/entry.ts +0 -42
  47. package/templates/src/demo/web/locales/en-US.json +0 -10
  48. package/templates/src/demo/web/locales/zh-CN.json +0 -10
  49. package/templates/src/demo/web/pages/index.tsx +0 -45
@@ -1,5 +0,0 @@
1
- name: demo
2
- desc: 演示模块(todos 等,P3 接数据层)
3
- version: 0.1.0
4
- tables:
5
- - todos
@@ -1,9 +0,0 @@
1
- -- demo 模块建表(P3-2)。todos 待办表,S007 要求序号连续且唯一,单文件 0001。
2
- -- done 用 INTEGER(0/1) 承载布尔,handler 映射为 boolean。
3
- CREATE TABLE IF NOT EXISTS todos (
4
- id INTEGER PRIMARY KEY AUTOINCREMENT,
5
- title TEXT NOT NULL DEFAULT '',
6
- done INTEGER NOT NULL DEFAULT 0,
7
- create_time INTEGER NOT NULL DEFAULT 0,
8
- update_time INTEGER NOT NULL DEFAULT 0
9
- );
@@ -1,2 +0,0 @@
1
- -- 0002__tenant(mysql 方言):demo.todos 租户化。TEXT 不能带字面默认值 → VARCHAR(255)。
2
- ALTER TABLE todos ADD COLUMN tenant_id VARCHAR(255) NOT NULL DEFAULT 'default';
@@ -1,2 +0,0 @@
1
- -- 0002__tenant:demo.todos 租户化(企微代开发 v3 Phase 0 的 A 组)。
2
- ALTER TABLE todos ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default';
@@ -1,12 +0,0 @@
1
- # 声明式表结构(§4.2 / D1-C):demo 模块自有表 todos。
2
- # 加表/加可空列由 reconcile 自动收敛;类型变更/改名走 migrations/。
3
- tables:
4
- todos:
5
- pk: id
6
- columns:
7
- id: {type: integer, autoincrement: true}
8
- tenant_id: {type: text, null: false}
9
- title: {type: text, null: false}
10
- done: {type: integer, null: false}
11
- create_time: {type: integer, null: false}
12
- update_time: {type: integer, null: false}
@@ -1,5 +0,0 @@
1
- -- demo 模块种子(P3-2):示例待办,幂等 INSERT OR IGNORE,按分号朴素切分(S006)。
2
- INSERT OR IGNORE INTO todos (id, title, done, create_time, update_time) VALUES (1, '学习 uni-dev 契约机制', 1, 0, 0);
3
- INSERT OR IGNORE INTO todos (id, title, done, create_time, update_time) VALUES (2, '完成 playground-oj system 模块', 0, 0, 0);
4
- INSERT OR IGNORE INTO todos (id, title, done, create_time, update_time) VALUES (3, '编写 P3 教学文档', 0, 0, 0);
5
- INSERT OR IGNORE INTO todos (id, title, done, create_time, update_time) VALUES (4, '联调 demo 真实数据层', 0, 0, 0);
@@ -1,59 +0,0 @@
1
- // GET /api/demo/todos —— 演示待办列表(真实化 P3-2,AC-D9 apiPrefix=/demo)。
2
- // Bearer 守卫保护;keyword 模糊过滤 title;snake_case → camelCase,done 映射布尔。
3
-
4
- // 契约(v0.1.71「最新方式」):动词挂 `.schema` 四通道(params/query/body/response),
5
- // oj 运行期据此校验入参、并供 `oj openapi` 生成 openapi.json → 前端 `ojm api` 生成 __client。
6
- const todos = {
7
- async get() {
8
- const kw = http.query.keyword;
9
- const hasKw = typeof kw === "string" && kw.length > 0;
10
- // 构造器:模糊过滤走语义 op(contains 自动转义 %/_/!),count 走聚合,方言无关。
11
- const build = () => db.table("todos").whereIf(hasKw, { field: "title", op: "contains", value: kw });
12
- try {
13
- const total = Number((await build().select([{ fn: "count", as: "c" }]).all())[0]?.c ?? 0);
14
- const rows = await build()
15
- .select(["id", "title", "done", "create_time", "update_time"])
16
- .orderBy([{ field: "id", dir: "asc" }])
17
- .all();
18
- const list = rows.map(r => ({
19
- id: Number(r.id),
20
- title: String(r.title),
21
- done: Number(r.done) === 1,
22
- }));
23
- json.ok({ list, total });
24
- }
25
- catch (e) {
26
- json.fail(500, String(e));
27
- }
28
- },
29
- };
30
-
31
- todos.get.schema = {
32
- query: {
33
- type: "object",
34
- properties: { keyword: { type: "string" } },
35
- },
36
- };
37
-
38
- // oj v0.1.72 起出参走平级 .response(.schema 只放入参)。
39
- todos.get.response = {
40
- type: "object",
41
- required: ["list", "total"],
42
- properties: {
43
- list: {
44
- type: "array",
45
- items: {
46
- type: "object",
47
- required: ["id", "title", "done"],
48
- properties: {
49
- id: { type: "number" },
50
- title: { type: "string" },
51
- done: { type: "boolean" },
52
- },
53
- },
54
- },
55
- total: { type: "number" },
56
- },
57
- };
58
-
59
- export default todos;
@@ -1,20 +0,0 @@
1
- /* eslint-disable */
2
- // 生成物:ojm api 从契约生成,勿手改(改动请改契约文件后重跑 ojm api)
3
- // AC-D15:仅供 DEV 校验动态 import,生产构建不进产物
4
- import { z } from "@oj-module/runtime";
5
-
6
- export const schemas = {
7
- "demoTodosGet": {
8
- query: z.object({
9
- "keyword": z.string().optional()
10
- }),
11
- data: z.object({
12
- "list": z.array(z.object({
13
- "id": z.number(),
14
- "title": z.string(),
15
- "done": z.boolean()
16
- })),
17
- "total": z.number()
18
- }),
19
- },
20
- };
@@ -1,89 +0,0 @@
1
- /* eslint-disable */
2
- // 生成物:ojm api 从契约生成,勿手改(改动请改契约文件后重跑 ojm api)
3
- import { ContractApiError } from "@oj-module/runtime/contract/errors";
4
- import type { ScopedRequestLike } from "@oj-module/runtime/contract/errors";
5
- import type { ModuleContext } from "@oj-module/runtime";
6
- import type { z } from "@oj-module/runtime";
7
- import type { schemas } from "./api.schemas";
8
-
9
- /** oj 信封(AC-D16):code=0 成功;非 0 时 HTTP status=code,由 toApiError 归一为 ContractApiError */
10
- interface OjEnvelope<T> { code: number, msg?: string, data?: T }
11
-
12
- let req: ScopedRequestLike | undefined;
13
-
14
- /** 线上 API 前缀(ojm api 从契约抽取,唯一真源,勿手改):请求基址 + 前缀登记用 */
15
- export const API_PREFIX = "/demo";
16
-
17
- /** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
18
- export const MODULE_PREFIX = "/demo";
19
-
20
- /**
21
- * 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
22
- * scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
23
- * 重复构造幂等安全(前缀重复登记同值、request 重绑同值)。
24
- */
25
- export function createDemoClient(ctx: ModuleContext) {
26
- // 跨模块认领护栏(DEV):工厂知道自己该属于谁(MODULE_PREFIX = 契约 apiPrefix),
27
- // ctx 又带 module.name——名实不符说明别的模块在替本模块创建 client,会共享 request
28
- // 单槽、卸载互相耦合;跨模块需求应由本模块创建后经 provider 暴露。
29
- // 注意对比基准是 MODULE_PREFIX(目录名)而非 API_PREFIX——D-M8 映射时线上前缀
30
- // 属于别的命名空间,认领身份仍按目录名。
31
- if (import.meta.env.DEV && ctx.module.name !== MODULE_PREFIX.slice(1)) {
32
- console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${MODULE_PREFIX.slice(1)}" 模块在自身 onInit 创建,跨模块需求经 provider 暴露。`);
33
- }
34
- ctx.register.apiPrefix(API_PREFIX);
35
- bindRequest(ctx.utils.request);
36
- return { demoTodosGet };
37
- }
38
-
39
- /**
40
- * @deprecated 请改用 createDemoClient(ctx)——工厂构造即完成
41
- * 前缀登记 + request 绑定,不会出现「登记了前缀没绑 request」的半接线状态。
42
- */
43
- export function bindRequest(r: ScopedRequestLike): void {
44
- req = r;
45
- }
46
-
47
- function ensureReq(): ScopedRequestLike {
48
- if (!req)
49
- throw new ContractApiError(-1, "[ojm-api] 请求未绑定——请在模块 entry.ts 的 onInit 里调用 createDemoClient(ctx)(或 bindRequest(ctx.utils.request))。");
50
- return req;
51
- }
52
-
53
- /** ky HTTPError → ContractApiError(错误体为信封时取 code/msg);契约违例与原错误原样透传 */
54
- async function toApiError(e: unknown): Promise<unknown> {
55
- if (e instanceof ContractApiError)
56
- return e;
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);
64
- return e;
65
- }
66
-
67
- export type DemoTodosGetQuery = z.input<(typeof schemas)["demoTodosGet"]["query"]>;
68
- export type DemoTodosGetData = z.infer<(typeof schemas)["demoTodosGet"]["data"]>;
69
-
70
- export async function demoTodosGet(query: DemoTodosGetQuery): Promise<DemoTodosGetData> {
71
- const client = ensureReq();
72
- try {
73
- const env = await client.get(`demo/todos`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<DemoTodosGetData>>();
74
- // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
75
- if (typeof env.code === "number" && env.code !== 0)
76
- throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
77
- const data = env.data as DemoTodosGetData;
78
- if (import.meta.env.DEV) {
79
- const { schemas } = await import("./api.schemas");
80
- const r = schemas["demoTodosGet"].data.safeParse(data);
81
- if (!r.success)
82
- throw new ContractApiError(-1, `[契约违例] demoTodosGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
83
- }
84
- return data;
85
- }
86
- catch (e) {
87
- throw await toApiError(e);
88
- }
89
- }
@@ -1,42 +0,0 @@
1
- import { HomeOutlined } from "@ant-design/icons";
2
- import { defineModule } from "@oj-module/runtime";
3
- import { createElement } from "react";
4
-
5
- import DemoPage from "./pages/index";
6
-
7
- /**
8
- * demo 前端模块:本文件是模块元数据唯一来源(name/version/routes/i18n)。
9
- * 只允许 import 三类东西:runtime、共享依赖(宿主 importmap 提供)、自身相对路径。
10
- */
11
- export default defineModule({
12
- name: "demo",
13
- description: "uni-dev 演示模块",
14
- version: "0.1.0",
15
- peerRuntime: ">=0.0.0",
16
- routes: [
17
- {
18
- path: "/demo",
19
- handle: {
20
- layout: "container",
21
- order: 100,
22
- title: "demo:menu.demo",
23
- icon: createElement(HomeOutlined),
24
- },
25
- children: [
26
- {
27
- index: true,
28
- Component: DemoPage,
29
- handle: {
30
- title: "demo:menu.demo",
31
- icon: createElement(HomeOutlined),
32
- keepAlive: true,
33
- },
34
- },
35
- ],
36
- },
37
- ],
38
- i18n: {
39
- "zh-CN": () => import("./locales/zh-CN.json"),
40
- "en-US": () => import("./locales/en-US.json"),
41
- },
42
- });
@@ -1,10 +0,0 @@
1
- {
2
- "menu": {
3
- "demo": "Demo"
4
- },
5
- "page": {
6
- "title": "uni-dev Demo",
7
- "loaded": "Module loaded",
8
- "hello": "Backend says"
9
- }
10
- }
@@ -1,10 +0,0 @@
1
- {
2
- "menu": {
3
- "demo": "演示模块"
4
- },
5
- "page": {
6
- "title": "uni-dev 演示",
7
- "loaded": "模块加载成功",
8
- "hello": "后端响应"
9
- }
10
- }
@@ -1,45 +0,0 @@
1
- import { BasicContent, useAuthStore } from "@oj-module/runtime";
2
- import { Card, Tag, Typography } from "antd";
3
- import { useEffect, useState } from "react";
4
- import { useTranslation } from "react-i18next";
5
-
6
- /**
7
- * 演示页:调后端 /api/web/hello(oj dev/ts 热更,改 api/src 保存即生效)。
8
- * 业务侧直接消费 oj 原生信封 {code:0,data};登录链信封由 runtime 适配(D10)。
9
- *
10
- * 注意(集中审阅 F6 评估结论):这里用裸 fetch 是有意的 demo 简化——
11
- * runtime 不向页面组件暴露请求客户端(scoped client `ctx.utils.request`
12
- * 只在模块生命周期钩子可用),真实业务模块请把请求收敛到模块自己的
13
- * api/ 层再封装,不要在页面里散落 fetch。
14
- */
15
- export default function DemoPage() {
16
- const { t } = useTranslation();
17
- const token = useAuthStore(state => state.token);
18
- const [hello, setHello] = useState<string>("");
19
-
20
- useEffect(() => {
21
- const controller = new AbortController();
22
- fetch("/api/web/hello", { headers: { Authorization: `Bearer ${token}` }, signal: controller.signal })
23
- .then(res => res.json())
24
- .then((body: { data?: { message?: string } }) => setHello(body?.data?.message ?? ""))
25
- .catch(() => setHello(""));
26
- return () => controller.abort();
27
- }, [token]);
28
-
29
- return (
30
- <BasicContent>
31
- <Card title={t("demo:page.title")}>
32
- <Tag color="success">{t("demo:page.loaded")}</Tag>
33
- {hello
34
- ? (
35
- <Typography.Paragraph>
36
- {t("demo:page.hello")}
37
- {": "}
38
- <Typography.Text code>{hello}</Typography.Text>
39
- </Typography.Paragraph>
40
- )
41
- : null}
42
- </Card>
43
- </BasicContent>
44
- );
45
- }