@oj-module/cli 0.2.54 → 0.2.57

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 (307) hide show
  1. package/devkit/README.md +7 -4
  2. package/devkit/SKILL.md +7 -4
  3. package/devkit/manual.md +63 -54
  4. package/devkit/module-dev-and-cdn-playground.md +7 -0
  5. package/devkit/publish-walkthrough.md +199 -0
  6. package/package.json +2 -2
  7. package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
  8. package/shell-dist/assets/runtime.js +5 -5
  9. package/shell-dist/index.html +3 -3
  10. package/shell-dist/versions.json +3 -3
  11. package/src/__tests__/layout.test.ts +30 -1
  12. package/src/__tests__/templates-schema-columns.test.ts +99 -0
  13. package/src/__tests__/vendor-devkit.test.ts +87 -0
  14. package/src/alias-paths.ts +11 -12
  15. package/src/build/backend.ts +131 -0
  16. package/src/build/module-build.ts +364 -0
  17. package/src/build/module-def.ts +381 -0
  18. package/src/build/site-merge.ts +33 -0
  19. package/src/build.ts +16 -885
  20. package/src/builtin.ts +10 -3
  21. package/src/bundle.ts +61 -0
  22. package/src/cli.ts +4 -1
  23. package/src/contract/__tests__/emit-client.test.ts +4 -4
  24. package/src/contract/__tests__/market-client.integration.test.ts +2 -2
  25. package/src/contract/__tests__/run-api.test.ts +2 -2
  26. package/src/contract/check.ts +6 -2
  27. package/src/contract/emit-client.ts +10 -3
  28. package/src/contract/run.ts +10 -2
  29. package/src/init.ts +31 -46
  30. package/src/layout.ts +72 -16
  31. package/src/lifecycle/__tests__/bundle-summary.test.ts +106 -0
  32. package/src/lifecycle/__tests__/bundle.test.ts +6 -0
  33. package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
  34. package/src/market/__tests__/bootstrap.test.ts +1 -1
  35. package/src/site.ts +1 -1
  36. package/src/vendor.ts +34 -0
  37. package/templates/README.md +30 -20
  38. package/templates/init.include.yaml +19 -11
  39. package/templates/openapi.json +102 -86
  40. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/installer.ts +8 -3
  41. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/register.ts +53 -0
  42. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/roles.ts +4 -1
  43. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/solution-perms.ts +7 -3
  44. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/users.ts +27 -0
  45. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/oplog.ts +4 -2
  46. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +7 -0
  47. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +4 -0
  48. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +8 -0
  49. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +3 -0
  50. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +3 -0
  51. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +8 -0
  52. package/templates/src/{_platform/api → app/api/_platform}/schema.yaml +7 -0
  53. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/replay.ts +9 -3
  54. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/tenant-admin.ts +18 -27
  55. package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
  56. package/templates/src/{system/api → app/api/system}/roles/api.ts +2 -1
  57. package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +5 -2
  58. package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +5 -2
  59. package/templates/src/app/web/notification/pages/center/index.tsx +1 -1
  60. package/templates/src/app/web/notification/routes.ts +1 -1
  61. package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +1 -1
  62. package/templates/src/app/web/personal-center/routes.ts +1 -1
  63. package/templates/src/app/web/system/__client/api.schemas.ts +2 -0
  64. package/templates/src/app/web/system/locales/en-US.json +2 -3
  65. package/templates/src/app/web/system/locales/zh-CN.json +2 -3
  66. package/templates/src/app/web/system/pages/departments/index.tsx +2 -2
  67. package/templates/src/app/web/system/pages/login-methods/index.tsx +1 -1
  68. package/templates/src/app/web/system/pages/oplog/index.tsx +44 -19
  69. package/templates/src/app/web/system/pages/roles/index.tsx +12 -4
  70. package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
  71. package/templates/src/app/web/system/pages/settings/index.tsx +2 -2
  72. package/templates/src/app/web/system/pages/users/can-manage.ts +21 -0
  73. package/templates/src/app/web/system/pages/users/index.tsx +25 -17
  74. package/templates/src/app/web/system/pages/users/roles.tsx +1 -1
  75. package/templates/src/app/web/system/routes.ts +1 -1
  76. package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +5 -2
  77. package/templates/src/oj-market/web/api/defaultClient.ts +1 -1
  78. package/templates/tests/auth-ldap.spec.ts +2 -2
  79. package/templates/tests/auth-session.spec.ts +3 -3
  80. package/templates/tests/auth-throttle.spec.ts +1 -1
  81. package/templates/tests/fixture.ts +6 -4
  82. package/templates/tests/guard.spec.ts +1 -1
  83. package/templates/tests/lifecycle/atomic-state.spec.ts +3 -3
  84. package/templates/tests/lifecycle/bootstrap.spec.ts +3 -3
  85. package/templates/tests/lifecycle/deploy-smoke.spec.ts +8 -8
  86. package/templates/tests/lifecycle/installer.spec.ts +10 -10
  87. package/templates/tests/lifecycle/market-api.spec.ts +14 -14
  88. package/templates/tests/lifecycle/migrate.spec.ts +6 -6
  89. package/templates/tests/lifecycle/preflight.spec.ts +3 -3
  90. package/templates/tests/lifecycle/register.spec.ts +1 -1
  91. package/templates/tests/lifecycle/role-title-translate.spec.ts +171 -0
  92. package/templates/tests/lifecycle/semver.spec.ts +1 -1
  93. package/templates/tests/lifecycle/sha384.spec.ts +1 -1
  94. package/templates/tests/lifecycle/solutions-api.spec.ts +1 -1
  95. package/templates/tests/lifecycle/source-seq.spec.ts +1 -1
  96. package/templates/tests/lifecycle/steps-fs.spec.ts +9 -9
  97. package/templates/tests/lifecycle/text-edit.spec.ts +1 -1
  98. package/templates/tests/lifecycle/tgz-guard.spec.ts +2 -2
  99. package/templates/tests/lifecycle/trust.spec.ts +5 -5
  100. package/templates/tests/lifecycle/uninstall.spec.ts +7 -7
  101. package/templates/tests/lifecycle/verify-checks.spec.ts +5 -5
  102. package/templates/tests/lifecycle/verify-report.spec.ts +4 -4
  103. package/templates/tests/org-departments.spec.ts +10 -6
  104. package/templates/tests/org-read.spec.ts +7 -7
  105. package/templates/tests/query-utils.spec.ts +1 -1
  106. package/templates/tests/rbac-audit.spec.ts +1 -1
  107. package/templates/tests/rbac-contacts.spec.ts +2 -2
  108. package/templates/tests/rbac-guard.spec.ts +1 -1
  109. package/templates/tests/rbac-roles.spec.ts +19 -2
  110. package/templates/tests/rbac-seed.spec.ts +1 -1
  111. package/templates/tests/rbac-settings.spec.ts +77 -7
  112. package/templates/tests/rbac-solution-perms.spec.ts +1 -1
  113. package/templates/tests/rbac-tables.spec.ts +29 -0
  114. package/templates/tests/rbac-users.spec.ts +55 -3
  115. package/templates/tests/roles-page.spec.ts +40 -0
  116. package/templates/tests/seed-role-accounts.spec.ts +1 -1
  117. package/templates/tests/tenant-access-cache.spec.ts +1 -1
  118. package/templates/tests/tenant-forgery.spec.ts +5 -5
  119. package/templates/tests/tenant-isolation.spec.ts +5 -4
  120. package/templates/tests/username-namespace.spec.ts +3 -3
  121. package/templates/tests/users-page.spec.ts +39 -0
  122. package/templates/tests/wecom-admin.spec.ts +6 -6
  123. package/templates/tests/wecom-client-timeout.spec.ts +1 -1
  124. package/templates/tests/wecom-connector.spec.ts +9 -9
  125. package/templates/tests/wecom-corp.spec.ts +9 -9
  126. package/templates/tests/wecom-crypt.spec.ts +1 -1
  127. package/templates/tests/wecom-endpoints.spec.ts +2 -2
  128. package/templates/tests/wecom-landing.spec.ts +1 -1
  129. package/templates/tests/wecom-org-sync.spec.ts +7 -7
  130. package/templates/tests/wecom-sync.spec.ts +3 -3
  131. package/templates/tsconfig.paths.json +11 -11
  132. package/templates/vitest.config.ts +2 -2
  133. package/templates/web.config.ts +5 -2
  134. package/vendor/host-versions.json +3 -3
  135. package/templates/src/{_platform/api → app/api/_platform}/README.md +0 -0
  136. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/atomic.ts +0 -0
  137. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/history.ts +0 -0
  138. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/limits.ts +0 -0
  139. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/lock.ts +0 -0
  140. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/semver.ts +0 -0
  141. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/sha384.ts +0 -0
  142. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/source-seq.ts +0 -0
  143. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/state.ts +0 -0
  144. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/deploy-web.ts +0 -0
  145. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/download.ts +0 -0
  146. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/extract.ts +0 -0
  147. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/migrate.ts +0 -0
  148. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/preflight.ts +0 -0
  149. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/reload.ts +0 -0
  150. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/smoke.ts +0 -0
  151. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/verify.ts +0 -0
  152. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tasks.ts +0 -0
  153. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/text-edit.ts +0 -0
  154. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tgz-guard.ts +0 -0
  155. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/trust.ts +0 -0
  156. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/types.ts +0 -0
  157. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/uninstall.ts +0 -0
  158. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-checks.ts +0 -0
  159. package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-report.ts +0 -0
  160. package/templates/src/{_platform/api → app/api/_platform}/_shared/respond.ts +0 -0
  161. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/contacts.ts +0 -0
  162. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org-read.ts +0 -0
  163. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org.ts +0 -0
  164. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/settings.ts +0 -0
  165. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/access.ts +0 -0
  166. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/audit.ts +0 -0
  167. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/guard.ts +0 -0
  168. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/query.ts +0 -0
  169. package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/rate.ts +0 -0
  170. package/templates/src/{_platform/api → app/api/_platform}/_shared/site-facade.ts +0 -0
  171. package/templates/src/{_platform/api → app/api/_platform}/contacts/api.ts +0 -0
  172. package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +0 -0
  173. package/templates/src/{_platform/api → app/api/_platform}/fixtures/l1-test-user.sql +0 -0
  174. package/templates/src/{_platform/api → app/api/_platform}/manifest.yaml +0 -0
  175. package/templates/src/{_platform/api → app/api/_platform}/market/api.ts +0 -0
  176. package/templates/src/{_platform/api → app/api/_platform}/market/bootstrap.ts +0 -0
  177. package/templates/src/{_platform/api → app/api/_platform}/market/index-source.ts +0 -0
  178. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.mysql.sql +0 -0
  179. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.pg.sql +0 -0
  180. package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.sql +0 -0
  181. package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
  182. package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.sql +0 -0
  183. package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.mysql.sql +0 -0
  184. package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.sql +0 -0
  185. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.mysql.sql +0 -0
  186. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.pg.sql +0 -0
  187. package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.sql +0 -0
  188. package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.mysql.sql +0 -0
  189. package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.sql +0 -0
  190. package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
  191. package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.sql +0 -0
  192. package/templates/src/{_platform/api → app/api/_platform}/migrations/0007__users_email.sql +0 -0
  193. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
  194. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.pg.sql +0 -0
  195. package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.sql +0 -0
  196. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.mysql.sql +0 -0
  197. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.pg.sql +0 -0
  198. package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.sql +0 -0
  199. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.mysql.sql +0 -0
  200. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.pg.sql +0 -0
  201. package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.sql +0 -0
  202. package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
  203. package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.sql +0 -0
  204. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.mysql.sql +0 -0
  205. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.pg.sql +0 -0
  206. package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.sql +0 -0
  207. package/templates/src/{_platform/api → app/api/_platform}/migrations/0013__users_profile.sql +0 -0
  208. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.mysql.sql +0 -0
  209. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.pg.sql +0 -0
  210. package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.sql +0 -0
  211. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.mysql.sql +0 -0
  212. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.pg.sql +0 -0
  213. package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.sql +0 -0
  214. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.mysql.sql +0 -0
  215. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.pg.sql +0 -0
  216. package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.sql +0 -0
  217. package/templates/src/{_platform/api → app/api/_platform}/org/departments/api.ts +0 -0
  218. package/templates/src/{_platform/api → app/api/_platform}/org/is-member/api.ts +0 -0
  219. package/templates/src/{_platform/api → app/api/_platform}/org/members/api.ts +0 -0
  220. package/templates/src/{_platform/api → app/api/_platform}/org/picker/api.ts +0 -0
  221. package/templates/src/{_platform/api → app/api/_platform}/org/resolve/api.ts +0 -0
  222. package/templates/src/{_platform/api → app/api/_platform}/org/tree/api.ts +0 -0
  223. package/templates/src/{_platform/api → app/api/_platform}/org/user/api.ts +0 -0
  224. package/templates/src/{_platform/api → app/api/_platform}/seed.mysql.sql +0 -0
  225. package/templates/src/{_platform/api → app/api/_platform}/seed.pg.sql +0 -0
  226. package/templates/src/{_platform/api → app/api/_platform}/seed.sql +0 -0
  227. package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +0 -0
  228. package/templates/src/{auth/api → app/api/auth}/_shared/ldap-login.ts +0 -0
  229. package/templates/src/{auth/api → app/api/auth}/_shared/ldap.ts +0 -0
  230. package/templates/src/{auth/api → app/api/auth}/_shared/login-throttle.ts +0 -0
  231. package/templates/src/{auth/api → app/api/auth}/_shared/session.ts +0 -0
  232. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/admin.ts +1 -1
  233. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/client.ts +0 -0
  234. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/config.ts +0 -0
  235. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/contacts.ts +0 -0
  236. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/crypt.ts +0 -0
  237. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/events.ts +1 -1
  238. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/login.ts +0 -0
  239. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/payload.ts +0 -0
  240. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/store.ts +0 -0
  241. package/templates/src/{auth/api → app/api/auth}/_shared/wecom/sync.ts +0 -0
  242. package/templates/src/{auth/api → app/api/auth}/api.ts +0 -0
  243. package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +0 -0
  244. package/templates/src/{auth/api → app/api/auth}/manifest.yaml +0 -0
  245. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.mysql.sql +0 -0
  246. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.pg.sql +0 -0
  247. package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.sql +0 -0
  248. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.mysql.sql +0 -0
  249. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.pg.sql +0 -0
  250. package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.sql +0 -0
  251. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.mysql.sql +0 -0
  252. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.pg.sql +0 -0
  253. package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.sql +0 -0
  254. package/templates/src/{auth/api → app/api/auth}/schema.yaml +0 -0
  255. package/templates/src/{auth/api → app/api/auth}/wecom/admin/api.ts +0 -0
  256. package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/api.ts +1 -1
  257. package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/password/api.ts +1 -1
  258. /package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +0 -0
  259. /package/templates/src/{auth/api → app/api/auth}/wecom/sync/api.ts +0 -0
  260. /package/templates/src/{home/api → app/api/home}/line/api.ts +0 -0
  261. /package/templates/src/{home/api → app/api/home}/manifest.yaml +0 -0
  262. /package/templates/src/{home/api → app/api/home}/migrations/0001__create_home_tables.sql +0 -0
  263. /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.mysql.sql +0 -0
  264. /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.sql +0 -0
  265. /package/templates/src/{home/api → app/api/home}/pie/api.ts +0 -0
  266. /package/templates/src/{home/api → app/api/home}/schema.yaml +0 -0
  267. /package/templates/src/{home/api → app/api/home}/seed.sql +0 -0
  268. /package/templates/src/{notification/api → app/api/notification}/_shared/notify.ts +0 -0
  269. /package/templates/src/{notification/api → app/api/notification}/api.ts +0 -0
  270. /package/templates/src/{notification/api → app/api/notification}/del/api.ts +0 -0
  271. /package/templates/src/{notification/api → app/api/notification}/manifest.yaml +0 -0
  272. /package/templates/src/{notification/api → app/api/notification}/migrations/0001__create_notifications.sql +0 -0
  273. /package/templates/src/{notification/api → app/api/notification}/migrations/0002__notifications_user.sql +0 -0
  274. /package/templates/src/{notification/api → app/api/notification}/migrations/0003__notifications_broadcast.sql +0 -0
  275. /package/templates/src/{notification/api → app/api/notification}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
  276. /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.mysql.sql +0 -0
  277. /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.sql +0 -0
  278. /package/templates/src/{notification/api → app/api/notification}/schema.yaml +0 -0
  279. /package/templates/src/{notification/api → app/api/notification}/seed.sql +0 -0
  280. /package/templates/src/{personal-center/api → app/api/personal-center}/manifest.yaml +0 -0
  281. /package/templates/src/{personal-center/api → app/api/personal-center}/profile/api.ts +0 -0
  282. /package/templates/src/{personal-center/api → app/api/personal-center}/upload/api.ts +0 -0
  283. /package/templates/src/{system/api → app/api/system}/departments/api.ts +0 -0
  284. /package/templates/src/{system/api → app/api/system}/departments/detach/api.ts +0 -0
  285. /package/templates/src/{system/api → app/api/system}/departments/members/api.ts +0 -0
  286. /package/templates/src/{system/api → app/api/system}/departments/move/api.ts +0 -0
  287. /package/templates/src/{system/api → app/api/system}/login-methods/api.ts +0 -0
  288. /package/templates/src/{system/api → app/api/system}/manifest.yaml +0 -0
  289. /package/templates/src/{system/api → app/api/system}/permissions/api.ts +0 -0
  290. /package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +0 -0
  291. /package/templates/src/{system/api → app/api/system}/settings/api.ts +0 -0
  292. /package/templates/src/{system/api → app/api/system}/users/api.ts +0 -0
  293. /package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +0 -0
  294. /package/templates/src/{system/api → app/api/system}/users/password/api.ts +0 -0
  295. /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
  296. /package/templates/src/{system/api → app/api/system}/users/roles/api.ts +0 -0
  297. /package/templates/src/{web/api → app/api/web}/get-async-routes/api.ts +0 -0
  298. /package/templates/src/{web/api → app/api/web}/hello/api.ts +0 -0
  299. /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
  300. /package/templates/src/{web/api → app/api/web}/user-info/api.ts +0 -0
  301. /package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +0 -0
  302. /package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +0 -0
  303. /package/templates/src/app/web/home/__client/{api.ts → index.ts} +0 -0
  304. /package/templates/src/app/web/notification/__client/{api.ts → index.ts} +0 -0
  305. /package/templates/src/app/web/personal-center/__client/{api.ts → index.ts} +0 -0
  306. /package/templates/src/app/web/system/__client/{api.ts → index.ts} +0 -0
  307. /package/templates/src/{web → app/web}/web/__client/api.schemas.ts +0 -0
@@ -0,0 +1,364 @@
1
+ // 前端模块构建(SRP 拆分自 build.ts,2026-11-03,计划 docs/plans/20261103-0930):
2
+ // 逐模块 vite/rolldown 构建 → 产物完整性(sha384 chunks、importmap 说明符校验、
3
+ // CJS require 门禁)→ modules.json 清单。元数据读取见 module-def.ts,
4
+ // 后端编排见 backend.ts。
5
+ import type { Plugin } from "vite";
6
+ import type { ProjectLayout } from "../layout";
7
+ import crypto from "node:crypto";
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import tailwindcss from "@tailwindcss/vite";
11
+ import { build } from "vite";
12
+ import { parse as parseYaml } from "yaml";
13
+ import { assertModuleList, loadSiteConfig, mergeModuleList, resolveModuleEntry } from "../config";
14
+ import { moduleDir, resolveLayout, scanModules } from "../layout";
15
+ import { isPrebuiltDep, isSharedDep, SHARED_DEPS } from "../shared-deps";
16
+ import { checkSharedVersions, resolveShellDist } from "../versions";
17
+ import { readModuleDefinition } from "./module-def";
18
+ import { mergeShellSite } from "./site-merge";
19
+
20
+ /** modules.json 中的 chunk 条目 */
21
+ export interface ChunkEntry {
22
+ url: string
23
+ integrity: string
24
+ /** 懒加载 chunk:L2 完整性档位下不受保护(设计文档 §4.7) */
25
+ lazy: boolean
26
+ }
27
+
28
+ /** modules.json 中的模块条目 */
29
+ export interface BuiltModule {
30
+ name: string
31
+ version: string
32
+ enabled: boolean
33
+ dependencies: string[]
34
+ peerRuntime?: string
35
+ entry: string
36
+ integrity: string
37
+ css: string[]
38
+ chunks: ChunkEntry[]
39
+ /**
40
+ * 生效的 web 路由前缀段(契约 C2-14:`web.route_prefix` 缺省 `/<name>`)。
41
+ * 运行期据其改写模块路由根(单根约定下仅根段),缺省 = name 保证零漂移。
42
+ */
43
+ routePrefix: string
44
+ }
45
+
46
+ /**
47
+ * 解析模块生效的 web 路由前缀段(R1.1)。
48
+ * module-root:读 `src/<name>/solution.yaml` 的 `web.route_prefix`(契约 C2-14,缺省 `/<name>`);
49
+ * 未配置/非法/非 module-root → 缺省 `name`,与现有路由根(顶层段即 name)逐字节一致。
50
+ */
51
+ function resolveRoutePrefix(layout: ProjectLayout, name: string): string {
52
+ if (layout.kind !== "module-root")
53
+ return name;
54
+ const solPath = path.join(moduleDir(layout, name), "solution.yaml");
55
+ if (!fs.existsSync(solPath))
56
+ return name;
57
+ try {
58
+ const doc = parseYaml(fs.readFileSync(solPath, "utf-8")) as Record<string, unknown>;
59
+ const web = doc.web;
60
+ if (web && typeof web === "object" && !Array.isArray(web)) {
61
+ const rp = (web as Record<string, unknown>).route_prefix;
62
+ if (typeof rp === "string" && /^\/[a-z][a-z0-9-]{0,63}$/.test(rp))
63
+ return rp.slice(1);
64
+ }
65
+ }
66
+ catch {
67
+ // YAML 解析失败 → 缺省,不阻断构建(契约校验会在别处暴露)
68
+ }
69
+ return name;
70
+ }
71
+
72
+ const ALGORITHM = "sha384";
73
+
74
+ function sha384(file: string): string {
75
+ const digest = crypto.createHash(ALGORITHM).update(fs.readFileSync(file)).digest("base64");
76
+ return `${ALGORITHM}-${digest}`;
77
+ }
78
+
79
+ function warnUnsharedDeps(projectRoot: string) {
80
+ const pkgPath = path.join(projectRoot, "package.json");
81
+ if (!fs.existsSync(pkgPath))
82
+ return;
83
+
84
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
85
+ const deps = Object.keys(pkg.dependencies ?? {});
86
+ const unshared = deps.filter(dep => !isSharedDep(dep) && !dep.startsWith("@oj-module/"));
87
+
88
+ if (unshared.length) {
89
+ console.warn(
90
+ `[ojm] ⚠️ 以下运行时依赖不在共享表内,会被打进模块产物:${unshared.join(", ")}\n`
91
+ + " 若它应与宿主共用,请加入 SHARED_DEPS 并在宿主 importmap 中映射(设计文档 C8)",
92
+ );
93
+ }
94
+ }
95
+
96
+ /** 提取产物文件中的全部裸说明符(排除相对/绝对/# 路径) */
97
+ function collectBareSpecifiers(file: string): string[] {
98
+ const source = fs.readFileSync(file, "utf-8");
99
+ const found = new Set<string>();
100
+ const patterns = [
101
+ /(?:import|export)\s[^'";]*?from\s*["']([^"']+)["']/g, // import/export ... from "x"
102
+ /import\s*["']([^"']+)["']/g, // 副作用导入 import "x"
103
+ /import\(\s*["']([^"']+)["']\s*\)/g, // 动态 import("x")
104
+ ];
105
+ for (const pattern of patterns) {
106
+ for (const match of source.matchAll(pattern)) {
107
+ const spec = match[1]!;
108
+ if (!spec.startsWith(".") && !spec.startsWith("/") && !spec.startsWith("#"))
109
+ found.add(spec);
110
+ }
111
+ }
112
+ return [...found];
113
+ }
114
+
115
+ /**
116
+ * P7.9 / B11 + C8:构建期扫描模块产物的裸说明符。
117
+ * - 深路径命中共享表前缀但非精确 importmap 键(如 dayjs/plugin/utc):
118
+ * 构建期直接报错——importmap 无前缀通配,浏览器必抛
119
+ * "Failed to resolve module specifier",不能拖到运行期(§4.7 错误契约)。
120
+ * - 表外说明符:C8 构建期告警(按真实 import 分析,不依赖 package.json 字段)。
121
+ */
122
+ function assertResolvableSpecifiers(
123
+ moduleName: string,
124
+ moduleOutDir: string,
125
+ emitted: Map<string, { type: string, fileName: string }>,
126
+ ): void {
127
+ const exactKeys = new Set(SHARED_DEPS.map(dep => dep.specifier));
128
+ const deepPathErrors: string[] = [];
129
+ const unsharedWarnings = new Set<string>();
130
+
131
+ for (const info of emitted.values()) {
132
+ if (info.type !== "chunk")
133
+ continue;
134
+ for (const spec of collectBareSpecifiers(path.join(moduleOutDir, info.fileName))) {
135
+ if (exactKeys.has(spec))
136
+ continue;
137
+ if (isSharedDep(spec)) {
138
+ deepPathErrors.push(` · ${info.fileName} → "${spec}"`);
139
+ }
140
+ else {
141
+ unsharedWarnings.add(spec);
142
+ }
143
+ }
144
+ }
145
+
146
+ if (deepPathErrors.length > 0) {
147
+ throw new Error(
148
+ `[ojm] 模块 "${moduleName}" 的产物含 importmap 无法解析的深路径说明符:\n`
149
+ + `${deepPathErrors.join("\n")}\n`
150
+ + "共享表只提供精确键(importmap 无前缀通配)。修复建议:改从包根导入"
151
+ + "(如 dayjs 插件改在宿主侧注册),或联系框架方在 SHARED_DEPS 增补该深路径条目。",
152
+ );
153
+ }
154
+
155
+ if (unsharedWarnings.size > 0) {
156
+ console.warn(
157
+ `[ojm] ⚠️ 模块 "${moduleName}" import 了共享表外的三方库:${[...unsharedWarnings].join(", ")}\n`
158
+ + " 它们会被打进模块产物。若应与宿主共用,请加入 SHARED_DEPS(设计文档 C8)",
159
+ );
160
+ }
161
+ }
162
+
163
+ /**
164
+ * 构建模块工程。
165
+ *
166
+ * 产出(layout.distDir:module-root / new → dist/web;flat → build):
167
+ * <dist>/modules/<name>/<version>/{entry.js, chunk-*.js, *.css}
168
+ * <dist>/modules.json
169
+ *
170
+ * opts.mergeSite 仅 `ojm build` 传 true:清场 + 拷 shell dist 全量;
171
+ * devServer 热重建默认 false,只写模块产物。
172
+ */
173
+ export async function buildModules(
174
+ projectRoot: string,
175
+ opts: { mergeSite?: boolean } = {},
176
+ ): Promise<BuiltModule[]> {
177
+ const layout = resolveLayout(projectRoot);
178
+ const config = await loadSiteConfig(projectRoot);
179
+ // module-root:模块清单由 src/*/web/entry.ts 扫描得出(web.config.ts 仅可选覆盖);
180
+ // 历史布局:仍以 web.config.ts 的 modules 为唯一真源。
181
+ const modules = layout.kind === "module-root"
182
+ ? mergeModuleList(scanModules(layout), config.modules, projectRoot)
183
+ : assertModuleList(projectRoot, config.modules);
184
+ const outDir = layout.distDir;
185
+ const baseUrl = config.baseUrl ?? "";
186
+
187
+ if (opts.mergeSite)
188
+ mergeShellSite(outDir, config.siteBase ?? "", config.apiBase ?? "");
189
+
190
+ // P4.5 / C4 / D12:构建前先过版本矩阵门禁,版本漂移直接拒绝
191
+ checkSharedVersions(projectRoot, resolveShellDist());
192
+
193
+ warnUnsharedDeps(projectRoot);
194
+
195
+ const built: BuiltModule[] = [];
196
+
197
+ for (const item of modules) {
198
+ if (item.enabled === false) {
199
+ console.log(`[ojm] 跳过已禁用模块 ${item.name}`);
200
+ continue;
201
+ }
202
+
203
+ const entryFile = resolveModuleEntry(projectRoot, item.entry);
204
+ const definition = await readModuleDefinition(entryFile, projectRoot);
205
+
206
+ if (definition.name !== item.name) {
207
+ throw new Error(
208
+ `模块名不一致:${layout.kind === "module-root" ? `src/${item.name}` : "web.config.ts"} 中为 "${item.name}",entry.ts 中为 "${definition.name}"`,
209
+ );
210
+ }
211
+
212
+ const moduleOutDir = path.join(outDir, "modules", definition.name, definition.version);
213
+ const emitted = new Map<string, { fileName: string, type: "chunk" | "asset", isEntry: boolean, isDynamicEntry: boolean }>();
214
+
215
+ const collectChunks: Plugin = {
216
+ name: "ojm:collect-chunks",
217
+ writeBundle(_options, bundle) {
218
+ for (const [fileName, output] of Object.entries(bundle)) {
219
+ emitted.set(fileName, {
220
+ fileName,
221
+ type: output.type,
222
+ isEntry: output.type === "chunk" && output.isEntry,
223
+ isDynamicEntry: output.type === "chunk" && output.isDynamicEntry,
224
+ });
225
+ }
226
+ },
227
+ };
228
+
229
+ console.log(`[ojm] 构建 ${definition.name}@${definition.version} ...`);
230
+
231
+ await build({
232
+ root: projectRoot,
233
+ logLevel: "warn",
234
+ // §4.1-④:tailwind 模块管线——模块内 import 的 css 经 @tailwindcss/vite
235
+ // 编译,产物由宿主 <link> 注入(R16);模块无 css 入口时插件不产生任何产物
236
+ plugins: [collectChunks, tailwindcss()],
237
+ // Spike A 坑 2:lib 模式不替换 process.env.NODE_ENV,
238
+ // 浏览器顶层求值会抛 process is not defined(风险 R15)
239
+ define: { "process.env.NODE_ENV": JSON.stringify("production") },
240
+ build: {
241
+ outDir: moduleOutDir,
242
+ emptyOutDir: true,
243
+ sourcemap: false,
244
+ /**
245
+ * 模块产物压缩(2026-09-17 由 `false` 改为 `true`)。
246
+ *
247
+ * 本行原为 `false` **且无注释**(同文件其余设置都带 rationale)—— 经查出自
248
+ * 2026-08-31 的调试提交 `1bf3200`,疑似调试期临时值遗留。实测代价极大:
249
+ * 仅这一项就让 planning 的 gzip 从 186,730 → **75,872(−59.4%)**、
250
+ * workitems 88,351 → **40,113(−54.6%)**(同一份产物只做压缩,未改任何配置)。
251
+ * 背景:曾评估「把重复的生成 client 提成共享资产来省体积」,实测 gzip 净变化
252
+ * 仅 −364 B(生成 client 压缩率 6.8%,且重复内容已被同一 bundle 内的 gzip
253
+ * 滑窗吃掉)⇒ **真正的杠杆是压缩,不是去重**(见 oj-module 台账 T54)。
254
+ *
255
+ * ⚠️ **本项只作用于「模块产物」**,与宿主共享资产无关:`shell-dist/assets/*.js`
256
+ * 由 `shell/scripts/build.mts` 自己的 esbuild 构建,且 `esm-exports.ts` 的
257
+ * 导出面解析**依赖资产顶格输出**(其文件头写明「`minify: false` 下顶层语句
258
+ * 一律顶格输出」)⇒ **不要**顺手把共享资产也压了,那会让导入完整性门禁失效。
259
+ *
260
+ * 代价(已知并接受):生产产物栈不可读(`sourcemap: false` 保持不变 —— 开
261
+ * sourcemap 会额外部署 .map 文件,属另一个决策)。
262
+ */
263
+ minify: true,
264
+ lib: {
265
+ entry: entryFile,
266
+ formats: ["es"],
267
+ fileName: () => "entry.js",
268
+ },
269
+ rolldownOptions: {
270
+ // 只把共享依赖留给宿主 importmap;
271
+ // 相对路径 / 绝对路径是模块自身代码,需要打包
272
+ external: (id: string) => !id.startsWith(".") && !path.isAbsolute(id) && isPrebuiltDep(id),
273
+ output: {
274
+ // P7.x / e2e:模块产物内联动态 import(lazy 页面、i18n 等),
275
+ // 输出为**单文件**。原因:
276
+ // 1. 拆出的 chunk 只能靠 import.meta.url 在「真实 HTTP 服务」下解析,
277
+ // 任何非 HTTP 加载上下文(e2e harness、离线/原生壳、L2 完整性之外的
278
+ // 加载路径)都会 ECONNREFUSED / 404,导致页面空白;
279
+ // 2. 拆出的 lazy chunk 不受 L2 完整性保护(构建期已告警),是模块化
280
+ // 方案的真实完整性缺陷;单文件后整包受 modulepreload+integrity 覆盖;
281
+ // 3. 单文件模块是微前端模块的通用形态,宿主按真实 URL 一次性加载即可,
282
+ // 无孤儿 chunk 依赖。
283
+ codeSplitting: false as any,
284
+ },
285
+ },
286
+ },
287
+ });
288
+
289
+ // 运行期 require 门禁:CJS 依赖 require 了 external 共享包时,rolldown 只留一个浏览器
290
+ // 不可用的 require 桩("Calling `require` for ..."),表现为模块加载即抛错、页面空白。
291
+ // 这类依赖必须移出 bundle 走宿主 importmap(shell 侧有 CJS→ESM 垫片)。
292
+ const builtEntry = path.join(moduleOutDir, "entry.js");
293
+ if (fs.existsSync(builtEntry)) {
294
+ const code = fs.readFileSync(builtEntry, "utf-8");
295
+ if (code.includes("doesn't expose the `require` function")) {
296
+ const specs = [...new Set([...code.matchAll(/ne\("([^"]+)"\)/g)].map(m => m[1]))];
297
+ throw new Error(
298
+ `[ojm] ${definition.name}@${definition.version} 产物含运行期 require(${specs.join(", ") || "?"})`
299
+ + "——浏览器没有 require,模块加载即抛错。"
300
+ + "根因:该 CJS 依赖被标为 bundle(自带副本),但它 require 的共享包被 external 了。"
301
+ + "修复:把它从 SHARED_DEPS 的 bundle 列表移回共享资产,或改用该依赖的 ESM 入口。",
302
+ );
303
+ }
304
+ }
305
+
306
+ const prefix = `${baseUrl}/modules/${definition.name}/${definition.version}/`;
307
+ const chunks: ChunkEntry[] = [];
308
+ const css: string[] = [];
309
+
310
+ for (const info of emitted.values()) {
311
+ if (info.type === "asset") {
312
+ if (info.fileName.endsWith(".css"))
313
+ css.push(`${prefix}${info.fileName}`);
314
+ continue;
315
+ }
316
+
317
+ // P7.3:entry 也进 chunks(lazy:false)——宿主 L2 完整性按 chunks[]
318
+ // 注入 modulepreload+integrity,此前 entry 被 isEntry 跳过导致
319
+ // 顶层 integrity 成为死字段(评审 S3:入口恰好不受保护)
320
+ chunks.push({
321
+ url: `${prefix}${info.fileName}`,
322
+ integrity: sha384(path.join(moduleOutDir, info.fileName)),
323
+ lazy: info.isEntry ? false : info.isDynamicEntry,
324
+ });
325
+ }
326
+
327
+ // §4.6:lazy chunk 不受 L2 完整性保护,构建期必须显式提示
328
+ const lazyChunks = chunks.filter(c => c.lazy);
329
+ if (lazyChunks.length > 0) {
330
+ console.warn(
331
+ `[ojm] 模块 "${definition.name}" 含 ${lazyChunks.length} 个 lazy chunk,`
332
+ + "它们在 L2 完整性档位下不受保护(§4.7 D7):\n"
333
+ + `${lazyChunks.map(c => ` · ${c.url}`).join("\n")}\n`
334
+ + "若这些 chunk 也要求完整性,请升级到 L3(Service Worker)或使用逃生通道(§4.7)。",
335
+ );
336
+ }
337
+
338
+ // P7.9 / B11:扫描产物中的裸说明符,构建期拦截 importmap 无法解析的
339
+ // 深路径(如 dayjs/plugin/utc——isSharedDep 前缀命中但 importmap 只有
340
+ // 精确键,浏览器必抛 Failed to resolve module specifier);
341
+ // 顺带以真实 import 分析落地 C8 表外依赖告警(不再只扫 package.json 字段)
342
+ assertResolvableSpecifiers(definition.name, moduleOutDir, emitted);
343
+
344
+ built.push({
345
+ name: definition.name,
346
+ version: definition.version,
347
+ enabled: true,
348
+ dependencies: definition.config?.dependencies ?? [],
349
+ peerRuntime: definition.peerRuntime,
350
+ entry: `${prefix}entry.js`,
351
+ integrity: sha384(path.join(moduleOutDir, "entry.js")),
352
+ css,
353
+ chunks,
354
+ routePrefix: resolveRoutePrefix(layout, definition.name),
355
+ });
356
+ }
357
+
358
+ const manifestPath = path.join(outDir, "modules.json");
359
+ fs.mkdirSync(outDir, { recursive: true });
360
+ fs.writeFileSync(manifestPath, `${JSON.stringify(built, null, 2)}\n`);
361
+ console.log(`[ojm] 清单已生成 → ${manifestPath}`);
362
+
363
+ return built;
364
+ }