@oj-module/cli 0.2.53 → 0.2.56

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 (330) hide show
  1. package/devkit/SKILL.md +4 -4
  2. package/devkit/manual.md +79 -65
  3. package/package.json +2 -2
  4. package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
  5. package/shell-dist/assets/runtime.js +7 -4
  6. package/shell-dist/index.html +3 -3
  7. package/shell-dist/versions.json +3 -3
  8. package/src/__tests__/layout.test.ts +30 -1
  9. package/src/__tests__/templates-schema-columns.test.ts +99 -0
  10. package/src/__tests__/templates-tenant-scope.test.ts +3 -2
  11. package/src/alias-paths.ts +11 -12
  12. package/src/builtin.ts +10 -3
  13. package/src/config.ts +9 -0
  14. package/src/contract/__tests__/client-path.test.ts +30 -0
  15. package/src/contract/__tests__/emit-client.test.ts +20 -2
  16. package/src/contract/__tests__/handler-scan.test.ts +23 -0
  17. package/src/contract/__tests__/market-client.integration.test.ts +2 -2
  18. package/src/contract/__tests__/run-api.test.ts +2 -2
  19. package/src/contract/check.ts +11 -7
  20. package/src/contract/client-path.ts +30 -0
  21. package/src/contract/emit-client.ts +27 -6
  22. package/src/contract/handler-scan.ts +40 -3
  23. package/src/contract/run.ts +15 -5
  24. package/src/init.ts +29 -3
  25. package/src/layout.ts +72 -16
  26. package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
  27. package/src/market/__tests__/bootstrap.test.ts +1 -1
  28. package/src/site.ts +1 -1
  29. package/templates/README.md +49 -43
  30. package/templates/init.include.yaml +31 -19
  31. package/templates/openapi.json +1488 -120
  32. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/users.ts +27 -0
  33. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/oplog.ts +4 -2
  34. package/templates/src/{_platform/api → app/api/_platform}/contacts/api.ts +29 -1
  35. package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +25 -1
  36. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +7 -0
  37. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +4 -0
  38. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +8 -0
  39. package/templates/src/{_platform/api → app/api/_platform}/schema.yaml +5 -0
  40. package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +60 -1
  41. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/replay.ts +9 -3
  42. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/tenant-admin.ts +18 -27
  43. package/templates/src/{auth/api → app/api/auth}/api.ts +59 -0
  44. package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +37 -1
  45. package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +23 -0
  46. package/templates/src/{notification/api → app/api/notification}/api.ts +17 -0
  47. package/templates/src/{notification/api → app/api/notification}/del/api.ts +2 -0
  48. package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
  49. package/templates/src/{system/api → app/api/system}/roles/api.ts +3 -0
  50. package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +3 -0
  51. package/templates/src/{system/api → app/api/system}/settings/api.ts +3 -0
  52. package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +3 -0
  53. package/templates/src/{system/api → app/api/system}/users/password/api.ts +3 -0
  54. package/templates/src/{system/api → app/api/system}/users/roles/api.ts +3 -0
  55. package/templates/src/app/api/web/get-async-routes/api.ts +23 -0
  56. package/templates/src/app/api/web/hello/api.ts +22 -0
  57. package/templates/src/{web/api → app/api/web}/user-info/api.ts +21 -1
  58. package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +99 -35
  59. package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +108 -61
  60. package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +133 -13
  61. package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +134 -33
  62. package/templates/src/app/web/entry.ts +77 -0
  63. package/templates/src/{home/web/__client/api.ts → app/web/home/__client/index.ts} +5 -2
  64. package/templates/src/app/web/home/routes.ts +41 -0
  65. package/templates/src/app/web/login/routes.ts +71 -0
  66. package/templates/src/{notification/web → app/web/notification}/__client/api.schemas.ts +14 -0
  67. package/templates/src/{notification/web/__client/api.ts → app/web/notification/__client/index.ts} +67 -20
  68. package/templates/src/{notification/web → app/web/notification}/pages/center/index.tsx +1 -1
  69. package/templates/src/app/web/notification/routes.ts +70 -0
  70. package/templates/src/{personal-center/web/__client/api.ts → app/web/personal-center/__client/index.ts} +5 -2
  71. package/templates/src/{personal-center/web → app/web/personal-center}/pages/my-profile/index.tsx +1 -1
  72. package/templates/src/app/web/personal-center/routes.ts +49 -0
  73. package/templates/src/{system/web → app/web/system}/__client/api.schemas.ts +29 -22
  74. package/templates/src/{system/web/__client/api.ts → app/web/system/__client/index.ts} +103 -58
  75. package/templates/src/{system/web → app/web/system}/locales/en-US.json +2 -3
  76. package/templates/src/{system/web → app/web/system}/locales/zh-CN.json +2 -3
  77. package/templates/src/{system/web → app/web/system}/pages/departments/index.tsx +2 -2
  78. package/templates/src/{system/web → app/web/system}/pages/login-methods/index.tsx +1 -1
  79. package/templates/src/{system/web → app/web/system}/pages/oplog/index.tsx +44 -19
  80. package/templates/src/{system/web → app/web/system}/pages/roles/index.tsx +5 -3
  81. package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
  82. package/templates/src/{system/web → app/web/system}/pages/settings/index.tsx +2 -2
  83. package/templates/src/app/web/system/pages/users/can-manage.ts +21 -0
  84. package/templates/src/{system/web → app/web/system}/pages/users/index.tsx +23 -15
  85. package/templates/src/{system/web → app/web/system}/pages/users/roles.tsx +1 -1
  86. package/templates/src/{system/web → app/web/system}/pages/wecom/index.tsx +12 -3
  87. package/templates/src/{system/web/entry.ts → app/web/system/routes.ts} +25 -36
  88. package/templates/src/app/web/web/__client/api.schemas.ts +36 -0
  89. package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +38 -11
  90. package/templates/src/oj-market/web/api/defaultClient.ts +1 -1
  91. package/templates/tests/auth-ldap.spec.ts +2 -2
  92. package/templates/tests/auth-session.spec.ts +3 -3
  93. package/templates/tests/auth-throttle.spec.ts +1 -1
  94. package/templates/tests/fixture.ts +6 -4
  95. package/templates/tests/guard.spec.ts +1 -1
  96. package/templates/tests/lifecycle/atomic-state.spec.ts +3 -3
  97. package/templates/tests/lifecycle/bootstrap.spec.ts +3 -3
  98. package/templates/tests/lifecycle/deploy-smoke.spec.ts +8 -8
  99. package/templates/tests/lifecycle/installer.spec.ts +10 -10
  100. package/templates/tests/lifecycle/market-api.spec.ts +14 -14
  101. package/templates/tests/lifecycle/migrate.spec.ts +6 -6
  102. package/templates/tests/lifecycle/preflight.spec.ts +3 -3
  103. package/templates/tests/lifecycle/register.spec.ts +1 -1
  104. package/templates/tests/lifecycle/semver.spec.ts +1 -1
  105. package/templates/tests/lifecycle/sha384.spec.ts +1 -1
  106. package/templates/tests/lifecycle/solutions-api.spec.ts +1 -1
  107. package/templates/tests/lifecycle/source-seq.spec.ts +1 -1
  108. package/templates/tests/lifecycle/steps-fs.spec.ts +9 -9
  109. package/templates/tests/lifecycle/text-edit.spec.ts +1 -1
  110. package/templates/tests/lifecycle/tgz-guard.spec.ts +2 -2
  111. package/templates/tests/lifecycle/trust.spec.ts +5 -5
  112. package/templates/tests/lifecycle/uninstall.spec.ts +7 -7
  113. package/templates/tests/lifecycle/verify-checks.spec.ts +5 -5
  114. package/templates/tests/lifecycle/verify-report.spec.ts +4 -4
  115. package/templates/tests/org-departments.spec.ts +10 -6
  116. package/templates/tests/org-read.spec.ts +7 -7
  117. package/templates/tests/query-utils.spec.ts +1 -1
  118. package/templates/tests/rbac-audit.spec.ts +1 -1
  119. package/templates/tests/rbac-contacts.spec.ts +2 -2
  120. package/templates/tests/rbac-guard.spec.ts +1 -1
  121. package/templates/tests/rbac-roles.spec.ts +10 -2
  122. package/templates/tests/rbac-seed.spec.ts +1 -1
  123. package/templates/tests/rbac-settings.spec.ts +77 -7
  124. package/templates/tests/rbac-solution-perms.spec.ts +1 -1
  125. package/templates/tests/rbac-tables.spec.ts +29 -0
  126. package/templates/tests/rbac-users.spec.ts +55 -3
  127. package/templates/tests/roles-page.spec.ts +40 -0
  128. package/templates/tests/seed-role-accounts.spec.ts +1 -1
  129. package/templates/tests/tenant-access-cache.spec.ts +1 -1
  130. package/templates/tests/tenant-forgery.spec.ts +5 -5
  131. package/templates/tests/tenant-isolation.spec.ts +5 -4
  132. package/templates/tests/username-namespace.spec.ts +3 -3
  133. package/templates/tests/users-page.spec.ts +39 -0
  134. package/templates/tests/wecom-admin.spec.ts +6 -6
  135. package/templates/tests/wecom-client-timeout.spec.ts +1 -1
  136. package/templates/tests/wecom-connector.spec.ts +9 -9
  137. package/templates/tests/wecom-corp.spec.ts +9 -9
  138. package/templates/tests/wecom-crypt.spec.ts +1 -1
  139. package/templates/tests/wecom-endpoints.spec.ts +2 -2
  140. package/templates/tests/wecom-landing.spec.ts +1 -1
  141. package/templates/tests/wecom-org-sync.spec.ts +7 -7
  142. package/templates/tests/wecom-sync.spec.ts +3 -3
  143. package/templates/tsconfig.paths.json +11 -11
  144. package/templates/vitest.config.ts +2 -2
  145. package/templates/web.config.ts +24 -15
  146. package/vendor/host-versions.json +3 -3
  147. package/templates/src/home/web/entry.ts +0 -49
  148. package/templates/src/login/web/entry.ts +0 -79
  149. package/templates/src/notification/web/entry.ts +0 -84
  150. package/templates/src/personal-center/web/entry.ts +0 -60
  151. package/templates/src/web/api/get-async-routes/api.ts +0 -8
  152. package/templates/src/web/api/hello/api.ts +0 -10
  153. package/templates/src/web/web/__client/api.schemas.ts +0 -8
  154. package/templates/src/{_platform/api → app/api/_platform}/README.md +0 -0
  155. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/atomic.ts +0 -0
  156. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/history.ts +0 -0
  157. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/installer.ts +0 -0
  158. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/limits.ts +0 -0
  159. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/lock.ts +0 -0
  160. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/semver.ts +0 -0
  161. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/sha384.ts +0 -0
  162. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/source-seq.ts +0 -0
  163. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/state.ts +0 -0
  164. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/deploy-web.ts +0 -0
  165. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/download.ts +0 -0
  166. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/extract.ts +0 -0
  167. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/migrate.ts +0 -0
  168. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/preflight.ts +0 -0
  169. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/register.ts +0 -0
  170. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/reload.ts +0 -0
  171. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/smoke.ts +0 -0
  172. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/verify.ts +0 -0
  173. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tasks.ts +0 -0
  174. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/text-edit.ts +0 -0
  175. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tgz-guard.ts +0 -0
  176. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/trust.ts +0 -0
  177. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/types.ts +0 -0
  178. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/uninstall.ts +0 -0
  179. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-checks.ts +0 -0
  180. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-report.ts +0 -0
  181. package/templates/src/{_platform/api → app/api/_platform}/_shared/respond.ts +0 -0
  182. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/contacts.ts +0 -0
  183. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org-read.ts +0 -0
  184. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org.ts +0 -0
  185. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/roles.ts +0 -0
  186. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/settings.ts +0 -0
  187. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/solution-perms.ts +0 -0
  188. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/access.ts +0 -0
  189. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/audit.ts +0 -0
  190. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/guard.ts +0 -0
  191. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/query.ts +0 -0
  192. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/rate.ts +0 -0
  193. package/templates/src/{_platform/api → app/api/_platform}/_shared/site-facade.ts +0 -0
  194. package/templates/src/{_platform/api → app/api/_platform}/fixtures/l1-test-user.sql +0 -0
  195. package/templates/src/{_platform/api → app/api/_platform}/manifest.yaml +0 -0
  196. package/templates/src/{_platform/api → app/api/_platform}/market/api.ts +0 -0
  197. package/templates/src/{_platform/api → app/api/_platform}/market/bootstrap.ts +0 -0
  198. package/templates/src/{_platform/api → app/api/_platform}/market/index-source.ts +0 -0
  199. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.mysql.sql +0 -0
  200. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.pg.sql +0 -0
  201. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.sql +0 -0
  202. package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
  203. package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.sql +0 -0
  204. package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.mysql.sql +0 -0
  205. package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.sql +0 -0
  206. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.mysql.sql +0 -0
  207. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.pg.sql +0 -0
  208. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.sql +0 -0
  209. package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.mysql.sql +0 -0
  210. package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.sql +0 -0
  211. package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
  212. package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.sql +0 -0
  213. package/templates/src/{_platform/api → app/api/_platform}/migrations/0007__users_email.sql +0 -0
  214. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
  215. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.pg.sql +0 -0
  216. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.sql +0 -0
  217. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.mysql.sql +0 -0
  218. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.pg.sql +0 -0
  219. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.sql +0 -0
  220. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.mysql.sql +0 -0
  221. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.pg.sql +0 -0
  222. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.sql +0 -0
  223. package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
  224. package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.sql +0 -0
  225. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.mysql.sql +0 -0
  226. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.pg.sql +0 -0
  227. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.sql +0 -0
  228. package/templates/src/{_platform/api → app/api/_platform}/migrations/0013__users_profile.sql +0 -0
  229. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.mysql.sql +0 -0
  230. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.pg.sql +0 -0
  231. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.sql +0 -0
  232. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.mysql.sql +0 -0
  233. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.pg.sql +0 -0
  234. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.sql +0 -0
  235. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.mysql.sql +0 -0
  236. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.pg.sql +0 -0
  237. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.sql +0 -0
  238. package/templates/src/{_platform/api → app/api/_platform}/org/departments/api.ts +0 -0
  239. package/templates/src/{_platform/api → app/api/_platform}/org/is-member/api.ts +0 -0
  240. package/templates/src/{_platform/api → app/api/_platform}/org/members/api.ts +0 -0
  241. package/templates/src/{_platform/api → app/api/_platform}/org/picker/api.ts +0 -0
  242. package/templates/src/{_platform/api → app/api/_platform}/org/resolve/api.ts +0 -0
  243. package/templates/src/{_platform/api → app/api/_platform}/org/tree/api.ts +0 -0
  244. package/templates/src/{_platform/api → app/api/_platform}/org/user/api.ts +0 -0
  245. package/templates/src/{_platform/api → app/api/_platform}/seed.mysql.sql +0 -0
  246. package/templates/src/{_platform/api → app/api/_platform}/seed.pg.sql +0 -0
  247. package/templates/src/{_platform/api → app/api/_platform}/seed.sql +0 -0
  248. package/templates/src/{auth/api → app/api/auth}/_shared/ldap-login.ts +0 -0
  249. package/templates/src/{auth/api → app/api/auth}/_shared/ldap.ts +0 -0
  250. package/templates/src/{auth/api → app/api/auth}/_shared/login-throttle.ts +0 -0
  251. package/templates/src/{auth/api → app/api/auth}/_shared/session.ts +0 -0
  252. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/admin.ts +1 -1
  253. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/client.ts +0 -0
  254. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/config.ts +0 -0
  255. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/contacts.ts +0 -0
  256. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/crypt.ts +0 -0
  257. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/events.ts +1 -1
  258. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/login.ts +0 -0
  259. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/payload.ts +0 -0
  260. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/store.ts +0 -0
  261. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/sync.ts +0 -0
  262. package/templates/src/{auth/api → app/api/auth}/manifest.yaml +0 -0
  263. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.mysql.sql +0 -0
  264. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.pg.sql +0 -0
  265. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.sql +0 -0
  266. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.mysql.sql +0 -0
  267. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.pg.sql +0 -0
  268. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.sql +0 -0
  269. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.mysql.sql +0 -0
  270. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.pg.sql +0 -0
  271. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.sql +0 -0
  272. package/templates/src/{auth/api → app/api/auth}/schema.yaml +0 -0
  273. package/templates/src/{auth/api → app/api/auth}/wecom/admin/api.ts +0 -0
  274. package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/api.ts +1 -1
  275. package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/password/api.ts +1 -1
  276. /package/templates/src/{auth/api → app/api/auth}/wecom/sync/api.ts +0 -0
  277. /package/templates/src/{home/api → app/api/home}/line/api.ts +0 -0
  278. /package/templates/src/{home/api → app/api/home}/manifest.yaml +0 -0
  279. /package/templates/src/{home/api → app/api/home}/migrations/0001__create_home_tables.sql +0 -0
  280. /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.mysql.sql +0 -0
  281. /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.sql +0 -0
  282. /package/templates/src/{home/api → app/api/home}/pie/api.ts +0 -0
  283. /package/templates/src/{home/api → app/api/home}/schema.yaml +0 -0
  284. /package/templates/src/{home/api → app/api/home}/seed.sql +0 -0
  285. /package/templates/src/{notification/api → app/api/notification}/_shared/notify.ts +0 -0
  286. /package/templates/src/{notification/api → app/api/notification}/manifest.yaml +0 -0
  287. /package/templates/src/{notification/api → app/api/notification}/migrations/0001__create_notifications.sql +0 -0
  288. /package/templates/src/{notification/api → app/api/notification}/migrations/0002__notifications_user.sql +0 -0
  289. /package/templates/src/{notification/api → app/api/notification}/migrations/0003__notifications_broadcast.sql +0 -0
  290. /package/templates/src/{notification/api → app/api/notification}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
  291. /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.mysql.sql +0 -0
  292. /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.sql +0 -0
  293. /package/templates/src/{notification/api → app/api/notification}/schema.yaml +0 -0
  294. /package/templates/src/{notification/api → app/api/notification}/seed.sql +0 -0
  295. /package/templates/src/{personal-center/api → app/api/personal-center}/manifest.yaml +0 -0
  296. /package/templates/src/{personal-center/api → app/api/personal-center}/profile/api.ts +0 -0
  297. /package/templates/src/{personal-center/api → app/api/personal-center}/upload/api.ts +0 -0
  298. /package/templates/src/{system/api → app/api/system}/departments/api.ts +0 -0
  299. /package/templates/src/{system/api → app/api/system}/departments/detach/api.ts +0 -0
  300. /package/templates/src/{system/api → app/api/system}/departments/members/api.ts +0 -0
  301. /package/templates/src/{system/api → app/api/system}/departments/move/api.ts +0 -0
  302. /package/templates/src/{system/api → app/api/system}/login-methods/api.ts +0 -0
  303. /package/templates/src/{system/api → app/api/system}/manifest.yaml +0 -0
  304. /package/templates/src/{system/api → app/api/system}/permissions/api.ts +0 -0
  305. /package/templates/src/{system/api → app/api/system}/users/api.ts +0 -0
  306. /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
  307. /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
  308. /package/templates/src/{home/web → app/web/home}/__client/api.schemas.ts +0 -0
  309. /package/templates/src/{home/web → app/web/home}/locales/en-US.json +0 -0
  310. /package/templates/src/{home/web → app/web/home}/locales/zh-CN.json +0 -0
  311. /package/templates/src/{home/web → app/web/home}/pages/components/bar-chart.tsx +0 -0
  312. /package/templates/src/{home/web → app/web/home}/pages/components/card-list.tsx +0 -0
  313. /package/templates/src/{home/web → app/web/home}/pages/components/line-chart.tsx +0 -0
  314. /package/templates/src/{home/web → app/web/home}/pages/components/pie-chart.tsx +0 -0
  315. /package/templates/src/{home/web → app/web/home}/pages/index.tsx +0 -0
  316. /package/templates/src/{login/web → app/web/login}/auth-provider.ts +0 -0
  317. /package/templates/src/{login/web → app/web/login}/locales/en-US.json +0 -0
  318. /package/templates/src/{login/web → app/web/login}/locales/zh-CN.json +0 -0
  319. /package/templates/src/{login/web → app/web/login}/pages/change-password.tsx +0 -0
  320. /package/templates/src/{login/web → app/web/login}/pages/login.tsx +0 -0
  321. /package/templates/src/{login/web → app/web/login}/wecom.ts +0 -0
  322. /package/templates/src/{notification/web → app/web/notification}/locales/en-US.json +0 -0
  323. /package/templates/src/{notification/web → app/web/notification}/locales/zh-CN.json +0 -0
  324. /package/templates/src/{personal-center/web → app/web/personal-center}/__client/api.schemas.ts +0 -0
  325. /package/templates/src/{personal-center/web → app/web/personal-center}/locales/en-US.json +0 -0
  326. /package/templates/src/{personal-center/web → app/web/personal-center}/locales/zh-CN.json +0 -0
  327. /package/templates/src/{system/web → app/web/system}/pages/departments/sync-bar.tsx +0 -0
  328. /package/templates/src/{system/web → app/web/system}/pages/departments/tree.ts +0 -0
  329. /package/templates/src/{system/web → app/web/system}/pages/errors.ts +0 -0
  330. /package/templates/src/{system/web → app/web/system}/pages/forbidden.tsx +0 -0
@@ -4,10 +4,89 @@
4
4
  import { z } from "@oj-module/runtime";
5
5
 
6
6
  export const schemas = {
7
+ "authLoginPost": {
8
+ body: z.object({
9
+ "username": z.string().min(1),
10
+ "password": z.string().min(1)
11
+ }),
12
+ data: z.object({
13
+ "access_token": z.string(),
14
+ "refresh_token": z.string(),
15
+ "expires_in": z.number(),
16
+ "restricted": z.boolean(),
17
+ "user": z.object({
18
+ "id": z.number(),
19
+ "username": z.string(),
20
+ "display_name": z.string().nullable(),
21
+ "avatar_base64": z.string().nullable(),
22
+ "must_change": z.boolean(),
23
+ "roles": z.array(z.string())
24
+ })
25
+ }),
26
+ },
27
+ "authLogoutPost": {
28
+ body: z.object({
29
+ "refresh_token": z.string().min(1)
30
+ }),
31
+ data: z.null(),
32
+ },
33
+ "authRefreshPost": {
34
+ body: z.object({
35
+ "refresh_token": z.string().min(1)
36
+ }),
37
+ data: z.object({
38
+ "access_token": z.string(),
39
+ "refresh_token": z.string(),
40
+ "expires_in": z.number(),
41
+ "restricted": z.boolean(),
42
+ "user": z.object({
43
+ "id": z.number(),
44
+ "username": z.string(),
45
+ "display_name": z.string().nullable(),
46
+ "avatar_base64": z.string().nullable(),
47
+ "must_change": z.boolean(),
48
+ "roles": z.array(z.string())
49
+ })
50
+ }),
51
+ },
7
52
  "authPasswordPut": {
8
53
  body: z.object({
9
54
  "old_password": z.string().min(1),
10
55
  "new_password": z.string().min(6)
56
+ }),
57
+ data: z.object({
58
+ "access_token": z.string(),
59
+ "refresh_token": z.string(),
60
+ "expires_in": z.number(),
61
+ "restricted": z.boolean(),
62
+ "user": z.object({
63
+ "id": z.number(),
64
+ "username": z.string(),
65
+ "display_name": z.string().nullable(),
66
+ "avatar_base64": z.string().nullable(),
67
+ "must_change": z.boolean(),
68
+ "roles": z.array(z.string())
69
+ })
70
+ }),
71
+ },
72
+ "authLdapLoginPost": {
73
+ body: z.object({
74
+ "username": z.string().min(1),
75
+ "password": z.string().min(1)
76
+ }),
77
+ data: z.object({
78
+ "access_token": z.string(),
79
+ "refresh_token": z.string(),
80
+ "expires_in": z.number(),
81
+ "restricted": z.boolean(),
82
+ "user": z.object({
83
+ "id": z.number(),
84
+ "username": z.string(),
85
+ "display_name": z.string().nullable(),
86
+ "avatar_base64": z.string().nullable(),
87
+ "must_change": z.boolean(),
88
+ "roles": z.array(z.string())
89
+ })
11
90
  }),
12
91
  },
13
92
  "authWecomAdminAppsGet": {
@@ -24,6 +103,16 @@ export const schemas = {
24
103
  "installed_at": z.number(),
25
104
  "update_time": z.number()
26
105
  })),
106
+ },
107
+ "authWecomAdminOverviewGet": {
108
+ data: z.object({
109
+ "kinds": z.array(z.enum(["suite", "corp"])),
110
+ "configError": z.string().nullable(),
111
+ "callbackUrl": z.string().nullable(),
112
+ "corpId": z.string().nullable(),
113
+ "agentId": z.string().nullable(),
114
+ "corpCallbackConfigured": z.boolean()
115
+ }),
27
116
  },
28
117
  "authWecomAdminStatusPost": {
29
118
  body: z.object({
@@ -41,16 +130,6 @@ export const schemas = {
41
130
  "installUrl": z.string(),
42
131
  "callbackUrl": z.string(),
43
132
  "expiresIn": z.number()
44
- }),
45
- },
46
- "authWecomAdminOverviewGet": {
47
- data: z.object({
48
- "kinds": z.array(z.enum(["suite", "corp"])),
49
- "configError": z.string().nullable(),
50
- "callbackUrl": z.string().nullable(),
51
- "corpId": z.string().nullable(),
52
- "agentId": z.string().nullable(),
53
- "corpCallbackConfigured": z.boolean()
54
133
  }),
55
134
  },
56
135
  "authWecomAdminConnectPost": {
@@ -59,11 +138,48 @@ export const schemas = {
59
138
  "agentId": z.string(),
60
139
  "departments": z.number(),
61
140
  "members": z.number()
141
+ }),
142
+ },
143
+ "authWecomAdminTenantAdminGet": {
144
+ query: z.object({
145
+ "corpId": z.string().min(1)
146
+ }),
147
+ data: z.object({
148
+ "corpId": z.string(),
149
+ "username": z.string(),
150
+ "exists": z.boolean(),
151
+ "mustChange": z.boolean()
152
+ }),
153
+ },
154
+ "authWecomAdminTenantAdminPasswordPost": {
155
+ body: z.object({
156
+ "corpId": z.string().min(1),
157
+ "password": z.string().min(6)
158
+ }),
159
+ data: z.object({
160
+ "corpId": z.string(),
161
+ "username": z.string(),
162
+ "exists": z.boolean(),
163
+ "mustChange": z.boolean()
62
164
  }),
63
165
  },
64
166
  "authWecomTicketPost": {
65
167
  body: z.object({
66
168
  "ticket": z.string().min(32).max(128)
169
+ }),
170
+ data: z.object({
171
+ "access_token": z.string(),
172
+ "refresh_token": z.string(),
173
+ "expires_in": z.number(),
174
+ "restricted": z.boolean(),
175
+ "user": z.object({
176
+ "id": z.number(),
177
+ "username": z.string(),
178
+ "display_name": z.string().nullable(),
179
+ "avatar_base64": z.string().nullable(),
180
+ "must_change": z.boolean(),
181
+ "roles": z.array(z.string())
182
+ })
67
183
  }),
68
184
  },
69
185
  "authWecomSyncStartPost": {
@@ -74,6 +190,8 @@ export const schemas = {
74
190
  "connected": z.boolean(),
75
191
  "authMode": z.number(),
76
192
  "profileStatus": z.string().nullable(),
193
+ "agentId": z.string().nullable(),
194
+ "credentialKind": z.union([z.literal("suite"), z.literal("corp"), z.literal(null)]).nullable(),
77
195
  "status": z.enum(["idle", "running", "done", "failed", "cancelled"]),
78
196
  "phase": z.enum(["departments", "members", "reconcile"]),
79
197
  "stats": z.object({
@@ -106,6 +224,8 @@ export const schemas = {
106
224
  "connected": z.boolean(),
107
225
  "authMode": z.number(),
108
226
  "profileStatus": z.string().nullable(),
227
+ "agentId": z.string().nullable(),
228
+ "credentialKind": z.union([z.literal("suite"), z.literal("corp"), z.literal(null)]).nullable(),
109
229
  "status": z.enum(["idle", "running", "done", "failed", "cancelled"]),
110
230
  "phase": z.enum(["departments", "members", "reconcile"]),
111
231
  "stats": z.object({
@@ -127,9 +247,7 @@ export const schemas = {
127
247
  }).nullable(),
128
248
  "startedAt": z.number(),
129
249
  "finishedAt": z.number(),
130
- "updateTime": z.number(),
131
- "agentId": z.string().nullable(),
132
- "credentialKind": z.union([z.literal("suite"), z.literal("corp"), z.literal(null)]).nullable()
250
+ "updateTime": z.number()
133
251
  }),
134
252
  },
135
253
  "authWecomSyncCancelPost": {
@@ -140,6 +258,8 @@ export const schemas = {
140
258
  "connected": z.boolean(),
141
259
  "authMode": z.number(),
142
260
  "profileStatus": z.string().nullable(),
261
+ "agentId": z.string().nullable(),
262
+ "credentialKind": z.union([z.literal("suite"), z.literal("corp"), z.literal(null)]).nullable(),
143
263
  "status": z.enum(["idle", "running", "done", "failed", "cancelled"]),
144
264
  "phase": z.enum(["departments", "members", "reconcile"]),
145
265
  "stats": z.object({
@@ -17,6 +17,9 @@ export const API_PREFIX = "/auth";
17
17
  /** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
18
18
  export const MODULE_PREFIX = "/auth";
19
19
 
20
+ /** 认领方模块(web.config clientOwners 指定):跨模块认领护栏对比基准 */
21
+ export const MODULE_OWNER = "/app";
22
+
20
23
  /**
21
24
  * 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
22
25
  * scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
@@ -28,12 +31,12 @@ export function createAuthClient(ctx: ModuleContext) {
28
31
  // 单槽、卸载互相耦合;跨模块需求应由本模块创建后经 provider 暴露。
29
32
  // 注意对比基准是 MODULE_PREFIX(目录名)而非 API_PREFIX——D-M8 映射时线上前缀
30
33
  // 属于别的命名空间,认领身份仍按目录名。
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 暴露。`);
34
+ if (import.meta.env.DEV && ctx.module.name !== MODULE_OWNER.slice(1)) {
35
+ console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${MODULE_OWNER.slice(1)}" 模块在自身 onInit 创建,跨模块需求经 provider 暴露。`);
33
36
  }
34
37
  ctx.register.apiPrefix(API_PREFIX);
35
38
  bindRequest(ctx.utils.request);
36
- return { authLoginPost, authLogoutPost, authRefreshPost, authPasswordPut, authLdapLoginPost, authWecomAdminAppsGet, authWecomAdminStatusPost, authWecomAdminInstallGet, authWecomAdminOverviewGet, authWecomAdminConnectPost, authWecomLoginGet, authWecomCallbackGet, authWecomTicketPost, authWecomEventGet, authWecomEventPost, authWecomSyncStartPost, authWecomSyncStatusGet, authWecomSyncCancelPost };
39
+ return { authLoginPost, authLogoutPost, authRefreshPost, authPasswordPut, authLdapLoginPost, authWecomAdminAppsGet, authWecomAdminOverviewGet, authWecomAdminStatusPost, authWecomAdminInstallGet, authWecomAdminConnectPost, authWecomAdminTenantAdminGet, authWecomAdminTenantAdminPasswordPost, authWecomLoginGet, authWecomCallbackGet, authWecomTicketPost, authWecomEventGet, authWecomEventPost, authWecomSyncStartPost, authWecomSyncStatusGet, authWecomSyncCancelPost };
37
40
  }
38
41
 
39
42
  /**
@@ -64,14 +67,23 @@ async function toApiError(e: unknown): Promise<unknown> {
64
67
  return e;
65
68
  }
66
69
 
67
- export async function authLoginPost(): Promise<unknown> {
70
+ export type AuthLoginPostBody = z.input<(typeof schemas)["authLoginPost"]["body"]>;
71
+ export type AuthLoginPostData = z.infer<(typeof schemas)["authLoginPost"]["data"]>;
72
+
73
+ export async function authLoginPost(body: AuthLoginPostBody): Promise<AuthLoginPostData> {
68
74
  const client = ensureReq();
69
75
  try {
70
- const env = await client.post(`auth/login`).json<OjEnvelope<unknown>>();
76
+ const env = await client.post(`auth/login`, { json: body }).json<OjEnvelope<AuthLoginPostData>>();
71
77
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
72
78
  if (typeof env.code === "number" && env.code !== 0)
73
79
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
74
- const data = env.data as unknown;
80
+ const data = env.data as AuthLoginPostData;
81
+ if (import.meta.env.DEV) {
82
+ const { schemas } = await import("./api.schemas");
83
+ const r = schemas["authLoginPost"].data.safeParse(data);
84
+ if (!r.success)
85
+ throw new ContractApiError(-1, `[契约违例] authLoginPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
86
+ }
75
87
  return data;
76
88
  }
77
89
  catch (e) {
@@ -79,14 +91,23 @@ export async function authLoginPost(): Promise<unknown> {
79
91
  }
80
92
  }
81
93
 
82
- export async function authLogoutPost(): Promise<unknown> {
94
+ export type AuthLogoutPostBody = z.input<(typeof schemas)["authLogoutPost"]["body"]>;
95
+ export type AuthLogoutPostData = z.infer<(typeof schemas)["authLogoutPost"]["data"]>;
96
+
97
+ export async function authLogoutPost(body: AuthLogoutPostBody): Promise<AuthLogoutPostData> {
83
98
  const client = ensureReq();
84
99
  try {
85
- const env = await client.post(`auth/logout`).json<OjEnvelope<unknown>>();
100
+ const env = await client.post(`auth/logout`, { json: body }).json<OjEnvelope<AuthLogoutPostData>>();
86
101
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
87
102
  if (typeof env.code === "number" && env.code !== 0)
88
103
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
89
- const data = env.data as unknown;
104
+ const data = env.data as AuthLogoutPostData;
105
+ if (import.meta.env.DEV) {
106
+ const { schemas } = await import("./api.schemas");
107
+ const r = schemas["authLogoutPost"].data.safeParse(data);
108
+ if (!r.success)
109
+ throw new ContractApiError(-1, `[契约违例] authLogoutPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
110
+ }
90
111
  return data;
91
112
  }
92
113
  catch (e) {
@@ -94,14 +115,23 @@ export async function authLogoutPost(): Promise<unknown> {
94
115
  }
95
116
  }
96
117
 
97
- export async function authRefreshPost(): Promise<unknown> {
118
+ export type AuthRefreshPostBody = z.input<(typeof schemas)["authRefreshPost"]["body"]>;
119
+ export type AuthRefreshPostData = z.infer<(typeof schemas)["authRefreshPost"]["data"]>;
120
+
121
+ export async function authRefreshPost(body: AuthRefreshPostBody): Promise<AuthRefreshPostData> {
98
122
  const client = ensureReq();
99
123
  try {
100
- const env = await client.post(`auth/refresh`).json<OjEnvelope<unknown>>();
124
+ const env = await client.post(`auth/refresh`, { json: body }).json<OjEnvelope<AuthRefreshPostData>>();
101
125
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
102
126
  if (typeof env.code === "number" && env.code !== 0)
103
127
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
104
- const data = env.data as unknown;
128
+ const data = env.data as AuthRefreshPostData;
129
+ if (import.meta.env.DEV) {
130
+ const { schemas } = await import("./api.schemas");
131
+ const r = schemas["authRefreshPost"].data.safeParse(data);
132
+ if (!r.success)
133
+ throw new ContractApiError(-1, `[契约违例] authRefreshPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
134
+ }
105
135
  return data;
106
136
  }
107
137
  catch (e) {
@@ -110,15 +140,22 @@ export async function authRefreshPost(): Promise<unknown> {
110
140
  }
111
141
 
112
142
  export type AuthPasswordPutBody = z.input<(typeof schemas)["authPasswordPut"]["body"]>;
143
+ export type AuthPasswordPutData = z.infer<(typeof schemas)["authPasswordPut"]["data"]>;
113
144
 
114
- export async function authPasswordPut(body: AuthPasswordPutBody): Promise<unknown> {
145
+ export async function authPasswordPut(body: AuthPasswordPutBody): Promise<AuthPasswordPutData> {
115
146
  const client = ensureReq();
116
147
  try {
117
- const env = await client.put(`auth/password`, { json: body }).json<OjEnvelope<unknown>>();
148
+ const env = await client.put(`auth/password`, { json: body }).json<OjEnvelope<AuthPasswordPutData>>();
118
149
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
119
150
  if (typeof env.code === "number" && env.code !== 0)
120
151
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
121
- const data = env.data as unknown;
152
+ const data = env.data as AuthPasswordPutData;
153
+ if (import.meta.env.DEV) {
154
+ const { schemas } = await import("./api.schemas");
155
+ const r = schemas["authPasswordPut"].data.safeParse(data);
156
+ if (!r.success)
157
+ throw new ContractApiError(-1, `[契约违例] authPasswordPut 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
158
+ }
122
159
  return data;
123
160
  }
124
161
  catch (e) {
@@ -126,14 +163,23 @@ export async function authPasswordPut(body: AuthPasswordPutBody): Promise<unknow
126
163
  }
127
164
  }
128
165
 
129
- export async function authLdapLoginPost(): Promise<unknown> {
166
+ export type AuthLdapLoginPostBody = z.input<(typeof schemas)["authLdapLoginPost"]["body"]>;
167
+ export type AuthLdapLoginPostData = z.infer<(typeof schemas)["authLdapLoginPost"]["data"]>;
168
+
169
+ export async function authLdapLoginPost(body: AuthLdapLoginPostBody): Promise<AuthLdapLoginPostData> {
130
170
  const client = ensureReq();
131
171
  try {
132
- const env = await client.post(`auth/ldap-login`).json<OjEnvelope<unknown>>();
172
+ const env = await client.post(`auth/ldap-login`, { json: body }).json<OjEnvelope<AuthLdapLoginPostData>>();
133
173
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
134
174
  if (typeof env.code === "number" && env.code !== 0)
135
175
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
136
- const data = env.data as unknown;
176
+ const data = env.data as AuthLdapLoginPostData;
177
+ if (import.meta.env.DEV) {
178
+ const { schemas } = await import("./api.schemas");
179
+ const r = schemas["authLdapLoginPost"].data.safeParse(data);
180
+ if (!r.success)
181
+ throw new ContractApiError(-1, `[契约违例] authLdapLoginPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
182
+ }
137
183
  return data;
138
184
  }
139
185
  catch (e) {
@@ -164,6 +210,29 @@ export async function authWecomAdminAppsGet(): Promise<AuthWecomAdminAppsGetData
164
210
  }
165
211
  }
166
212
 
213
+ export type AuthWecomAdminOverviewGetData = z.infer<(typeof schemas)["authWecomAdminOverviewGet"]["data"]>;
214
+
215
+ export async function authWecomAdminOverviewGet(): Promise<AuthWecomAdminOverviewGetData> {
216
+ const client = ensureReq();
217
+ try {
218
+ const env = await client.get(`auth/wecom/admin/overview`).json<OjEnvelope<AuthWecomAdminOverviewGetData>>();
219
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
220
+ if (typeof env.code === "number" && env.code !== 0)
221
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
222
+ const data = env.data as AuthWecomAdminOverviewGetData;
223
+ if (import.meta.env.DEV) {
224
+ const { schemas } = await import("./api.schemas");
225
+ const r = schemas["authWecomAdminOverviewGet"].data.safeParse(data);
226
+ if (!r.success)
227
+ throw new ContractApiError(-1, `[契约违例] authWecomAdminOverviewGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
228
+ }
229
+ return data;
230
+ }
231
+ catch (e) {
232
+ throw await toApiError(e);
233
+ }
234
+ }
235
+
167
236
  export type AuthWecomAdminStatusPostBody = z.input<(typeof schemas)["authWecomAdminStatusPost"]["body"]>;
168
237
  export type AuthWecomAdminStatusPostData = z.infer<(typeof schemas)["authWecomAdminStatusPost"]["data"]>;
169
238
 
@@ -211,21 +280,21 @@ export async function authWecomAdminInstallGet(): Promise<AuthWecomAdminInstallG
211
280
  }
212
281
  }
213
282
 
214
- export type AuthWecomAdminOverviewGetData = z.infer<(typeof schemas)["authWecomAdminOverviewGet"]["data"]>;
283
+ export type AuthWecomAdminConnectPostData = z.infer<(typeof schemas)["authWecomAdminConnectPost"]["data"]>;
215
284
 
216
- export async function authWecomAdminOverviewGet(): Promise<AuthWecomAdminOverviewGetData> {
285
+ export async function authWecomAdminConnectPost(): Promise<AuthWecomAdminConnectPostData> {
217
286
  const client = ensureReq();
218
287
  try {
219
- const env = await client.get(`auth/wecom/admin/overview`).json<OjEnvelope<AuthWecomAdminOverviewGetData>>();
288
+ const env = await client.post(`auth/wecom/admin/connect`).json<OjEnvelope<AuthWecomAdminConnectPostData>>();
220
289
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
221
290
  if (typeof env.code === "number" && env.code !== 0)
222
291
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
223
- const data = env.data as AuthWecomAdminOverviewGetData;
292
+ const data = env.data as AuthWecomAdminConnectPostData;
224
293
  if (import.meta.env.DEV) {
225
294
  const { schemas } = await import("./api.schemas");
226
- const r = schemas["authWecomAdminOverviewGet"].data.safeParse(data);
295
+ const r = schemas["authWecomAdminConnectPost"].data.safeParse(data);
227
296
  if (!r.success)
228
- throw new ContractApiError(-1, `[契约违例] authWecomAdminOverviewGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
297
+ throw new ContractApiError(-1, `[契约违例] authWecomAdminConnectPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
229
298
  }
230
299
  return data;
231
300
  }
@@ -234,21 +303,46 @@ export async function authWecomAdminOverviewGet(): Promise<AuthWecomAdminOvervie
234
303
  }
235
304
  }
236
305
 
237
- export type AuthWecomAdminConnectPostData = z.infer<(typeof schemas)["authWecomAdminConnectPost"]["data"]>;
306
+ export type AuthWecomAdminTenantAdminGetQuery = z.input<(typeof schemas)["authWecomAdminTenantAdminGet"]["query"]>;
307
+ export type AuthWecomAdminTenantAdminGetData = z.infer<(typeof schemas)["authWecomAdminTenantAdminGet"]["data"]>;
238
308
 
239
- export async function authWecomAdminConnectPost(): Promise<AuthWecomAdminConnectPostData> {
309
+ export async function authWecomAdminTenantAdminGet(query: AuthWecomAdminTenantAdminGetQuery): Promise<AuthWecomAdminTenantAdminGetData> {
240
310
  const client = ensureReq();
241
311
  try {
242
- const env = await client.post(`auth/wecom/admin/connect`).json<OjEnvelope<AuthWecomAdminConnectPostData>>();
312
+ const env = await client.get(`auth/wecom/admin/tenant-admin`, { searchParams: query as Record<string, string | number | boolean> }).json<OjEnvelope<AuthWecomAdminTenantAdminGetData>>();
243
313
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
244
314
  if (typeof env.code === "number" && env.code !== 0)
245
315
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
246
- const data = env.data as AuthWecomAdminConnectPostData;
316
+ const data = env.data as AuthWecomAdminTenantAdminGetData;
247
317
  if (import.meta.env.DEV) {
248
318
  const { schemas } = await import("./api.schemas");
249
- const r = schemas["authWecomAdminConnectPost"].data.safeParse(data);
319
+ const r = schemas["authWecomAdminTenantAdminGet"].data.safeParse(data);
250
320
  if (!r.success)
251
- throw new ContractApiError(-1, `[契约违例] authWecomAdminConnectPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
321
+ throw new ContractApiError(-1, `[契约违例] authWecomAdminTenantAdminGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
322
+ }
323
+ return data;
324
+ }
325
+ catch (e) {
326
+ throw await toApiError(e);
327
+ }
328
+ }
329
+
330
+ export type AuthWecomAdminTenantAdminPasswordPostBody = z.input<(typeof schemas)["authWecomAdminTenantAdminPasswordPost"]["body"]>;
331
+ export type AuthWecomAdminTenantAdminPasswordPostData = z.infer<(typeof schemas)["authWecomAdminTenantAdminPasswordPost"]["data"]>;
332
+
333
+ export async function authWecomAdminTenantAdminPasswordPost(body: AuthWecomAdminTenantAdminPasswordPostBody): Promise<AuthWecomAdminTenantAdminPasswordPostData> {
334
+ const client = ensureReq();
335
+ try {
336
+ const env = await client.post(`auth/wecom/admin/tenant-admin/password`, { json: body }).json<OjEnvelope<AuthWecomAdminTenantAdminPasswordPostData>>();
337
+ // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
338
+ if (typeof env.code === "number" && env.code !== 0)
339
+ throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
340
+ const data = env.data as AuthWecomAdminTenantAdminPasswordPostData;
341
+ if (import.meta.env.DEV) {
342
+ const { schemas } = await import("./api.schemas");
343
+ const r = schemas["authWecomAdminTenantAdminPasswordPost"].data.safeParse(data);
344
+ if (!r.success)
345
+ throw new ContractApiError(-1, `[契约违例] authWecomAdminTenantAdminPasswordPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
252
346
  }
253
347
  return data;
254
348
  }
@@ -288,15 +382,22 @@ export async function authWecomCallbackGet(): Promise<unknown> {
288
382
  }
289
383
 
290
384
  export type AuthWecomTicketPostBody = z.input<(typeof schemas)["authWecomTicketPost"]["body"]>;
385
+ export type AuthWecomTicketPostData = z.infer<(typeof schemas)["authWecomTicketPost"]["data"]>;
291
386
 
292
- export async function authWecomTicketPost(body: AuthWecomTicketPostBody): Promise<unknown> {
387
+ export async function authWecomTicketPost(body: AuthWecomTicketPostBody): Promise<AuthWecomTicketPostData> {
293
388
  const client = ensureReq();
294
389
  try {
295
- const env = await client.post(`auth/wecom/ticket`, { json: body }).json<OjEnvelope<unknown>>();
390
+ const env = await client.post(`auth/wecom/ticket`, { json: body }).json<OjEnvelope<AuthWecomTicketPostData>>();
296
391
  // 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
297
392
  if (typeof env.code === "number" && env.code !== 0)
298
393
  throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
299
- const data = env.data as unknown;
394
+ const data = env.data as AuthWecomTicketPostData;
395
+ if (import.meta.env.DEV) {
396
+ const { schemas } = await import("./api.schemas");
397
+ const r = schemas["authWecomTicketPost"].data.safeParse(data);
398
+ if (!r.success)
399
+ throw new ContractApiError(-1, `[契约违例] authWecomTicketPost 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
400
+ }
300
401
  return data;
301
402
  }
302
403
  catch (e) {
@@ -0,0 +1,77 @@
1
+ import type { ModuleContext, ModuleI18n } from "@oj-module/runtime";
2
+ import { defineModule } from "@oj-module/runtime";
3
+
4
+ import { routes as homeRoutes } from "./home/routes";
5
+ import { onInit as loginOnInit, routes as loginRoutes } from "./login/routes";
6
+ import { onInit as notificationOnInit, routes as notificationRoutes } from "./notification/routes";
7
+ import { onInit as personalCenterOnInit, routes as personalCenterRoutes } from "./personal-center/routes";
8
+ import { onInit as systemOnInit, routes as systemRoutes } from "./system/routes";
9
+
10
+ /**
11
+ * 应用模块(多根聚合):一个 entry 承载六个业务根,各根独立成一级菜单。
12
+ *
13
+ * 为什么聚合:这六个根(首页/登录/个人中心/通知/系统管理)是脚手架的框架内置页面,
14
+ * 同版本发布、同生命周期、缺一不可,拆成六个模块只会把工程目录、web.config 登记、
15
+ * modules.json 与首屏模块入口请求都放大六倍。聚合后仍是「一目录一模块」,但模块内
16
+ * 按根分目录(`<root>/routes.ts` + `pages/` + `__client/`),页面相对导入不变。
17
+ *
18
+ * 结构约定(多根模块):
19
+ * - 顶层路由首段去重 > 1 → runtime 判为多根(`isMultiRoot`),各根按 entry 里的
20
+ * **绝对路径**原样注册,不被 `routePrefix` 改写——URL 与菜单 key 都不变;
21
+ * - 菜单顺序仍由各根 `handle.order` 决定(≥0 主区升序、<0 底部固定区),与聚合前
22
+ * 逐项一致;改顺序只改 order,不要依赖 routes 数组下标(缺省 order 会按数组下标兜底);
23
+ * - 门禁挂根路由:`/system` 的 `handle.roles` 等价于原先的模块级 requiredRoles。
24
+ *
25
+ * i18n 用 `i18nNamespaces` 沿用各根**原命名空间**(home / login / personal-center /
26
+ * notification / system),因此 `t("system:menu.users")`、`useTranslation("system")`
27
+ * 与菜单标题 `<ns>:menu.<key>` 全部零改动。
28
+ */
29
+ const i18nNamespaces: Record<string, ModuleI18n> = {
30
+ "home": {
31
+ "zh-CN": () => import("./home/locales/zh-CN.json"),
32
+ "en-US": () => import("./home/locales/en-US.json"),
33
+ },
34
+ "login": {
35
+ "zh-CN": () => import("./login/locales/zh-CN.json"),
36
+ "en-US": () => import("./login/locales/en-US.json"),
37
+ },
38
+ "personal-center": {
39
+ "zh-CN": () => import("./personal-center/locales/zh-CN.json"),
40
+ "en-US": () => import("./personal-center/locales/en-US.json"),
41
+ },
42
+ "notification": {
43
+ "zh-CN": () => import("./notification/locales/zh-CN.json"),
44
+ "en-US": () => import("./notification/locales/en-US.json"),
45
+ },
46
+ "system": {
47
+ "zh-CN": () => import("./system/locales/zh-CN.json"),
48
+ "en-US": () => import("./system/locales/en-US.json"),
49
+ },
50
+ };
51
+
52
+ export default defineModule({
53
+ name: "app",
54
+ description: "应用模块:框架内置页面(首页/登录/个人中心/通知/系统管理),多根聚合",
55
+ version: "0.1.0",
56
+ peerRuntime: ">=0.0.0",
57
+ routes: [
58
+ ...homeRoutes,
59
+ ...loginRoutes,
60
+ ...personalCenterRoutes,
61
+ ...notificationRoutes,
62
+ ...systemRoutes,
63
+ ],
64
+ i18nNamespaces,
65
+ lifecycle: {
66
+ /**
67
+ * 各根的 onInit 按原模块加载顺序串行——login 必须最先(认证 provider 要在任何
68
+ * 登录动作前就位),其余是前缀登记/API provider 注入,顺序无相互依赖。
69
+ */
70
+ async onInit(ctx: ModuleContext) {
71
+ await loginOnInit(ctx);
72
+ await personalCenterOnInit(ctx);
73
+ await notificationOnInit(ctx);
74
+ await systemOnInit(ctx);
75
+ },
76
+ },
77
+ });
@@ -17,6 +17,9 @@ export const API_PREFIX = "/home";
17
17
  /** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
18
18
  export const MODULE_PREFIX = "/home";
19
19
 
20
+ /** 认领方模块(web.config clientOwners 指定):跨模块认领护栏对比基准 */
21
+ export const MODULE_OWNER = "/app";
22
+
20
23
  /**
21
24
  * 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
22
25
  * scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
@@ -28,8 +31,8 @@ export function createHomeClient(ctx: ModuleContext) {
28
31
  // 单槽、卸载互相耦合;跨模块需求应由本模块创建后经 provider 暴露。
29
32
  // 注意对比基准是 MODULE_PREFIX(目录名)而非 API_PREFIX——D-M8 映射时线上前缀
30
33
  // 属于别的命名空间,认领身份仍按目录名。
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 暴露。`);
34
+ if (import.meta.env.DEV && ctx.module.name !== MODULE_OWNER.slice(1)) {
35
+ console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${MODULE_OWNER.slice(1)}" 模块在自身 onInit 创建,跨模块需求经 provider 暴露。`);
33
36
  }
34
37
  ctx.register.apiPrefix(API_PREFIX);
35
38
  bindRequest(ctx.utils.request);
@@ -0,0 +1,41 @@
1
+ import type { AppRouteRecordRaw } from "@oj-module/runtime";
2
+
3
+ import { HomeOutlined } from "@ant-design/icons";
4
+
5
+ import { createElement, lazy } from "react";
6
+
7
+ const Home = lazy(() => import("./pages/index"));
8
+
9
+ /**
10
+ * 首页根 `/home`。
11
+ *
12
+ * 为什么必须有:shell 预构建产物把 `VITE_BASE_HOME_PATH` 定为 `/home`
13
+ * (登录成功回跳、logo 点击、tabbar 首页、403/404 回首页都指向它)。
14
+ * 工程缺 `/home` 路由时这些跳转会落到错误边界。
15
+ *
16
+ * 结构对齐 playground-oj/web/src/home;页面用统计卡片 + 折线/柱/饼图
17
+ * 演示宿主共享依赖矩阵(echarts / echarts-for-react / react-countup / dayjs /
18
+ * antd / @ant-design/icons / react-i18next,均由宿主 importmap 提供单例)。
19
+ * 图表数据为静态演示值——真实业务走模块契约 + `ojm api` 生成的 client。
20
+ */
21
+ export const routes: AppRouteRecordRaw[] = [
22
+ {
23
+ path: "/home",
24
+ handle: {
25
+ layout: "container",
26
+ order: 1,
27
+ title: "home:menu.home",
28
+ icon: createElement(HomeOutlined),
29
+ },
30
+ children: [
31
+ {
32
+ index: true,
33
+ Component: Home,
34
+ handle: {
35
+ title: "home:menu.home",
36
+ icon: createElement(HomeOutlined),
37
+ },
38
+ },
39
+ ],
40
+ },
41
+ ];