@oj-module/cli 0.2.17 → 0.2.20

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 (332) hide show
  1. package/devkit/README.md +4 -4
  2. package/devkit/SKILL.md +41 -37
  3. package/devkit/framework-dev.md +6 -5
  4. package/devkit/manual.md +260 -162
  5. package/devkit/menu-rules.md +3 -4
  6. package/devkit/module-dev-and-cdn-playground.md +31 -22
  7. package/devkit/sql-builder-missing-capabilities-pr.md +11 -6
  8. package/package.json +2 -2
  9. package/shell-dist/assets/runtime.js +2 -2
  10. package/shell-dist/index.html +2 -2
  11. package/shell-dist/versions.json +3 -3
  12. package/src/__tests__/build-backend.test.ts +54 -0
  13. package/src/__tests__/layout.test.ts +176 -0
  14. package/src/__tests__/module-list.test.ts +66 -0
  15. package/src/__tests__/oj-caps.test.ts +114 -0
  16. package/src/alias-paths.ts +102 -0
  17. package/src/build.ts +41 -9
  18. package/src/bundle.ts +25 -13
  19. package/src/config.ts +82 -9
  20. package/src/contract/__tests__/market-client.integration.test.ts +2 -2
  21. package/src/contract/check.ts +56 -28
  22. package/src/contract/emit-stub.ts +21 -9
  23. package/src/contract/handler-scan.ts +19 -10
  24. package/src/contract/run.ts +14 -4
  25. package/src/dev.ts +22 -7
  26. package/src/index.ts +1 -1
  27. package/src/info.ts +20 -3
  28. package/src/init.ts +91 -21
  29. package/src/layout.ts +282 -24
  30. package/src/lifecycle/__tests__/bundle.test.ts +16 -1
  31. package/src/lifecycle/__tests__/manifest-contract.test.ts +17 -58
  32. package/src/manifest-contract.ts +2 -25
  33. package/src/market/__tests__/bootstrap.test.ts +17 -9
  34. package/src/market/bootstrap.ts +30 -17
  35. package/src/oj-caps.ts +133 -0
  36. package/src/oj.ts +27 -4
  37. package/src/preview-config.ts +1 -1
  38. package/src/preview.ts +2 -1
  39. package/src/site.ts +2 -2
  40. package/src/usage.ts +6 -6
  41. package/src/vendor.ts +5 -1
  42. package/templates/{api/config.yaml → config.yaml} +13 -8
  43. package/templates/global.d.ts +7 -6
  44. package/templates/init.include.yaml +41 -36
  45. package/templates/package.json +1 -1
  46. package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/installer.ts +4 -0
  47. package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/smoke.ts +21 -2
  48. package/templates/{api/src/_platform → src/_platform/api}/market/api.ts +25 -15
  49. package/templates/{api/src/_platform → src/_platform/api}/solutions/api.ts +7 -3
  50. package/templates/{api/src/auth → src/auth/api}/_shared/login-throttle.ts +2 -2
  51. package/templates/{api/src/auth → src/auth/api}/_shared/session.ts +2 -2
  52. package/templates/{api/src/auth → src/auth/api}/api.ts +1 -1
  53. package/templates/{api/src/auth → src/auth/api}/ldap-login/api.ts +1 -1
  54. package/templates/src/auth/api/manifest.yaml +6 -0
  55. package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/InstallDialog.test.tsx +53 -1
  56. package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/marketClient.fake.ts +6 -0
  57. package/templates/{web/src/oj-market → src/oj-market/web}/api/client.ts +5 -0
  58. package/templates/{web/src/oj-market → src/oj-market/web}/api/defaultClient.ts +7 -1
  59. package/templates/{web/src/oj-market → src/oj-market/web}/components/InstallDialog.tsx +80 -5
  60. package/templates/{web/src/oj-market → src/oj-market/web}/hooks/useMarket.ts +6 -1
  61. package/templates/{web/src/oj-market → src/oj-market/web}/locales/en-US.json +10 -1
  62. package/templates/{web/src/oj-market → src/oj-market/web}/locales/zh-CN.json +10 -1
  63. package/templates/{web/src/oj-market → src/oj-market/web}/types.ts +15 -2
  64. package/templates/{api/src/system → src/system/api}/login-methods/api.ts +2 -2
  65. package/templates/src/system/api/manifest.yaml +6 -0
  66. package/templates/{api/src/system → src/system/api}/oplog/api.ts +4 -4
  67. package/templates/{api/src/system → src/system/api}/permissions/api.ts +3 -3
  68. package/templates/{api/src/system → src/system/api}/roles/api.ts +3 -3
  69. package/templates/{api/src/system → src/system/api}/roles/bindings/api.ts +3 -3
  70. package/templates/{api/src/system → src/system/api}/settings/api.ts +3 -3
  71. package/templates/{api/src/system → src/system/api}/users/api.ts +3 -3
  72. package/templates/{api/src/system → src/system/api}/users/forbidden/api.ts +3 -3
  73. package/templates/{api/src/system → src/system/api}/users/password/api.ts +3 -3
  74. package/templates/{api/src/system → src/system/api}/users/roles/api.ts +3 -3
  75. package/templates/src/tsconfig.json +16 -0
  76. package/templates/{api/tests → tests}/auth-ldap.spec.ts +2 -2
  77. package/templates/{api/tests → tests}/auth-session.spec.ts +3 -3
  78. package/templates/{api/tests → tests}/auth-throttle.spec.ts +1 -1
  79. package/templates/tests/fixture.ts +434 -0
  80. package/templates/{api/tests → tests}/guard.spec.ts +1 -1
  81. package/templates/{api/tests → tests}/lifecycle/atomic-state.spec.ts +3 -3
  82. package/templates/{api/tests → tests}/lifecycle/bootstrap.spec.ts +8 -4
  83. package/templates/{api/tests → tests}/lifecycle/deploy-smoke.spec.ts +31 -8
  84. package/templates/{api/tests → tests}/lifecycle/installer.spec.ts +15 -15
  85. package/templates/{api/tests → tests}/lifecycle/market-api.spec.ts +30 -29
  86. package/templates/{api/tests → tests}/lifecycle/migrate.spec.ts +6 -6
  87. package/templates/{api/tests → tests}/lifecycle/preflight.spec.ts +4 -4
  88. package/templates/{api/tests → tests}/lifecycle/register.spec.ts +1 -1
  89. package/templates/{api/tests → tests}/lifecycle/semver.spec.ts +1 -1
  90. package/templates/{api/tests → tests}/lifecycle/sha384.spec.ts +1 -1
  91. package/templates/{api/tests → tests}/lifecycle/sig-fixtures.spec.ts +1 -1
  92. package/templates/{api/tests → tests}/lifecycle/solutions-api.spec.ts +1 -1
  93. package/templates/{api/tests → tests}/lifecycle/steps-fs.spec.ts +12 -12
  94. package/templates/{api/tests → tests}/lifecycle/text-edit.spec.ts +1 -1
  95. package/templates/{api/tests → tests}/lifecycle/tgz-guard.spec.ts +1 -1
  96. package/templates/{api/tests → tests}/lifecycle/trust.spec.ts +5 -5
  97. package/templates/{api/tests → tests}/lifecycle/uninstall.spec.ts +7 -7
  98. package/templates/{api/tests → tests}/lifecycle/verify-checks.spec.ts +9 -6
  99. package/templates/{api/tests → tests}/lifecycle/verify-report.spec.ts +7 -5
  100. package/templates/{api/tests → tests}/query-utils.spec.ts +1 -1
  101. package/templates/{api/tests → tests}/rbac-audit.spec.ts +1 -1
  102. package/templates/{api/tests → tests}/rbac-contacts.spec.ts +2 -2
  103. package/templates/{api/tests → tests}/rbac-guard.spec.ts +1 -1
  104. package/templates/{api/tests → tests}/rbac-roles.spec.ts +2 -2
  105. package/templates/{api/tests → tests}/rbac-seed.spec.ts +1 -1
  106. package/templates/{api/tests → tests}/rbac-settings.spec.ts +2 -2
  107. package/templates/{api/tests → tests}/rbac-solution-perms.spec.ts +1 -1
  108. package/templates/{api/tests → tests}/rbac-users.spec.ts +3 -3
  109. package/templates/tsconfig.json +5 -1
  110. package/templates/tsconfig.paths.json +19 -0
  111. package/templates/types/oj-modules.d.ts +17 -0
  112. package/templates/vitest.config.ts +22 -0
  113. package/templates/web.config.ts +23 -13
  114. package/vendor/host-versions.json +3 -3
  115. package/templates/api/src/auth/manifest.yaml +0 -5
  116. package/templates/api/src/system/manifest.yaml +0 -5
  117. package/templates/api/tests/fixture.ts +0 -58
  118. package/templates/api/tsconfig.json +0 -8
  119. package/templates/api/vitest.config.ts +0 -12
  120. package/templates/logs/task-events.jsonl +0 -0
  121. /package/templates/{api/.ojm-api-exempt.json → .ojm-api-exempt.json} +0 -0
  122. /package/templates/{api/seed.mysql.sql → seed.mysql.sql} +0 -0
  123. /package/templates/{api/seed.pg.sql → seed.pg.sql} +0 -0
  124. /package/templates/{api/src/_platform → src/_platform/api}/README.md +0 -0
  125. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/atomic.ts +0 -0
  126. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/history.ts +0 -0
  127. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/lock.ts +0 -0
  128. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/semver.ts +0 -0
  129. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/sha384.ts +0 -0
  130. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/state.ts +0 -0
  131. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/deploy-web.ts +0 -0
  132. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/download.ts +0 -0
  133. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/extract.ts +0 -0
  134. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/migrate.ts +0 -0
  135. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/preflight.ts +0 -0
  136. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/register.ts +0 -0
  137. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/reload.ts +0 -0
  138. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/verify.ts +0 -0
  139. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tasks.ts +0 -0
  140. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/text-edit.ts +0 -0
  141. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tgz-guard.ts +0 -0
  142. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/trust.ts +0 -0
  143. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/types.ts +0 -0
  144. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/uninstall.ts +0 -0
  145. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-checks.ts +0 -0
  146. /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-report.ts +0 -0
  147. /package/templates/{api/src/_platform → src/_platform/api}/_shared/respond.ts +0 -0
  148. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/contacts.ts +0 -0
  149. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/roles.ts +0 -0
  150. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/settings.ts +0 -0
  151. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/solution-perms.ts +0 -0
  152. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/users.ts +0 -0
  153. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/access.ts +0 -0
  154. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/audit.ts +0 -0
  155. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/guard.ts +0 -0
  156. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/oplog.ts +0 -0
  157. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/query.ts +0 -0
  158. /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/rate.ts +0 -0
  159. /package/templates/{api/src/_platform → src/_platform/api}/_shared/site-facade.ts +0 -0
  160. /package/templates/{api/src/_platform → src/_platform/api}/contacts/api.ts +0 -0
  161. /package/templates/{api/src/_platform → src/_platform/api}/contacts/detail/api.ts +0 -0
  162. /package/templates/{api/src/_platform → src/_platform/api}/fixtures/l1-test-user.sql +0 -0
  163. /package/templates/{api/src/_platform → src/_platform/api}/manifest.yaml +0 -0
  164. /package/templates/{api/src/_platform → src/_platform/api}/market/bootstrap.ts +0 -0
  165. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.mysql.sql +0 -0
  166. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.pg.sql +0 -0
  167. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.sql +0 -0
  168. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
  169. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.sql +0 -0
  170. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.mysql.sql +0 -0
  171. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.sql +0 -0
  172. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.mysql.sql +0 -0
  173. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.pg.sql +0 -0
  174. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.sql +0 -0
  175. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.mysql.sql +0 -0
  176. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.sql +0 -0
  177. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
  178. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.sql +0 -0
  179. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0007__users_email.sql +0 -0
  180. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
  181. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.pg.sql +0 -0
  182. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.sql +0 -0
  183. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.mysql.sql +0 -0
  184. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.pg.sql +0 -0
  185. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.sql +0 -0
  186. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.mysql.sql +0 -0
  187. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.pg.sql +0 -0
  188. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.sql +0 -0
  189. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
  190. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.sql +0 -0
  191. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.mysql.sql +0 -0
  192. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.pg.sql +0 -0
  193. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.sql +0 -0
  194. /package/templates/{api/src/_platform → src/_platform/api}/migrations/0013__users_profile.sql +0 -0
  195. /package/templates/{api/src/_platform → src/_platform/api}/schema.yaml +0 -0
  196. /package/templates/{api/src/_platform → src/_platform/api}/seed.mysql.sql +0 -0
  197. /package/templates/{api/src/_platform → src/_platform/api}/seed.pg.sql +0 -0
  198. /package/templates/{api/src/_platform → src/_platform/api}/seed.sql +0 -0
  199. /package/templates/{web/src/_platform → src/_platform/web}/__client/api.schemas.ts +0 -0
  200. /package/templates/{web/src/_platform → src/_platform/web}/__client/api.ts +0 -0
  201. /package/templates/{web/src/about → src/about/web}/entry.ts +0 -0
  202. /package/templates/{web/src/about → src/about/web}/locales/en-US.json +0 -0
  203. /package/templates/{web/src/about → src/about/web}/locales/zh-CN.json +0 -0
  204. /package/templates/{web/src/about → src/about/web}/pages/constants.ts +0 -0
  205. /package/templates/{web/src/about → src/about/web}/pages/index.tsx +0 -0
  206. /package/templates/{web/src/access → src/access/web}/entry.ts +0 -0
  207. /package/templates/{web/src/access → src/access/web}/locales/en-US.json +0 -0
  208. /package/templates/{web/src/access → src/access/web}/locales/zh-CN.json +0 -0
  209. /package/templates/{web/src/access → src/access/web}/pages/access-mode/index.tsx +0 -0
  210. /package/templates/{web/src/access → src/access/web}/pages/admin-visible/index.tsx +0 -0
  211. /package/templates/{web/src/access → src/access/web}/pages/button-control/index.tsx +0 -0
  212. /package/templates/{web/src/access → src/access/web}/pages/common-visible/index.tsx +0 -0
  213. /package/templates/{web/src/access → src/access/web}/pages/page-control/index.tsx +0 -0
  214. /package/templates/{api/src/auth → src/auth/api}/_shared/ldap-login.ts +0 -0
  215. /package/templates/{api/src/auth → src/auth/api}/_shared/ldap.ts +0 -0
  216. /package/templates/{web/src/auth → src/auth/web}/__client/api.schemas.ts +0 -0
  217. /package/templates/{web/src/auth → src/auth/web}/__client/api.ts +0 -0
  218. /package/templates/{api/src/demo → src/demo/api}/manifest.yaml +0 -0
  219. /package/templates/{api/src/demo → src/demo/api}/migrations/0001__create_todos.sql +0 -0
  220. /package/templates/{api/src/demo → src/demo/api}/schema.yaml +0 -0
  221. /package/templates/{api/src/demo → src/demo/api}/seed.sql +0 -0
  222. /package/templates/{api/src/demo → src/demo/api}/todos/api.ts +0 -0
  223. /package/templates/{web/src/demo → src/demo/web}/__client/api.schemas.ts +0 -0
  224. /package/templates/{web/src/demo → src/demo/web}/__client/api.ts +0 -0
  225. /package/templates/{web/src/demo → src/demo/web}/entry.ts +0 -0
  226. /package/templates/{web/src/demo → src/demo/web}/locales/en-US.json +0 -0
  227. /package/templates/{web/src/demo → src/demo/web}/locales/zh-CN.json +0 -0
  228. /package/templates/{web/src/demo → src/demo/web}/pages/index.tsx +0 -0
  229. /package/templates/{web/src/exception → src/exception/web}/entry.ts +0 -0
  230. /package/templates/{web/src/exception → src/exception/web}/locales/en-US.json +0 -0
  231. /package/templates/{web/src/exception → src/exception/web}/locales/zh-CN.json +0 -0
  232. /package/templates/{web/src/exception → src/exception/web}/pages/403/index.tsx +0 -0
  233. /package/templates/{web/src/exception → src/exception/web}/pages/404/index.tsx +0 -0
  234. /package/templates/{web/src/exception → src/exception/web}/pages/500/index.tsx +0 -0
  235. /package/templates/{web/src/exception → src/exception/web}/pages/unknown-component/index.tsx +0 -0
  236. /package/templates/{api/src/home → src/home/api}/line/api.ts +0 -0
  237. /package/templates/{api/src/home → src/home/api}/manifest.yaml +0 -0
  238. /package/templates/{api/src/home → src/home/api}/migrations/0001__create_home_tables.sql +0 -0
  239. /package/templates/{api/src/home → src/home/api}/pie/api.ts +0 -0
  240. /package/templates/{api/src/home → src/home/api}/schema.yaml +0 -0
  241. /package/templates/{api/src/home → src/home/api}/seed.sql +0 -0
  242. /package/templates/{web/src/home → src/home/web}/__client/api.schemas.ts +0 -0
  243. /package/templates/{web/src/home → src/home/web}/__client/api.ts +0 -0
  244. /package/templates/{web/src/home → src/home/web}/entry.ts +0 -0
  245. /package/templates/{web/src/home → src/home/web}/locales/en-US.json +0 -0
  246. /package/templates/{web/src/home → src/home/web}/locales/zh-CN.json +0 -0
  247. /package/templates/{web/src/home → src/home/web}/pages/components/bar-chart.tsx +0 -0
  248. /package/templates/{web/src/home → src/home/web}/pages/components/card-list.tsx +0 -0
  249. /package/templates/{web/src/home → src/home/web}/pages/components/line-chart.tsx +0 -0
  250. /package/templates/{web/src/home → src/home/web}/pages/components/pie-chart.tsx +0 -0
  251. /package/templates/{web/src/home → src/home/web}/pages/index.tsx +0 -0
  252. /package/templates/{web/src/login → src/login/web}/entry.ts +0 -0
  253. /package/templates/{web/src/login → src/login/web}/locales/en-US.json +0 -0
  254. /package/templates/{web/src/login → src/login/web}/locales/zh-CN.json +0 -0
  255. /package/templates/{web/src/login → src/login/web}/pages/change-password.tsx +0 -0
  256. /package/templates/{web/src/login → src/login/web}/pages/login.tsx +0 -0
  257. /package/templates/{api/src/notification → src/notification/api}/_shared/notify.ts +0 -0
  258. /package/templates/{api/src/notification → src/notification/api}/api.ts +0 -0
  259. /package/templates/{api/src/notification → src/notification/api}/del/api.ts +0 -0
  260. /package/templates/{api/src/notification → src/notification/api}/manifest.yaml +0 -0
  261. /package/templates/{api/src/notification → src/notification/api}/migrations/0001__create_notifications.sql +0 -0
  262. /package/templates/{api/src/notification → src/notification/api}/migrations/0002__notifications_user.sql +0 -0
  263. /package/templates/{api/src/notification → src/notification/api}/migrations/0003__notifications_broadcast.sql +0 -0
  264. /package/templates/{api/src/notification → src/notification/api}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
  265. /package/templates/{api/src/notification → src/notification/api}/schema.yaml +0 -0
  266. /package/templates/{api/src/notification → src/notification/api}/seed.sql +0 -0
  267. /package/templates/{web/src/notification → src/notification/web}/__client/api.schemas.ts +0 -0
  268. /package/templates/{web/src/notification → src/notification/web}/__client/api.ts +0 -0
  269. /package/templates/{web/src/notification → src/notification/web}/entry.ts +0 -0
  270. /package/templates/{web/src/notification → src/notification/web}/locales/en-US.json +0 -0
  271. /package/templates/{web/src/notification → src/notification/web}/locales/zh-CN.json +0 -0
  272. /package/templates/{web/src/notification → src/notification/web}/pages/center/index.tsx +0 -0
  273. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/CardGrid.test.tsx +0 -0
  274. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/HistoryDrawer.test.tsx +0 -0
  275. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/RollbackDialog.test.tsx +0 -0
  276. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/UninstallConfirm.test.tsx +0 -0
  277. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/poll.test.ts +0 -0
  278. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/render.tsx +0 -0
  279. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/runtime-stub.ts +0 -0
  280. /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/semver.test.ts +0 -0
  281. /package/templates/{web/src/oj-market → src/oj-market/web}/api/MarketClientProvider.tsx +0 -0
  282. /package/templates/{web/src/oj-market → src/oj-market/web}/api/context.ts +0 -0
  283. /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardGrid.tsx +0 -0
  284. /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardItem.tsx +0 -0
  285. /package/templates/{web/src/oj-market → src/oj-market/web}/components/DetailDrawer.tsx +0 -0
  286. /package/templates/{web/src/oj-market → src/oj-market/web}/components/HistoryDrawer.tsx +0 -0
  287. /package/templates/{web/src/oj-market → src/oj-market/web}/components/RollbackDialog.tsx +0 -0
  288. /package/templates/{web/src/oj-market → src/oj-market/web}/components/UninstallConfirm.tsx +0 -0
  289. /package/templates/{web/src/oj-market → src/oj-market/web}/entry.ts +0 -0
  290. /package/templates/{web/src/oj-market → src/oj-market/web}/pages/MarketApp.tsx +0 -0
  291. /package/templates/{web/src/oj-market → src/oj-market/web}/utils/poll.ts +0 -0
  292. /package/templates/{web/src/oj-market → src/oj-market/web}/utils/semver.ts +0 -0
  293. /package/templates/{web/src/outside → src/outside/web}/entry.ts +0 -0
  294. /package/templates/{web/src/outside → src/outside/web}/locales/en-US.json +0 -0
  295. /package/templates/{web/src/outside → src/outside/web}/locales/zh-CN.json +0 -0
  296. /package/templates/{api/src/personal-center → src/personal-center/api}/manifest.yaml +0 -0
  297. /package/templates/{api/src/personal-center → src/personal-center/api}/profile/api.ts +0 -0
  298. /package/templates/{api/src/personal-center → src/personal-center/api}/upload/api.ts +0 -0
  299. /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.schemas.ts +0 -0
  300. /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.ts +0 -0
  301. /package/templates/{web/src/personal-center → src/personal-center/web}/entry.ts +0 -0
  302. /package/templates/{web/src/personal-center → src/personal-center/web}/locales/en-US.json +0 -0
  303. /package/templates/{web/src/personal-center → src/personal-center/web}/locales/zh-CN.json +0 -0
  304. /package/templates/{web/src/personal-center → src/personal-center/web}/pages/my-profile/index.tsx +0 -0
  305. /package/templates/{web/src/route-nest → src/route-nest/web}/entry.ts +0 -0
  306. /package/templates/{web/src/route-nest → src/route-nest/web}/locales/en-US.json +0 -0
  307. /package/templates/{web/src/route-nest → src/route-nest/web}/locales/zh-CN.json +0 -0
  308. /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-1/index.tsx +0 -0
  309. /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-2/index.tsx +0 -0
  310. /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu2/index.tsx +0 -0
  311. /package/templates/{web/src → src}/styles.css +0 -0
  312. /package/templates/{web/src/system → src/system/web}/__client/api.schemas.ts +0 -0
  313. /package/templates/{web/src/system → src/system/web}/__client/api.ts +0 -0
  314. /package/templates/{web/src/system → src/system/web}/entry.ts +0 -0
  315. /package/templates/{web/src/system → src/system/web}/locales/en-US.json +0 -0
  316. /package/templates/{web/src/system → src/system/web}/locales/zh-CN.json +0 -0
  317. /package/templates/{web/src/system → src/system/web}/pages/errors.ts +0 -0
  318. /package/templates/{web/src/system → src/system/web}/pages/forbidden.tsx +0 -0
  319. /package/templates/{web/src/system → src/system/web}/pages/login-methods/index.tsx +0 -0
  320. /package/templates/{web/src/system → src/system/web}/pages/oplog/index.tsx +0 -0
  321. /package/templates/{web/src/system → src/system/web}/pages/roles/index.tsx +0 -0
  322. /package/templates/{web/src/system → src/system/web}/pages/settings/index.tsx +0 -0
  323. /package/templates/{web/src/system → src/system/web}/pages/users/index.tsx +0 -0
  324. /package/templates/{web/src/system → src/system/web}/pages/users/roles.tsx +0 -0
  325. /package/templates/{api/src/web → src/web/api}/get-async-routes/api.ts +0 -0
  326. /package/templates/{api/src/web → src/web/api}/hello/api.ts +0 -0
  327. /package/templates/{api/src/web → src/web/api}/manifest.yaml +0 -0
  328. /package/templates/{api/src/web → src/web/api}/user-info/api.ts +0 -0
  329. /package/templates/{web/src → src/web}/web/__client/api.schemas.ts +0 -0
  330. /package/templates/{web/src → src/web}/web/__client/api.ts +0 -0
  331. /package/templates/{api/tests → tests}/l1-builder.test.ts +0 -0
  332. /package/templates/{api/tests → tests}/rbac-tables.spec.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { IndexRow, TaskRecord } from "../types";
2
2
  import { Alert, Button, Modal, Progress, Space, Typography } from "antd";
3
- import React, { useEffect, useState } from "react";
3
+ import React, { useEffect, useRef, useState } from "react";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { useMarketClient } from "../api/context";
6
6
  import { useInstallTask } from "../hooks/useMarket";
@@ -18,6 +18,17 @@ export interface InstallDialogProps {
18
18
 
19
19
  const isTerminal = (r: TaskRecord | null) => r != null && r.status !== "running";
20
20
 
21
+ /**
22
+ * 阶段失败指引(契约附录 A 的 `lifecycle.stage.*` key)→ 本模块文案。
23
+ * 附录 A 的这批 key 在模板 locales 里尚未落地,直接 t() 会把裸 key 显示给运维,
24
+ * 故此处显式映射;未收录的 key 保持原样(不吞信息)。
25
+ */
26
+ const HINT_KEYS: Record<string, string> = {
27
+ "lifecycle.stage.smoke.hint": "oj-market:task:hintSmoke",
28
+ "lifecycle.stage.cancelled": "oj-market:task:hintCancelled",
29
+ "lifecycle.stage.reloading.hint": "oj-market:task:hintReloading",
30
+ };
31
+
21
32
  /**
22
33
  * 安装/升级/回滚对话框:触发 POST install → 800ms 轮询 TaskRecord 终态渲染(reason+retryable+hintKey 双语)。
23
34
  * 回滚 = 对已装旧版降级安装(显式 version);降版迁移差异校验(R12)的可读失败由终态 error 渲染。
@@ -27,7 +38,13 @@ export function InstallDialog({ row, open, onClose, onDone, version, mode }: Ins
27
38
  const client = useMarketClient();
28
39
  const [taskId, setTaskId] = useState<string | null>(null);
29
40
  const [started, setStarted] = useState(false);
41
+ const [trusting, setTrusting] = useState(false);
42
+ const [trustError, setTrustError] = useState<string | null>(null);
30
43
  const { record, done } = useInstallTask(taskId);
44
+ // onDone 对同一任务只通告一次:父级每次渲染都会换 onDone 身份,若只靠 deps 触发,
45
+ // 终态后 onDone → index.retry() → 父级重渲染 → onDone 身份变 → 再触发,会形成
46
+ // 无限请求循环(浏览器侧表现为 ERR_INSUFFICIENT_RESOURCES)。
47
+ const notifiedTaskId = useRef<string | null>(null);
31
48
 
32
49
  const targetVersion = version ?? row?.latest ?? null;
33
50
  const title
@@ -49,15 +66,43 @@ export function InstallDialog({ row, open, onClose, onDone, version, mode }: Ins
49
66
  if (!open) {
50
67
  setTaskId(null);
51
68
  setStarted(false);
69
+ setTrustError(null);
70
+ notifiedTaskId.current = null;
52
71
  }
53
72
  }, [open, row, started, client, targetVersion]);
54
73
 
55
74
  useEffect(() => {
56
- if (record && isTerminal(record) && done)
57
- onDone?.(record);
75
+ if (!record || !isTerminal(record) || !done)
76
+ return;
77
+ if (notifiedTaskId.current === record.id)
78
+ return;
79
+ notifiedTaskId.current = record.id;
80
+ onDone?.(record);
58
81
  }, [record, done, onDone]);
59
82
 
83
+ // TOFU 确认:确认入库后重试同一安装(服务端 staging 未清场,续跑不重下)
84
+ const handleTrustConfirm = async () => {
85
+ if (taskId === null || taskId.startsWith("__error__"))
86
+ return;
87
+ setTrusting(true);
88
+ setTrustError(null);
89
+ try {
90
+ await client.trust(taskId);
91
+ notifiedTaskId.current = null;
92
+ setTaskId(null);
93
+ setStarted(false);
94
+ }
95
+ catch (e) {
96
+ setTrustError(e instanceof Error ? e.message : String(e));
97
+ }
98
+ finally {
99
+ setTrusting(false);
100
+ }
101
+ };
102
+
60
103
  const terminal = isTerminal(record);
104
+ const needsTrust = record?.status === "needs_trust";
105
+ const succeeded = record?.status === "done";
61
106
  const failed = record?.status === "failed" || record?.status === "partial";
62
107
  const errorTask = typeof taskId === "string" && taskId.startsWith("__error__");
63
108
 
@@ -78,9 +123,35 @@ export function InstallDialog({ row, open, onClose, onDone, version, mode }: Ins
78
123
  )}
79
124
  {record && (
80
125
  <>
81
- <Progress percent={record.progress} status={terminal ? (failed ? "exception" : "success") : "active"} />
126
+ <Progress percent={record.progress} status={terminal ? (succeeded ? "success" : "exception") : "active"} />
82
127
  <div data-testid="install-stage">{record.stage ? t(`oj-market:task:stage.${record.stage}`, record.stage) : record.stage}</div>
83
128
  <div data-testid="install-message">{record.message}</div>
129
+ {needsTrust && record?.trust && (
130
+ <Alert
131
+ style={{ marginTop: 12 }}
132
+ type="warning"
133
+ showIcon
134
+ message={t("oj-market:task:trustTitle")}
135
+ description={(
136
+ <Space direction="vertical" size={4}>
137
+ <span>{t("oj-market:task:trustBody", { keyId: record.trust.key_id })}</span>
138
+ <span data-testid="install-trust-fingerprint">
139
+ {t("oj-market:task:trustFingerprint")}
140
+ <Typography.Text code copyable={{ text: record.trust.fingerprint }}>
141
+ {record.trust.fingerprint}
142
+ </Typography.Text>
143
+ </span>
144
+ <span>{t("oj-market:task:trustHint")}</span>
145
+ </Space>
146
+ )}
147
+ />
148
+ )}
149
+ {needsTrust && trustError && <Alert style={{ marginTop: 8 }} type="error" showIcon message={trustError} />}
150
+ {needsTrust && (
151
+ <Button type="primary" style={{ marginTop: 12 }} loading={trusting} onClick={handleTrustConfirm}>
152
+ {t("oj-market:task:trustConfirm")}
153
+ </Button>
154
+ )}
84
155
  {failed && record.error && (
85
156
  <Alert
86
157
  type="error"
@@ -89,7 +160,11 @@ export function InstallDialog({ row, open, onClose, onDone, version, mode }: Ins
89
160
  description={(
90
161
  <Space direction="vertical">
91
162
  <span>{record.error.retryable ? t("oj-market:task:retryable") : t("oj-market:task:notRetryable")}</span>
92
- {record.error.hintKey && <span data-testid="install-hint">{t(record.error.hintKey, record.error.hintKey)}</span>}
163
+ {record.error.hintKey && (
164
+ <span data-testid="install-hint">
165
+ {t(HINT_KEYS[record.error.hintKey] ?? record.error.hintKey, record.error.hintKey)}
166
+ </span>
167
+ )}
93
168
  </Space>
94
169
  )}
95
170
  />
@@ -40,8 +40,13 @@ export function useInstallTask(taskId: string | null): {
40
40
  const [done, setDone] = useState(false);
41
41
 
42
42
  useEffect(() => {
43
- if (!taskId)
43
+ // 无任务 id = 尚无任务:清空上一次任务的记录,避免「重新安装/信任后重试」时
44
+ // 旧终态(可能是 needs_trust)残留在弹窗里被误读成本次结果。
45
+ if (!taskId) {
46
+ setRecord(null);
47
+ setDone(false);
44
48
  return;
49
+ }
45
50
  let active = true;
46
51
  setRecord(null);
47
52
  setDone(false);
@@ -49,12 +49,21 @@
49
49
  "running": "Running",
50
50
  "done": "Done",
51
51
  "failed": "Failed",
52
- "partial": "Partial"
52
+ "partial": "Partial",
53
+ "needs_trust": "Awaiting trust"
53
54
  },
55
+ "trustTitle": "Trust confirmation required: publisher key not in host trust store",
56
+ "trustBody": "The signing key of publisher \"{{keyId}}\" is not trusted by this host yet (first-use TOFU).",
57
+ "trustFingerprint": "Key fingerprint: ",
58
+ "trustHint": "Compare this fingerprint with the one published by the vendor; confirm only if they match. Confirming retries this install automatically and reuses the staged files.",
59
+ "trustConfirm": "Fingerprint matches — trust and retry",
54
60
  "reason": "Reason",
55
61
  "retryable": "Retryable",
56
62
  "notRetryable": "Not retryable",
57
63
  "hint": "Hint",
64
+ "hintSmoke": "Smoke probe failures usually mean one of two things: (1) the anonymous endpoints added by this install (auth.anonymous_paths) are pending a restart — restart the host and retry; (2) in dev the host already ships a module with the same name, so the route belongs to the source module and the probe is not hitting the freshly installed package.",
65
+ "hintCancelled": "This install was cancelled: lock file, version directory and staging were restored to their pre-install state. You can retry directly.",
66
+ "hintReloading": "Config hot-reload was partial: hot-applicable sections (vars, ...) are applied, while the auth section (including anonymous endpoints) needs a host restart.",
58
67
  "close": "Close",
59
68
  "viewLog": "View log"
60
69
  },
@@ -49,12 +49,21 @@
49
49
  "running": "进行中",
50
50
  "done": "完成",
51
51
  "failed": "失败",
52
- "partial": "部分完成"
52
+ "partial": "部分完成",
53
+ "needs_trust": "待信任确认"
53
54
  },
55
+ "trustTitle": "待信任确认:发布方密钥不在宿主信任库",
56
+ "trustBody": "发布方「{{keyId}}」的签名密钥尚未被本宿主信任(首次信任 TOFU)。",
57
+ "trustFingerprint": "密钥指纹:",
58
+ "trustHint": "请与发布方公布的公钥指纹逐字核对,一致才确认。确认后会自动重试本次安装,已暂存的内容不会重新下载。",
59
+ "trustConfirm": "指纹一致,信任并重试",
54
60
  "reason": "原因",
55
61
  "retryable": "可重试",
56
62
  "notRetryable": "不可重试",
57
63
  "hint": "提示",
64
+ "hintSmoke": "冒烟探活失败常见于两类原因:① 本次安装新增的匿名端点(auth.anonymous_paths)属「待重启生效」,重启宿主后再点重试即可;② dev 形态下宿主已内置同名模块,该路由由源码模块占位,探活打到的不是刚装的包。",
65
+ "hintCancelled": "本次安装已被取消:锁、版本目录与 staging 均已回到发起前状态,可直接重试。",
66
+ "hintReloading": "配置热更未完全生效:可热改段(vars 等)已应用,auth 段(含匿名端点)需重启宿主后生效。",
58
67
  "close": "关闭",
59
68
  "viewLog": "查看日志"
60
69
  },
@@ -5,8 +5,12 @@
5
5
  /** 安装阶段名(契约附录 A 十阶段逐字 + lock_commit/audit/done 终态) */
6
6
  export type InstallStage = "preflight" | "downloading" | "verifying" | "extracting" | "migrating" | "lock_commit" | "registering" | "deploying_web" | "reloading" | "smoke" | "audit" | "done";
7
7
 
8
- /** 任务状态(§10.2 三态 + partial:锁后失败部分生效) */
9
- export type TaskStatus = "running" | "done" | "failed" | "partial";
8
+ /**
9
+ * 任务状态(§10.2 三态 + partial:锁后失败部分生效 + needs_trust:未知发布方 key 待人工
10
+ * TOFU 确认,staging 不清场,确认入库后重试同一安装即可续跑)。
11
+ * needs_trust 是非成功态:消费面不得按绿色成功渲染(真源 api/src/_platform/_lifecycle/types.ts:64)。
12
+ */
13
+ export type TaskStatus = "running" | "done" | "failed" | "partial" | "needs_trust";
10
14
 
11
15
  /** 阶段明细日志(UI 详情日志区数据源) */
12
16
  export interface TaskStageLog {
@@ -22,6 +26,13 @@ export interface TaskError {
22
26
  hintKey?: string
23
27
  }
24
28
 
29
+ /** needs_trust 终态:待确认的发布方 key(指纹 = sha256(public_key) 十六进制,供人核对) */
30
+ export interface TaskTrust {
31
+ key_id: string
32
+ public_key: string
33
+ fingerprint: string
34
+ }
35
+
25
36
  /** 安装任务记录(§10.2 + stages 明细日志;落 .install-tasks/<id>.json,800ms 轮询消费面) */
26
37
  export interface TaskRecord {
27
38
  id: string
@@ -34,6 +45,8 @@ export interface TaskRecord {
34
45
  message: string
35
46
  stages: TaskStageLog[]
36
47
  error?: TaskError
48
+ /** needs_trust 终态才有:待确认的发布方 key(POST /market/trust {task_id} 消费) */
49
+ trust?: TaskTrust
37
50
  startedAt: number
38
51
  finishedAt?: number
39
52
  appliedSeq?: number
@@ -1,7 +1,7 @@
1
- import { respond } from "../../_platform/_shared/respond";
1
+ import { respond } from "#/_platform/_shared/respond";
2
2
  // GET /api/system/login-methods —— 登录方式发现(C5/D2;匿名端点:登录前无 token,
3
3
  // 项目 config.yaml auth.anonymous_paths 必须列 /system/login-methods,漏列则握手 401 登录页必坏)。
4
- import { listLoginMethods } from "../../_platform/_shared/service/domain/settings";
4
+ import { listLoginMethods } from "#/_platform/_shared/service/domain/settings";
5
5
 
6
6
  async function get() {
7
7
  await respond(async () => {
@@ -0,0 +1,6 @@
1
+ name: system
2
+ desc: 框架管理域端点(/api/system/*):角色/权限点管理(assertSystemAdmin 判权,H2)
3
+ version: 0.1.0
4
+ deps: # 两处都用:roles/bindings/permissions 读写 _platform 的 sys_* 表(ownership_guard: deny);
5
+ # 跨模块别名 `#/_platform/…` 的依赖门禁(oj build S008)
6
+ _platform: ^0.1.0
@@ -1,9 +1,9 @@
1
- import { respond } from "../../_platform/_shared/respond";
1
+ import { respond } from "#/_platform/_shared/respond";
2
2
  // GET /api/system/oplog?action=&username=&module=&limit= —— 操作日志查询(AC1-29;D13 admin 可查)。
3
3
  // POST /api/system/oplog —— 操作日志写入(C3;登录态即可,解决方案模块记录自身操作)。
4
- import { assertSystemAdmin, currentAccess } from "../../_platform/_shared/service/infra/access";
5
- import { recordOp } from "../../_platform/_shared/service/infra/audit";
6
- import { searchOplog } from "../../_platform/_shared/service/infra/oplog";
4
+ import { assertSystemAdmin, currentAccess } from "#/_platform/_shared/service/infra/access";
5
+ import { recordOp } from "#/_platform/_shared/service/infra/audit";
6
+ import { searchOplog } from "#/_platform/_shared/service/infra/oplog";
7
7
 
8
8
  async function get() {
9
9
  await respond(async () => {
@@ -1,7 +1,7 @@
1
- import { respond } from "../../_platform/_shared/respond";
2
- import { listPermissions } from "../../_platform/_shared/service/domain/roles";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { listPermissions } from "#/_platform/_shared/service/domain/roles";
3
3
  // GET /api/system/permissions —— 权限点全量(C2 绑定编辑器数据源,deprecated 标灰)。
4
- import { assertSystemAdmin } from "../../_platform/_shared/service/infra/access";
4
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
5
5
 
6
6
  async function get() {
7
7
  await respond(async () => {
@@ -1,8 +1,8 @@
1
- import { respond } from "../../_platform/_shared/respond";
2
- import { createRole, deleteRole, listRoles } from "../../_platform/_shared/service/domain/roles";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { createRole, deleteRole, listRoles } from "#/_platform/_shared/service/domain/roles";
3
3
  // 管理域端点 /api/system/roles(设计文档 D207:/api/system/* = 管理域,assertSystemAdmin 判权)。
4
4
  // handler 层只编排:守卫 → service → json 信封;name 走 query(wiki 先例:静态段 + http.query)。
5
- import { assertSystemAdmin } from "../../_platform/_shared/service/infra/access";
5
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
6
6
 
7
7
  async function guard(): Promise<void> {
8
8
  await assertSystemAdmin();
@@ -1,9 +1,9 @@
1
- import { respond } from "../../../_platform/_shared/respond";
2
- import { updateBindings } from "../../../_platform/_shared/service/domain/roles";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { updateBindings } from "#/_platform/_shared/service/domain/roles";
3
3
  // PUT /api/system/roles/bindings?name=xxx —— 整集替换角色绑定。
4
4
  // AC1-18 声明角色绑定可调整;AC1-19 builtin 硬拒(service 层);AC1-30 摘绑定 = 紧急吊销出口
5
5
  // (service 内写后按持有者失效判权缓存)。
6
- import { assertSystemAdmin } from "../../../_platform/_shared/service/infra/access";
6
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
7
7
 
8
8
  async function put() {
9
9
  await respond(async () => {
@@ -1,7 +1,7 @@
1
- import { respond } from "../../_platform/_shared/respond";
2
- import { listSettings, updateSetting } from "../../_platform/_shared/service/domain/settings";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { listSettings, updateSetting } from "#/_platform/_shared/service/domain/settings";
3
3
  // /api/system/settings —— 系统设置(PRD §4.3):GET 按组列出(secret 掩码),PUT 写值(写审计)。
4
- import { assertSystemAdmin } from "../../_platform/_shared/service/infra/access";
4
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
5
5
 
6
6
  const settingItemSchema = {
7
7
  type: "object",
@@ -1,9 +1,9 @@
1
- import { respond } from "../../_platform/_shared/respond";
2
- import { createUser, listUsers } from "../../_platform/_shared/service/domain/users";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { createUser, listUsers } from "#/_platform/_shared/service/domain/users";
3
3
  // 管理域端点组 /api/system/users(AC1-7~10):handler 只编排——assertSystemAdmin 守卫 → service → json。
4
4
  // 保护红线在 service 层硬 enforcement:禁止操作自己、admin 不碰成员资格、最后 superadmin 兜底。
5
5
  // 子端点:roles/password/forbidden 各为独立目录(wiki per-endpoint 先例)。
6
- import { assertSystemAdmin } from "../../_platform/_shared/service/infra/access";
6
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
7
7
 
8
8
  const bcryptDeps = { bcryptHash: (pw: string) => bcrypt.hash(pw) };
9
9
 
@@ -1,7 +1,7 @@
1
- import { respond } from "../../../_platform/_shared/respond";
2
- import { setForbidden } from "../../../_platform/_shared/service/domain/users";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { setForbidden } from "#/_platform/_shared/service/domain/users";
3
3
  // PUT /api/system/users/forbidden?uid= —— 禁用/解禁(禁用即删 refresh,撤销即强退)。
4
- import { assertSystemAdmin } from "../../../_platform/_shared/service/infra/access";
4
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
5
5
 
6
6
  async function put() {
7
7
  await respond(async () => {
@@ -1,7 +1,7 @@
1
- import { respond } from "../../../_platform/_shared/respond";
2
- import { changePasswordByAdmin } from "../../../_platform/_shared/service/domain/users";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { changePasswordByAdmin } from "#/_platform/_shared/service/domain/users";
3
3
  // PUT /api/system/users/password?uid= —— 管理员重置口令(must_change=1 + 级联吊销 refresh)。
4
- import { assertSystemAdmin } from "../../../_platform/_shared/service/infra/access";
4
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
5
5
 
6
6
  async function put() {
7
7
  await respond(async () => {
@@ -1,7 +1,7 @@
1
- import { respond } from "../../../_platform/_shared/respond";
2
- import { updateUserRoles } from "../../../_platform/_shared/service/domain/users";
1
+ import { respond } from "#/_platform/_shared/respond";
2
+ import { updateUserRoles } from "#/_platform/_shared/service/domain/users";
3
3
  // PUT /api/system/users/roles?uid= —— 整集替换用户角色(AC1-7;sys_user_role 权威源 + 写时失效)。
4
- import { assertSystemAdmin } from "../../../_platform/_shared/service/infra/access";
4
+ import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
5
5
 
6
6
  async function put() {
7
7
  await respond(async () => {
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": [
3
+ "../tsconfig.json",
4
+ "../tsconfig.paths.json"
5
+ ],
6
+ "include": [
7
+ ".",
8
+ "../global.d.ts",
9
+ "../env.d.ts",
10
+ "../types"
11
+ ],
12
+ "exclude": [
13
+ "*/web",
14
+ "*/web/**"
15
+ ]
16
+ }
@@ -4,8 +4,8 @@
4
4
  /* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
5
5
  import { afterEach, beforeAll, describe, expect, it } from "vitest";
6
6
 
7
- import { esc, firstAttr } from "../src/auth/_shared/ldap";
8
- import { createLdapLogin } from "../src/auth/_shared/ldap-login";
7
+ import { esc, firstAttr } from "../src/auth/api/_shared/ldap";
8
+ import { createLdapLogin } from "../src/auth/api/_shared/ldap-login";
9
9
  import { installDb } from "./fixture";
10
10
 
11
11
  let dbo: ReturnType<typeof installDb>;
@@ -1,11 +1,11 @@
1
1
  // BDD:登录链——B1 登录顺序(D14 统一 401)、B2 首登改密(AC1-27)、B3 refresh 轮换/reuse 检测(AC1-13)、B4 JWT 仅 sub。
2
2
  // deps 全注入(Node 侧 crypto 只读不可 stub,设计 §9.1);fake bcrypt 以 `hashed:<pw>` 为口令哈希约定。
3
3
  /* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
4
- import type { SessionDeps } from "../src/auth/_shared/session";
4
+ import type { SessionDeps } from "../src/auth/api/_shared/session";
5
5
 
6
6
  import { afterEach, beforeAll, describe, expect, it } from "vitest";
7
- import { assertPermission } from "../src/_platform/_shared/service/infra/access";
8
- import { createSession } from "../src/auth/_shared/session";
7
+ import { assertPermission } from "../src/_platform/api/_shared/service/infra/access";
8
+ import { createSession } from "../src/auth/api/_shared/session";
9
9
  import { installDb } from "./fixture";
10
10
 
11
11
  let dbo: ReturnType<typeof installDb>;
@@ -5,7 +5,7 @@
5
5
  /* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
6
6
  import { afterEach, beforeAll, describe, expect, it } from "vitest";
7
7
 
8
- import { loginBlocked, loginFailed, loginSucceeded, resetLoginThrottle } from "../src/_platform/_shared/service/infra/rate";
8
+ import { loginBlocked, loginFailed, loginSucceeded, resetLoginThrottle } from "../src/_platform/api/_shared/service/infra/rate";
9
9
  import { installDb } from "./fixture";
10
10
 
11
11
  let dbo: ReturnType<typeof installDb>;