@oj-module/cli 0.2.2 → 0.2.5

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 (231) hide show
  1. package/devkit/README.md +14 -3
  2. package/devkit/SKILL.md +16 -4
  3. package/devkit/framework-dev.md +8 -6
  4. package/devkit/manual.md +243 -23
  5. package/package.json +2 -2
  6. package/shell-dist/assets/runtime.js +143 -8
  7. package/shell-dist/index.html +2 -2
  8. package/shell-dist/versions.json +3 -3
  9. package/src/args.ts +67 -0
  10. package/src/build.ts +11 -3
  11. package/src/bundle.ts +197 -0
  12. package/src/contract/__tests__/handler-scan.test.ts +82 -0
  13. package/src/contract/check.ts +2 -1
  14. package/src/contract/handler-scan.ts +32 -0
  15. package/src/deterministic-tar.ts +120 -0
  16. package/src/dev.ts +4 -2
  17. package/src/enable.ts +28 -0
  18. package/src/index.ts +63 -2
  19. package/src/info.ts +3 -2
  20. package/src/init.ts +147 -14
  21. package/src/install.ts +268 -0
  22. package/src/keygen.ts +88 -0
  23. package/src/layout.ts +31 -0
  24. package/src/lifecycle/__tests__/authoring.test.ts +109 -0
  25. package/src/lifecycle/__tests__/bundle.test.ts +150 -0
  26. package/src/lifecycle/__tests__/deterministic-tar.test.ts +145 -0
  27. package/src/lifecycle/__tests__/fixtures/README.md +59 -0
  28. package/src/lifecycle/__tests__/fixtures/fixture-invalid/EXPECTED-VIOLATIONS.md +27 -0
  29. package/src/lifecycle/__tests__/fixtures/fixture-invalid/api/src/Demo/manifest.yaml +6 -0
  30. package/src/lifecycle/__tests__/fixtures/fixture-invalid/manifest.yaml +40 -0
  31. package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/entry.ts +14 -0
  32. package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/en-US.json +12 -0
  33. package/src/lifecycle/__tests__/fixtures/fixture-invalid/web/src/Demo/locales/zh-CN.json +12 -0
  34. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +9 -0
  35. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +6 -0
  36. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/ping/api.ts +9 -0
  37. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +9 -0
  38. package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +96 -0
  39. package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/entry.ts +23 -0
  40. package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/en-US.json +29 -0
  41. package/src/lifecycle/__tests__/fixtures/fixture-valid/web/src/demo-solution/locales/zh-CN.json +29 -0
  42. package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz +0 -0
  43. package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.bad.sig +7 -0
  44. package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.sig +7 -0
  45. package/src/lifecycle/__tests__/fixtures/sig/demo-solution-0.2.0.tgz.unknown.sig +7 -0
  46. package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.d.mts +21 -0
  47. package/src/lifecycle/__tests__/fixtures/sig/gen-signed-fixtures.mjs +196 -0
  48. package/src/lifecycle/__tests__/helpers.ts +78 -0
  49. package/src/lifecycle/__tests__/install.test.ts +514 -0
  50. package/src/lifecycle/__tests__/keygen.test.ts +61 -0
  51. package/src/lifecycle/__tests__/manifest-contract.test.ts +228 -0
  52. package/src/lifecycle/__tests__/publish.test.ts +80 -0
  53. package/src/lifecycle/__tests__/sig-fixtures.test.ts +100 -0
  54. package/src/lifecycle/__tests__/sign.test.ts +131 -0
  55. package/src/lifecycle/__tests__/smoke.test.ts +61 -0
  56. package/src/lifecycle/__tests__/trust.test.ts +177 -0
  57. package/src/lifecycle/__tests__/uninstall.test.ts +87 -0
  58. package/src/lifecycle/keygen.ts +40 -0
  59. package/src/lifecycle/sign.ts +74 -0
  60. package/src/manifest-contract.ts +696 -0
  61. package/src/oj-cert.ts +19 -0
  62. package/src/oj-cmd.ts +3 -3
  63. package/src/preview.ts +2 -2
  64. package/src/publish.ts +150 -0
  65. package/src/sign.ts +128 -0
  66. package/src/site.ts +146 -0
  67. package/src/trust.ts +116 -0
  68. package/src/uninstall.ts +29 -0
  69. package/src/usage.ts +35 -1
  70. package/templates/README.md +1 -1
  71. package/templates/api/config.yaml +47 -0
  72. package/templates/api/seed.mysql.sql +1 -1
  73. package/templates/api/seed.pg.sql +1 -1
  74. package/templates/api/src/_platform/_lifecycle/atomic.ts +98 -0
  75. package/templates/api/src/_platform/_lifecycle/history.ts +31 -0
  76. package/templates/api/src/_platform/_lifecycle/installer.ts +1080 -0
  77. package/templates/api/src/_platform/_lifecycle/lock.ts +148 -0
  78. package/templates/api/src/_platform/_lifecycle/semver.ts +61 -0
  79. package/templates/api/src/_platform/_lifecycle/sha384.ts +187 -0
  80. package/templates/api/src/_platform/_lifecycle/state.ts +256 -0
  81. package/templates/api/src/_platform/_lifecycle/steps/deploy-web.ts +182 -0
  82. package/templates/api/src/_platform/_lifecycle/steps/download.ts +90 -0
  83. package/templates/api/src/_platform/_lifecycle/steps/extract.ts +239 -0
  84. package/templates/api/src/_platform/_lifecycle/steps/migrate.ts +363 -0
  85. package/templates/api/src/_platform/_lifecycle/steps/preflight.ts +590 -0
  86. package/templates/api/src/_platform/_lifecycle/steps/register.ts +211 -0
  87. package/templates/api/src/_platform/_lifecycle/steps/reload.ts +81 -0
  88. package/templates/api/src/_platform/_lifecycle/steps/smoke.ts +216 -0
  89. package/templates/api/src/_platform/_lifecycle/steps/verify.ts +207 -0
  90. package/templates/api/src/_platform/_lifecycle/tasks.ts +119 -0
  91. package/templates/api/src/_platform/_lifecycle/text-edit.ts +110 -0
  92. package/templates/api/src/_platform/_lifecycle/tgz-guard.ts +41 -0
  93. package/templates/api/src/_platform/_lifecycle/trust.ts +229 -0
  94. package/templates/api/src/_platform/_lifecycle/types.ts +94 -0
  95. package/templates/api/src/_platform/_lifecycle/uninstall.ts +283 -0
  96. package/templates/api/src/_platform/_lifecycle/verify-checks.ts +228 -0
  97. package/templates/api/src/_platform/_lifecycle/verify-report.ts +92 -0
  98. package/templates/api/src/_platform/_shared/service/access.ts +2 -2
  99. package/templates/api/src/_platform/_shared/service/settings.ts +10 -1
  100. package/templates/api/src/_platform/_shared/service/solution-perms.ts +14 -7
  101. package/templates/api/src/_platform/_shared/site-facade.ts +44 -0
  102. package/templates/api/src/_platform/manifest.yaml +1 -0
  103. package/templates/api/src/_platform/market/api.ts +883 -0
  104. package/templates/api/src/_platform/market/bootstrap.ts +39 -0
  105. package/templates/api/src/_platform/migrations/0010__sys_solution_route.mysql.sql +17 -0
  106. package/templates/api/src/_platform/migrations/0010__sys_solution_route.pg.sql +16 -0
  107. package/templates/api/src/_platform/migrations/0010__sys_solution_route.sql +18 -0
  108. package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.mysql.sql +2 -0
  109. package/templates/api/src/_platform/migrations/0011__sys_setting_group_label.sql +4 -0
  110. package/templates/api/src/_platform/migrations/0012__market_history.mysql.sql +13 -0
  111. package/templates/api/src/_platform/migrations/0012__market_history.pg.sql +12 -0
  112. package/templates/api/src/_platform/migrations/0012__market_history.sql +14 -0
  113. package/templates/api/src/_platform/schema.yaml +21 -4
  114. package/templates/api/src/_platform/seed.sql +2 -2
  115. package/templates/api/src/_platform/solutions/api.ts +212 -0
  116. package/templates/api/src/demo/manifest.yaml +5 -0
  117. package/templates/api/src/demo/migrations/0001__create_todos.sql +9 -0
  118. package/templates/api/src/demo/schema.yaml +11 -0
  119. package/templates/api/src/demo/seed.sql +5 -0
  120. package/templates/api/src/demo/todos/api.ts +59 -0
  121. package/templates/api/src/home/line/api.ts +57 -0
  122. package/templates/api/src/home/manifest.yaml +6 -0
  123. package/templates/api/src/home/migrations/0001__create_home_tables.sql +13 -0
  124. package/templates/api/src/home/pie/api.ts +40 -0
  125. package/templates/api/src/home/schema.yaml +14 -0
  126. package/templates/api/src/home/seed.sql +70 -0
  127. package/templates/api/src/system/oplog/api.ts +44 -2
  128. package/templates/api/tests/fixture.ts +16 -0
  129. package/templates/api/tests/lifecycle/atomic-state.spec.ts +183 -0
  130. package/templates/api/tests/lifecycle/bootstrap.spec.ts +116 -0
  131. package/templates/api/tests/lifecycle/deploy-smoke.spec.ts +492 -0
  132. package/templates/api/tests/lifecycle/installer.spec.ts +1218 -0
  133. package/templates/api/tests/lifecycle/market-api.spec.ts +971 -0
  134. package/templates/api/tests/lifecycle/migrate.spec.ts +575 -0
  135. package/templates/api/tests/lifecycle/preflight.spec.ts +255 -0
  136. package/templates/api/tests/lifecycle/register.spec.ts +194 -0
  137. package/templates/api/tests/lifecycle/semver.spec.ts +43 -0
  138. package/templates/api/tests/lifecycle/sha384.spec.ts +48 -0
  139. package/templates/api/tests/lifecycle/sig-fixtures.spec.ts +65 -0
  140. package/templates/api/tests/lifecycle/solutions-api.spec.ts +98 -0
  141. package/templates/api/tests/lifecycle/steps-fs.spec.ts +623 -0
  142. package/templates/api/tests/lifecycle/text-edit.spec.ts +177 -0
  143. package/templates/api/tests/lifecycle/tgz-guard.spec.ts +103 -0
  144. package/templates/api/tests/lifecycle/trust.spec.ts +310 -0
  145. package/templates/api/tests/lifecycle/uninstall.spec.ts +386 -0
  146. package/templates/api/tests/lifecycle/verify-checks.spec.ts +385 -0
  147. package/templates/api/tests/lifecycle/verify-report.spec.ts +290 -0
  148. package/templates/api/tests/rbac-settings.spec.ts +8 -0
  149. package/templates/init.include.yaml +56 -0
  150. package/templates/openapi.json +527 -0
  151. package/templates/package.json +52 -0
  152. package/templates/web/src/_platform/__client/api.schemas.ts +8 -0
  153. package/templates/web/src/_platform/__client/api.ts +335 -0
  154. package/templates/web/src/about/entry.ts +42 -0
  155. package/templates/web/src/about/locales/en-US.json +16 -0
  156. package/templates/web/src/about/locales/zh-CN.json +16 -0
  157. package/templates/web/src/about/pages/constants.ts +20 -0
  158. package/templates/web/src/about/pages/index.tsx +135 -0
  159. package/templates/web/src/access/entry.ts +74 -0
  160. package/templates/web/src/access/locales/en-US.json +46 -0
  161. package/templates/web/src/access/locales/zh-CN.json +46 -0
  162. package/templates/web/src/access/pages/access-mode/index.tsx +16 -0
  163. package/templates/web/src/access/pages/admin-visible/index.tsx +16 -0
  164. package/templates/web/src/access/pages/button-control/index.tsx +181 -0
  165. package/templates/web/src/access/pages/common-visible/index.tsx +16 -0
  166. package/templates/web/src/access/pages/page-control/index.tsx +142 -0
  167. package/templates/web/src/demo/__client/api.schemas.ts +20 -0
  168. package/templates/web/src/demo/__client/api.ts +89 -0
  169. package/templates/web/src/exception/entry.ts +80 -0
  170. package/templates/web/src/exception/locales/en-US.json +13 -0
  171. package/templates/web/src/exception/locales/zh-CN.json +13 -0
  172. package/templates/web/src/exception/pages/403/index.tsx +30 -0
  173. package/templates/web/src/exception/pages/404/index.tsx +30 -0
  174. package/templates/web/src/exception/pages/500/index.tsx +30 -0
  175. package/templates/web/src/exception/pages/unknown-component/index.tsx +38 -0
  176. package/templates/web/src/home/__client/api.schemas.ts +22 -0
  177. package/templates/web/src/home/__client/api.ts +113 -0
  178. package/templates/web/src/login/locales/en-US.json +6 -0
  179. package/templates/web/src/login/locales/zh-CN.json +6 -0
  180. package/templates/web/src/login/pages/login.tsx +67 -18
  181. package/templates/web/src/oj-market/__tests__/CardGrid.test.tsx +93 -0
  182. package/templates/web/src/oj-market/__tests__/HistoryDrawer.test.tsx +28 -0
  183. package/templates/web/src/oj-market/__tests__/InstallDialog.test.tsx +69 -0
  184. package/templates/web/src/oj-market/__tests__/RollbackDialog.test.tsx +43 -0
  185. package/templates/web/src/oj-market/__tests__/UninstallConfirm.test.tsx +30 -0
  186. package/templates/web/src/oj-market/__tests__/marketClient.fake.ts +70 -0
  187. package/templates/web/src/oj-market/__tests__/poll.test.ts +24 -0
  188. package/templates/web/src/oj-market/__tests__/render.tsx +14 -0
  189. package/templates/web/src/oj-market/__tests__/runtime-stub.ts +14 -0
  190. package/templates/web/src/oj-market/__tests__/semver.test.ts +26 -0
  191. package/templates/web/src/oj-market/api/MarketClientProvider.tsx +12 -0
  192. package/templates/web/src/oj-market/api/client.ts +135 -0
  193. package/templates/web/src/oj-market/api/context.ts +11 -0
  194. package/templates/web/src/oj-market/api/defaultClient.ts +7 -0
  195. package/templates/web/src/oj-market/components/CardGrid.tsx +76 -0
  196. package/templates/web/src/oj-market/components/CardItem.tsx +102 -0
  197. package/templates/web/src/oj-market/components/DetailDrawer.tsx +53 -0
  198. package/templates/web/src/oj-market/components/HistoryDrawer.tsx +75 -0
  199. package/templates/web/src/oj-market/components/InstallDialog.tsx +112 -0
  200. package/templates/web/src/oj-market/components/RollbackDialog.tsx +79 -0
  201. package/templates/web/src/oj-market/components/UninstallConfirm.tsx +74 -0
  202. package/templates/web/src/oj-market/entry.ts +27 -0
  203. package/templates/web/src/oj-market/hooks/useMarket.ts +91 -0
  204. package/templates/web/src/oj-market/locales/en-US.json +100 -0
  205. package/templates/web/src/oj-market/locales/zh-CN.json +100 -0
  206. package/templates/web/src/oj-market/pages/MarketApp.tsx +136 -0
  207. package/templates/web/src/oj-market/types.ts +84 -0
  208. package/templates/web/src/oj-market/utils/poll.ts +36 -0
  209. package/templates/web/src/oj-market/utils/semver.ts +14 -0
  210. package/templates/web/src/outside/entry.ts +80 -0
  211. package/templates/web/src/outside/locales/en-US.json +10 -0
  212. package/templates/web/src/outside/locales/zh-CN.json +10 -0
  213. package/templates/web/src/personal-center/entry.ts +1 -10
  214. package/templates/web/src/personal-center/locales/en-US.json +1 -5
  215. package/templates/web/src/personal-center/locales/zh-CN.json +1 -5
  216. package/templates/web/src/route-nest/entry.ts +73 -0
  217. package/templates/web/src/route-nest/locales/en-US.json +9 -0
  218. package/templates/web/src/route-nest/locales/zh-CN.json +9 -0
  219. package/templates/web/src/route-nest/pages/menu1/menu1-1/index.tsx +5 -0
  220. package/templates/web/src/route-nest/pages/menu1/menu1-2/index.tsx +5 -0
  221. package/templates/web/src/route-nest/pages/menu2/index.tsx +5 -0
  222. package/templates/web/src/system/__client/api.schemas.ts +12 -0
  223. package/templates/web/src/system/__client/api.ts +25 -1
  224. package/templates/web/src/system/pages/oplog/index.tsx +1 -1
  225. package/templates/web/src/system/pages/roles/index.tsx +1 -0
  226. package/templates/web/src/system/pages/settings/index.tsx +1 -1
  227. package/templates/web/src/system/pages/users/index.tsx +1 -1
  228. package/templates/web.config.ts +32 -40
  229. package/vendor/host-versions.json +3 -3
  230. package/templates/pnpm-workspace.yaml +0 -14
  231. package/templates/web/src/personal-center/pages/settings/index.tsx +0 -5
@@ -0,0 +1,335 @@
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 = "/_platform";
16
+
17
+ /** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
18
+ export const MODULE_PREFIX = "/_platform";
19
+
20
+ /**
21
+ * 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
22
+ * scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
23
+ * 重复构造幂等安全(前缀重复登记同值、request 重绑同值)。
24
+ */
25
+ export function create_platformClient(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 { platformContactsGet, platformContactsDetailGet, platformMarketInstallPost, platformMarketInstallCancelPost, platformMarketTaskGet, platformMarketEnablePost, platformMarketMetaGet, platformMarketTrustGet, platformMarketTrustPost, platformMarketTrustKeyPost, platformMarketTrustKeyDelete, platformMarketIndexGet, platformMarketUninstallImpactGet, platformMarketUninstallPost, platformMarketHistoryGet, platformSolutionsRoutesGet, platformSolutionsVerifyPost, platformSolutionsVerifyLastGet };
37
+ }
38
+
39
+ /**
40
+ * @deprecated 请改用 create_platformClient(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 里调用 create_platformClient(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 async function platformContactsGet(): Promise<unknown> {
68
+ const client = ensureReq();
69
+ try {
70
+ const env = await client.get(`_platform/contacts`).json<OjEnvelope<unknown>>();
71
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
72
+ if (typeof env.code === "number" && env.code !== 0)
73
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
74
+ const data = env.data as unknown;
75
+ return data;
76
+ }
77
+ catch (e) {
78
+ throw await toApiError(e);
79
+ }
80
+ }
81
+
82
+ export async function platformContactsDetailGet(): Promise<unknown> {
83
+ const client = ensureReq();
84
+ try {
85
+ const env = await client.get(`_platform/contacts/detail`).json<OjEnvelope<unknown>>();
86
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
87
+ if (typeof env.code === "number" && env.code !== 0)
88
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
89
+ const data = env.data as unknown;
90
+ return data;
91
+ }
92
+ catch (e) {
93
+ throw await toApiError(e);
94
+ }
95
+ }
96
+
97
+ export async function platformMarketInstallPost(): Promise<unknown> {
98
+ const client = ensureReq();
99
+ try {
100
+ const env = await client.post(`_platform/market/install`).json<OjEnvelope<unknown>>();
101
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
102
+ if (typeof env.code === "number" && env.code !== 0)
103
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
104
+ const data = env.data as unknown;
105
+ return data;
106
+ }
107
+ catch (e) {
108
+ throw await toApiError(e);
109
+ }
110
+ }
111
+
112
+ export async function platformMarketInstallCancelPost(): Promise<unknown> {
113
+ const client = ensureReq();
114
+ try {
115
+ const env = await client.post(`_platform/market/install/cancel`).json<OjEnvelope<unknown>>();
116
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
117
+ if (typeof env.code === "number" && env.code !== 0)
118
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
119
+ const data = env.data as unknown;
120
+ return data;
121
+ }
122
+ catch (e) {
123
+ throw await toApiError(e);
124
+ }
125
+ }
126
+
127
+ export async function platformMarketTaskGet(): Promise<unknown> {
128
+ const client = ensureReq();
129
+ try {
130
+ const env = await client.get(`_platform/market/task`).json<OjEnvelope<unknown>>();
131
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
132
+ if (typeof env.code === "number" && env.code !== 0)
133
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
134
+ const data = env.data as unknown;
135
+ return data;
136
+ }
137
+ catch (e) {
138
+ throw await toApiError(e);
139
+ }
140
+ }
141
+
142
+ export async function platformMarketEnablePost(): Promise<unknown> {
143
+ const client = ensureReq();
144
+ try {
145
+ const env = await client.post(`_platform/market/enable`).json<OjEnvelope<unknown>>();
146
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
147
+ if (typeof env.code === "number" && env.code !== 0)
148
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
149
+ const data = env.data as unknown;
150
+ return data;
151
+ }
152
+ catch (e) {
153
+ throw await toApiError(e);
154
+ }
155
+ }
156
+
157
+ export async function platformMarketMetaGet(): Promise<unknown> {
158
+ const client = ensureReq();
159
+ try {
160
+ const env = await client.get(`_platform/market/meta`).json<OjEnvelope<unknown>>();
161
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
162
+ if (typeof env.code === "number" && env.code !== 0)
163
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
164
+ const data = env.data as unknown;
165
+ return data;
166
+ }
167
+ catch (e) {
168
+ throw await toApiError(e);
169
+ }
170
+ }
171
+
172
+ export async function platformMarketTrustGet(): Promise<unknown> {
173
+ const client = ensureReq();
174
+ try {
175
+ const env = await client.get(`_platform/market/trust`).json<OjEnvelope<unknown>>();
176
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
177
+ if (typeof env.code === "number" && env.code !== 0)
178
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
179
+ const data = env.data as unknown;
180
+ return data;
181
+ }
182
+ catch (e) {
183
+ throw await toApiError(e);
184
+ }
185
+ }
186
+
187
+ export async function platformMarketTrustPost(): Promise<unknown> {
188
+ const client = ensureReq();
189
+ try {
190
+ const env = await client.post(`_platform/market/trust`).json<OjEnvelope<unknown>>();
191
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
192
+ if (typeof env.code === "number" && env.code !== 0)
193
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
194
+ const data = env.data as unknown;
195
+ return data;
196
+ }
197
+ catch (e) {
198
+ throw await toApiError(e);
199
+ }
200
+ }
201
+
202
+ export async function platformMarketTrustKeyPost(): Promise<unknown> {
203
+ const client = ensureReq();
204
+ try {
205
+ const env = await client.post(`_platform/market/trust/key`).json<OjEnvelope<unknown>>();
206
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
207
+ if (typeof env.code === "number" && env.code !== 0)
208
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
209
+ const data = env.data as unknown;
210
+ return data;
211
+ }
212
+ catch (e) {
213
+ throw await toApiError(e);
214
+ }
215
+ }
216
+
217
+ export async function platformMarketTrustKeyDelete(): Promise<unknown> {
218
+ const client = ensureReq();
219
+ try {
220
+ const env = await client.delete(`_platform/market/trust/key`).json<OjEnvelope<unknown>>();
221
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
222
+ if (typeof env.code === "number" && env.code !== 0)
223
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
224
+ const data = env.data as unknown;
225
+ return data;
226
+ }
227
+ catch (e) {
228
+ throw await toApiError(e);
229
+ }
230
+ }
231
+
232
+ export async function platformMarketIndexGet(): Promise<unknown> {
233
+ const client = ensureReq();
234
+ try {
235
+ const env = await client.get(`_platform/market/index`).json<OjEnvelope<unknown>>();
236
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
237
+ if (typeof env.code === "number" && env.code !== 0)
238
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
239
+ const data = env.data as unknown;
240
+ return data;
241
+ }
242
+ catch (e) {
243
+ throw await toApiError(e);
244
+ }
245
+ }
246
+
247
+ export async function platformMarketUninstallImpactGet(): Promise<unknown> {
248
+ const client = ensureReq();
249
+ try {
250
+ const env = await client.get(`_platform/market/uninstall-impact`).json<OjEnvelope<unknown>>();
251
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
252
+ if (typeof env.code === "number" && env.code !== 0)
253
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
254
+ const data = env.data as unknown;
255
+ return data;
256
+ }
257
+ catch (e) {
258
+ throw await toApiError(e);
259
+ }
260
+ }
261
+
262
+ export async function platformMarketUninstallPost(): Promise<unknown> {
263
+ const client = ensureReq();
264
+ try {
265
+ const env = await client.post(`_platform/market/uninstall`).json<OjEnvelope<unknown>>();
266
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
267
+ if (typeof env.code === "number" && env.code !== 0)
268
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
269
+ const data = env.data as unknown;
270
+ return data;
271
+ }
272
+ catch (e) {
273
+ throw await toApiError(e);
274
+ }
275
+ }
276
+
277
+ export async function platformMarketHistoryGet(): Promise<unknown> {
278
+ const client = ensureReq();
279
+ try {
280
+ const env = await client.get(`_platform/market/history`).json<OjEnvelope<unknown>>();
281
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
282
+ if (typeof env.code === "number" && env.code !== 0)
283
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
284
+ const data = env.data as unknown;
285
+ return data;
286
+ }
287
+ catch (e) {
288
+ throw await toApiError(e);
289
+ }
290
+ }
291
+
292
+ export async function platformSolutionsRoutesGet(): Promise<unknown> {
293
+ const client = ensureReq();
294
+ try {
295
+ const env = await client.get(`_platform/solutions/routes`).json<OjEnvelope<unknown>>();
296
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
297
+ if (typeof env.code === "number" && env.code !== 0)
298
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
299
+ const data = env.data as unknown;
300
+ return data;
301
+ }
302
+ catch (e) {
303
+ throw await toApiError(e);
304
+ }
305
+ }
306
+
307
+ export async function platformSolutionsVerifyPost(): Promise<unknown> {
308
+ const client = ensureReq();
309
+ try {
310
+ const env = await client.post(`_platform/solutions/verify`).json<OjEnvelope<unknown>>();
311
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
312
+ if (typeof env.code === "number" && env.code !== 0)
313
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
314
+ const data = env.data as unknown;
315
+ return data;
316
+ }
317
+ catch (e) {
318
+ throw await toApiError(e);
319
+ }
320
+ }
321
+
322
+ export async function platformSolutionsVerifyLastGet(): Promise<unknown> {
323
+ const client = ensureReq();
324
+ try {
325
+ const env = await client.get(`_platform/solutions/verify/last`).json<OjEnvelope<unknown>>();
326
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
327
+ if (typeof env.code === "number" && env.code !== 0)
328
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
329
+ const data = env.data as unknown;
330
+ return data;
331
+ }
332
+ catch (e) {
333
+ throw await toApiError(e);
334
+ }
335
+ }
@@ -0,0 +1,42 @@
1
+ import type { AppRouteRecordRaw, ModuleDefinition } from "@oj-module/runtime";
2
+
3
+ import { CopyrightOutlined } from "@ant-design/icons";
4
+
5
+ import { createElement, lazy } from "react";
6
+
7
+ const About = lazy(() => import("./pages/index"));
8
+
9
+ const routes: AppRouteRecordRaw[] = [
10
+ {
11
+ path: "/about",
12
+ handle: {
13
+ layout: "container",
14
+ order: 120,
15
+ title: "about:menu.about",
16
+ icon: createElement(CopyrightOutlined),
17
+ },
18
+ children: [
19
+ {
20
+ index: true,
21
+ Component: About,
22
+ handle: {
23
+ title: "about:menu.about",
24
+ icon: createElement(CopyrightOutlined),
25
+ },
26
+ },
27
+ ],
28
+ },
29
+ ];
30
+
31
+ const mod: ModuleDefinition = {
32
+ name: "about",
33
+ description: "关于页面模块",
34
+ version: "1.0.0",
35
+ routes,
36
+ i18n: {
37
+ "zh-CN": () => import("./locales/zh-CN.json"),
38
+ "en-US": () => import("./locales/en-US.json"),
39
+ },
40
+ };
41
+
42
+ export default mod;
@@ -0,0 +1,16 @@
1
+ {
2
+ "aboutProject": "About Project",
3
+ "descriptions": "react-ant-admin is a mid to backend solution based on React Hooks, Vite, and TypeScript. It is designed to help you quickly build enterprise level backend projects. It can help you in adopting new technologies and other aspects.",
4
+ "projectMessage": "Project Message",
5
+ "version": "Version",
6
+ "lastBuildTime": "Last Build Time",
7
+ "license": "License",
8
+ "previewAddress": "Preview URL",
9
+ "documentAddress": "Documentation URL",
10
+ "author": "Author",
11
+ "dependencies": "Prod Dependencies",
12
+ "devDependencies": "Dev Dependencies",
13
+ "menu": {
14
+ "about": "About"
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "aboutProject": "关于项目",
3
+ "descriptions": "react-antd-admin 是一个基于 React Hooks、Vite 和 TypeScript 的中后台解决方案。它旨在帮助您快速搭建企业级中后台项目。无论是在采用新技术方面还是其他方面,它都能为您提供帮助。",
4
+ "projectMessage": "项目信息",
5
+ "version": "版本",
6
+ "lastBuildTime": "最后构建时间",
7
+ "license": "开源许可协议",
8
+ "previewAddress": "预览地址",
9
+ "documentAddress": "文档地址",
10
+ "author": "作者",
11
+ "dependencies": "生产依赖",
12
+ "devDependencies": "开发依赖",
13
+ "menu": {
14
+ "about": "关于"
15
+ }
16
+ }
@@ -0,0 +1,20 @@
1
+ import { getAppInfo } from "@oj-module/runtime";
2
+
3
+ // P6.5:devDependencies 不再注入应用元信息(清单入 bundle 属信息
4
+ // 泄露),此数组恒为空,about 页对应卡片随之自动隐藏。
5
+ // 契约(P6.5/AppInfo):不同宿主注入的应用元信息字段可缺省
6
+ // (runtime 产物即不携带 dependencies)——缺字段必须走空态而非崩溃,
7
+ // 一律经 getAppInfo() 读取。此前直接 Object.keys(dependencies) 在宿主
8
+ // 形态直接崩整页(React Router ErrorBoundary,202609010056 暴露)
9
+ const { dependencies } = getAppInfo().pkg;
10
+
11
+ export const dependenciesItems = Object.keys(dependencies ?? {}).map((dep) => {
12
+ const value = dependencies?.[dep as keyof typeof dependencies];
13
+ return {
14
+ key: dep,
15
+ label: dep,
16
+ children: value,
17
+ };
18
+ });
19
+
20
+ export const devDependenciesItems: { key: string, label: string, children: string }[] = [];
@@ -0,0 +1,135 @@
1
+ import { BasicContent, getAppInfo } from "@oj-module/runtime";
2
+
3
+ import { Badge, Card, Col, Descriptions, Row, Tag, theme, Typography } from "antd";
4
+ import { useTranslation } from "react-i18next";
5
+
6
+ import { dependenciesItems, devDependenciesItems } from "./constants";
7
+
8
+ const { version } = getAppInfo().pkg;
9
+ const { lastBuildTime } = getAppInfo();
10
+
11
+ const { Text, Link } = Typography;
12
+
13
+ export default function About() {
14
+ const { t } = useTranslation();
15
+ const {
16
+ token: { colorBgLayout },
17
+ } = theme.useToken();
18
+
19
+ const projectMessageItems = [
20
+ {
21
+ key: 1,
22
+ label: t("about:version"),
23
+ children: <Text code>{version}</Text>,
24
+ },
25
+ {
26
+ key: 2,
27
+ label: t("about:lastBuildTime"),
28
+ children: <Tag color="#55acee">{lastBuildTime}</Tag>,
29
+ },
30
+ {
31
+ key: 3,
32
+ label: t("about:license"),
33
+ children: <Tag color="green">{getAppInfo().pkg.license}</Tag>,
34
+ },
35
+ {
36
+ key: 4,
37
+ label: t("about:previewAddress"),
38
+ children: (
39
+ <Link
40
+ rel="noreferrer noopener"
41
+ copyable
42
+ target="_blank"
43
+ href="https://condorheroblog.github.io/react-antd-admin/"
44
+ >
45
+ {t("common.view")}
46
+ </Link>
47
+ ),
48
+ },
49
+ {
50
+ key: 5,
51
+ label: t("about:documentAddress"),
52
+ children: (
53
+ <Link
54
+ rel="noreferrer noopener"
55
+ copyable
56
+ target="_blank"
57
+ href="https://condorheroblog.github.io/react-antd-admin/docs/"
58
+ >
59
+ {t("common.view")}
60
+ </Link>
61
+ ),
62
+ },
63
+ {
64
+ key: 6,
65
+ label: "Github",
66
+ children: (
67
+ <Link
68
+ rel="noreferrer noopener"
69
+ copyable
70
+ target="_blank"
71
+ href="https://github.com/condorheroblog/react-antd-admin"
72
+ >
73
+ {import.meta.env.VITE_GLOB_APP_TITLE}
74
+ </Link>
75
+ ),
76
+ },
77
+ {
78
+ key: 7,
79
+ label: t("about:author"),
80
+ children: (
81
+ <Link
82
+ rel="noreferrer noopener"
83
+ target="_blank"
84
+ href="https://github.com/condorheroblog/"
85
+ >
86
+ {getAppInfo().pkg.author}
87
+ </Link>
88
+ ),
89
+ },
90
+ ];
91
+
92
+ return (
93
+ <BasicContent>
94
+ <Row gutter={[0, 20]} style={{ backgroundColor: colorBgLayout }}>
95
+ <Col span={24}>
96
+ <Row>
97
+ <Col>
98
+ <Card title={t("about:aboutProject")}>
99
+ <Descriptions
100
+ items={[
101
+ {
102
+ key: 1,
103
+ children: t("about:descriptions"),
104
+ },
105
+ ]}
106
+ />
107
+ </Card>
108
+ </Col>
109
+ </Row>
110
+ </Col>
111
+ <Col span={24}>
112
+ <Card title={t("about:projectMessage")}>
113
+ <Descriptions bordered items={projectMessageItems} />
114
+ </Card>
115
+ </Col>
116
+ <Col span={24}>
117
+ <Badge.Ribbon text={dependenciesItems.length} color="green">
118
+ <Card title={t("about:dependencies")}>
119
+ <Descriptions bordered items={dependenciesItems} />
120
+ </Card>
121
+ </Badge.Ribbon>
122
+ </Col>
123
+ {devDependenciesItems.length > 0 && (
124
+ <Col span={24}>
125
+ <Badge.Ribbon text={devDependenciesItems.length} color="blue">
126
+ <Card title={t("about:devDependencies")}>
127
+ <Descriptions bordered items={devDependenciesItems} />
128
+ </Card>
129
+ </Badge.Ribbon>
130
+ </Col>
131
+ )}
132
+ </Row>
133
+ </BasicContent>
134
+ );
135
+ }
@@ -0,0 +1,74 @@
1
+ import type { AppRouteRecordRaw, ModuleDefinition } from "@oj-module/runtime";
2
+ import { EyeOutlined, FileTextOutlined, LockOutlined, SafetyOutlined } from "@ant-design/icons";
3
+
4
+ import { accessControlCodes } from "@oj-module/runtime";
5
+ import { createElement, lazy } from "react";
6
+
7
+ const PageControl = lazy(() => import("./pages/page-control"));
8
+ const ButtonControl = lazy(() => import("./pages/button-control"));
9
+ const AdminVisible = lazy(() => import("./pages/admin-visible"));
10
+ const CommonVisible = lazy(() => import("./pages/common-visible"));
11
+
12
+ const routes: AppRouteRecordRaw[] = [
13
+ {
14
+ path: "/access",
15
+ handle: {
16
+ layout: "container",
17
+ icon: createElement(SafetyOutlined),
18
+ title: "access:menu.access",
19
+ order: 10,
20
+ },
21
+ children: [
22
+ {
23
+ path: "/access/page-control",
24
+ Component: PageControl,
25
+ handle: {
26
+ icon: createElement(FileTextOutlined),
27
+ title: "access:menu.pageControl",
28
+ permissions: [
29
+ accessControlCodes.get,
30
+ ],
31
+ },
32
+ },
33
+ {
34
+ path: "/access/button-control",
35
+ Component: ButtonControl,
36
+ handle: {
37
+ icon: createElement(LockOutlined),
38
+ title: "access:menu.buttonControl",
39
+ },
40
+ },
41
+ {
42
+ path: "/access/admin-visible",
43
+ Component: AdminVisible,
44
+ handle: {
45
+ icon: createElement(EyeOutlined),
46
+ title: "access:menu.adminVisible",
47
+ roles: ["admin"],
48
+ },
49
+ },
50
+ {
51
+ path: "/access/common-visible",
52
+ Component: CommonVisible,
53
+ handle: {
54
+ icon: createElement(EyeOutlined),
55
+ title: "access:menu.commonVisible",
56
+ roles: ["common"],
57
+ },
58
+ },
59
+ ],
60
+ },
61
+ ];
62
+
63
+ const mod: ModuleDefinition = {
64
+ name: "access",
65
+ description: "权限控制模块",
66
+ version: "1.0.0",
67
+ routes,
68
+ i18n: {
69
+ "zh-CN": () => import("./locales/zh-CN.json"),
70
+ "en-US": () => import("./locales/en-US.json"),
71
+ },
72
+ };
73
+
74
+ export default mod;
@@ -0,0 +1,46 @@
1
+ {
2
+ "accessMode": {
3
+ "title": "Backend Access Permission Visibility",
4
+ "description": "The current page only supports obtaining route visibility through backend interfaces"
5
+ },
6
+ "adminVisible": {
7
+ "title": "Admin Visible",
8
+ "description": "The current page is only visible to Admin accounts"
9
+ },
10
+ "commonVisible": {
11
+ "title": "Common Visible",
12
+ "description": "The current page is only visible to Common accounts"
13
+ },
14
+ "pageControl": {
15
+ "alertMessage": "Demo of Frontend Page Access Permissions",
16
+ "alertDescription": "Switch to different accounts and observe the changes in the 'Permission Demonstration' submenu on the left.",
17
+ "cardTitle": "Permission Mode",
18
+ "frontendControl": "Frontend Permission Control",
19
+ "backendControl": "Backend Permission Control",
20
+ "switchToFrontend": "Switch to Frontend Permission Mode",
21
+ "switchToBackend": "Switch to Backend Permission Mode",
22
+ "switchAdmin": "Switch to Admin User",
23
+ "switchCommon": "Switch to Common User",
24
+ "currentPermissionMode": "Current permission mode:",
25
+ "accountSwitching": "Account Switching",
26
+ "warningMessage": "If enableFrontendAceess and enableBackendAceess are equal, switching routing mode is not allowed."
27
+ },
28
+ "buttonControl": {
29
+ "alertMessage": "Demo of Frontend Button Access Permissions",
30
+ "alertDescription": "Switch between different accounts to observe button changes.",
31
+ "currentRole": "Current Role",
32
+ "switchAdmin": "Switch to Admin User",
33
+ "switchCommon": "Switch to Common User",
34
+ "componentControlPermissionCodes": "Component-based Control - Permission Codes",
35
+ "componentControlRoles": "Component-based Control - Roles",
36
+ "functionControlPermissionCodes": "Function-based Control - Permission Codes",
37
+ "functionControlRoles": "Function-based Control - Roles"
38
+ },
39
+ "menu": {
40
+ "access": "Access Demo",
41
+ "pageControl": "Page Control",
42
+ "buttonControl": "Button Control",
43
+ "adminVisible": "Admin Visible",
44
+ "commonVisible": "Common Visible"
45
+ }
46
+ }