@oj-module/cli 0.2.64 → 0.2.67

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 (369) hide show
  1. package/bin/.oj-version +1 -0
  2. package/bin/oj +4 -0
  3. package/devkit/README.md +18 -4
  4. package/devkit/SKILL.md +35 -3
  5. package/devkit/framework-dev.md +22 -11
  6. package/devkit/manual.md +161 -68
  7. package/devkit/menu-rules.md +4 -1
  8. package/devkit/publish-walkthrough.md +110 -37
  9. package/devkit/wecom-internal-app.md +7 -2
  10. package/devkit/wecom-multi-corp-links.md +163 -0
  11. package/package.json +3 -2
  12. package/shell-dist/assets/ahooks.2l850ymmh0.js +18 -0
  13. package/shell-dist/assets/antd-es-locale-zh_CN.1gjjsvxbf0.js +1 -0
  14. package/shell-dist/assets/antd-img-crop.196rkty480.js +99 -0
  15. package/shell-dist/assets/antd-locale-en_US.561tozx860.js +1 -0
  16. package/shell-dist/assets/antd-locale-zh_CN.1cmpmgzh70.js +1 -0
  17. package/shell-dist/assets/antd.uw1coq15l0.js +348 -0
  18. package/shell-dist/assets/clsx.jotilrt2e0.js +1 -0
  19. package/shell-dist/assets/contract-errors.2o17vz9u50.js +1 -0
  20. package/shell-dist/assets/contract.3h327o3mj0.js +57 -0
  21. package/shell-dist/assets/cssinjs.atgmhan7m0.js +3 -0
  22. package/shell-dist/assets/dayjs-plugin-advancedFormat.3vsyd2eis0.js +1 -0
  23. package/shell-dist/assets/dayjs-plugin-customParseFormat.13xhghv1d0.js +1 -0
  24. package/shell-dist/assets/dayjs-plugin-isoWeek.1fn1tw82p0.js +1 -0
  25. package/shell-dist/assets/dayjs-plugin-localeData.2rwbjp9nk0.js +1 -0
  26. package/shell-dist/assets/dayjs-plugin-quarterOfYear.2oqo1lcx80.js +1 -0
  27. package/shell-dist/assets/dayjs-plugin-relativeTime.2pqs3et4y0.js +1 -0
  28. package/shell-dist/assets/dayjs-plugin-weekOfYear.gvn9iph080.js +1 -0
  29. package/shell-dist/assets/dayjs-plugin-weekYear.2u78l3ex10.js +1 -0
  30. package/shell-dist/assets/dayjs-plugin-weekday.2d56a4tml0.js +1 -0
  31. package/shell-dist/assets/dayjs.pa60l6wjo0.js +1 -0
  32. package/shell-dist/assets/dnd-kit-core.1xyreig6r0.js +5 -0
  33. package/shell-dist/assets/dnd-kit-sortable.s94qciuft0.js +1 -0
  34. package/shell-dist/assets/dnd-kit-utilities.1umw4xphb0.js +1 -0
  35. package/shell-dist/assets/i18next.33zqofapj0.js +1 -0
  36. package/shell-dist/assets/icons-es-components-Context.365qmflwg0.js +1 -0
  37. package/shell-dist/assets/icons.159wjwals0.js +57 -0
  38. package/shell-dist/assets/{index-xZhmujjM.js → index.6alqyx6ae0.js} +21 -1
  39. package/shell-dist/assets/jsx-dev-runtime.3uibuc82f0.js +14 -0
  40. package/shell-dist/assets/jsx-runtime.h40xu4o5b0.js +14 -0
  41. package/shell-dist/assets/keepalive-for-react.xenu5vam70.js +1 -0
  42. package/shell-dist/assets/kit.37kr8ui390.js +1 -0
  43. package/shell-dist/assets/ky.1cgch7gu60.js +6 -0
  44. package/shell-dist/assets/motion-react.pjsxytvjs0.js +12 -0
  45. package/shell-dist/assets/motion.21tciqutg0.js +4 -0
  46. package/shell-dist/assets/nprogress.2nz76n9ny0.js +7 -0
  47. package/shell-dist/assets/ojm-dayjs-locale-zh-cn.3vr3beiyp0.js +9 -0
  48. package/shell-dist/assets/pinyin-pro.3v0mnxczn0.js +1 -0
  49. package/shell-dist/assets/pro-components.2kyot1vcl0.js +83 -0
  50. package/shell-dist/assets/react-countup.2x8idnr8y0.js +10 -0
  51. package/shell-dist/assets/react-dom-client.ick0v05ob0.js +43 -0
  52. package/shell-dist/assets/react-dom.2so9uxg3f0.js +22 -0
  53. package/shell-dist/assets/react-error-boundary.2dncdfj3b0.js +1 -0
  54. package/shell-dist/assets/react-i18next.auhvjhqv00.js +1 -0
  55. package/shell-dist/assets/react-jss.1ei6dr9e00.js +29 -0
  56. package/shell-dist/assets/react-query.3rln45ow00.js +1 -0
  57. package/shell-dist/assets/react-router-dom.3c6zld8h40.js +44 -0
  58. package/shell-dist/assets/react-router.2h9rebcv50.js +56 -0
  59. package/shell-dist/assets/react.1ew63mwts0.js +14 -0
  60. package/shell-dist/assets/runtime.2dgstpjsu0.js +21702 -0
  61. package/shell-dist/assets/simplebar-react.2g739uvai0.js +1 -0
  62. package/shell-dist/assets/spin-delay.yjeyj6iwp0.js +9 -0
  63. package/shell-dist/assets/tailwind-merge.125ehiqjw0.js +1 -0
  64. package/shell-dist/assets/use-sync-external-store-shim.1nz1pi9bb0.js +22 -0
  65. package/shell-dist/assets/zustand-middleware.1xaxjueme0.js +6 -0
  66. package/shell-dist/assets/zustand-react-shallow.pybayv1hx0.js +1 -0
  67. package/shell-dist/assets/zustand-react.9fsl9brxy0.js +1 -0
  68. package/shell-dist/assets/zustand-shallow.6cz0yyv9x0.js +1 -0
  69. package/shell-dist/assets/zustand-vanilla-shallow.3424monv50.js +1 -0
  70. package/shell-dist/assets/zustand-vanilla.1mo3ka3g30.js +1 -0
  71. package/shell-dist/assets/zustand.3gjgzlnqo0.js +1 -0
  72. package/shell-dist/index.html +67 -118
  73. package/shell-dist/versions.json +3 -3
  74. package/src/__tests__/publish-keygen.test.ts +157 -0
  75. package/src/__tests__/templates-migration-schema-parity.test.ts +540 -0
  76. package/src/__tests__/templates-schema-columns.test.ts +15 -2
  77. package/src/__tests__/templates-tenant-scope.test.ts +6 -2
  78. package/src/bundle.ts +8 -3
  79. package/src/cli.ts +17 -5
  80. package/src/dev.ts +15 -10
  81. package/src/esm-exports.ts +152 -70
  82. package/src/install.ts +11 -4
  83. package/src/keygen.ts +54 -0
  84. package/src/lifecycle/__tests__/bundle.test.ts +21 -3
  85. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/manifest.yaml +1 -1
  86. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/migrations/0001__init.sql +2 -2
  87. package/src/lifecycle/__tests__/fixtures/fixture-valid/api/src/demo-solution/schema.yaml +5 -2
  88. package/src/lifecycle/__tests__/fixtures/fixture-valid/manifest.yaml +1 -1
  89. package/src/lifecycle/__tests__/manifest-contract.test.ts +75 -3
  90. package/src/lifecycle/__tests__/smoke.test.ts +2 -2
  91. package/src/manifest-contract.ts +91 -8
  92. package/src/market/bootstrap.ts +26 -2
  93. package/src/market/command.ts +1 -0
  94. package/src/market/publish.ts +5 -1
  95. package/src/market/walkthrough.ts +24 -8
  96. package/src/shared-deps.ts +69 -19
  97. package/src/site-base.ts +4 -0
  98. package/src/site.ts +2 -0
  99. package/src/usage.ts +8 -4
  100. package/src/vendor.ts +5 -1
  101. package/templates/config.yaml +4 -2
  102. package/templates/init.include.yaml +8 -3
  103. package/templates/openapi.json +460 -1
  104. package/templates/src/app/api/_platform/_lifecycle/compensate.ts +136 -0
  105. package/templates/src/app/api/_platform/_lifecycle/installer.ts +71 -22
  106. package/templates/src/app/api/_platform/_lifecycle/lock.ts +23 -0
  107. package/templates/src/app/api/_platform/_lifecycle/steps/deploy-web.ts +28 -0
  108. package/templates/src/app/api/_platform/_lifecycle/steps/preflight.ts +46 -0
  109. package/templates/src/app/api/_platform/_lifecycle/steps/reload.ts +100 -36
  110. package/templates/src/app/api/_platform/_lifecycle/steps/smoke.ts +7 -15
  111. package/templates/src/app/api/_platform/_lifecycle/text-edit.ts +71 -19
  112. package/templates/src/app/api/_platform/_lifecycle/types.ts +26 -2
  113. package/templates/src/app/api/_platform/_lifecycle/uninstall.ts +93 -14
  114. package/templates/src/app/api/_platform/_shared/service/domain/settings.ts +8 -4
  115. package/templates/src/app/api/_platform/manifest.yaml +1 -0
  116. package/templates/src/app/api/_platform/market/api.ts +235 -10
  117. package/templates/src/app/api/_platform/migrations/0001__baseline.mysql.sql +178 -0
  118. package/templates/src/app/api/_platform/migrations/0001__baseline.pg.sql +173 -0
  119. package/templates/src/app/api/_platform/migrations/0001__baseline.sql +188 -0
  120. package/templates/src/app/api/_platform/migrations/0002__market_release.mysql.sql +17 -0
  121. package/templates/src/app/api/_platform/migrations/0002__market_release.pg.sql +16 -0
  122. package/templates/src/app/api/_platform/migrations/0002__market_release.sql +33 -0
  123. package/templates/src/app/api/_platform/schema.yaml +18 -0
  124. package/templates/src/app/api/_platform/seed.mysql.sql +10 -0
  125. package/templates/src/app/api/_platform/seed.pg.sql +10 -0
  126. package/templates/src/app/api/auth/_shared/wecom/client.ts +24 -4
  127. package/templates/src/app/api/home/migrations/0001__create_home_tables.mysql.sql +14 -0
  128. package/templates/src/app/api/home/migrations/0001__create_home_tables.pg.sql +14 -0
  129. package/templates/src/app/api/home/migrations/0002__tenant.pg.sql +4 -0
  130. package/templates/src/app/api/home/seed.mysql.sql +71 -0
  131. package/templates/src/app/api/home/seed.pg.sql +71 -0
  132. package/templates/src/app/api/notification/_shared/notify.ts +6 -6
  133. package/templates/src/app/api/notification/migrations/0001__create_notifications.mysql.sql +11 -0
  134. package/templates/src/app/api/notification/migrations/0001__create_notifications.pg.sql +11 -0
  135. package/templates/src/app/api/notification/migrations/0002__notifications_user.mysql.sql +8 -0
  136. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.mysql.sql +21 -0
  137. package/templates/src/app/api/notification/migrations/0003__notifications_broadcast.pg.sql +22 -0
  138. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.mysql.sql +10 -0
  139. package/templates/src/app/api/notification/migrations/0004__notifications_broadcast_hidden.pg.sql +11 -0
  140. package/templates/src/app/api/notification/migrations/0005__tenant.pg.sql +6 -0
  141. package/templates/src/app/api/notification/seed.mysql.sql +8 -0
  142. package/templates/src/app/api/notification/seed.pg.sql +11 -0
  143. package/templates/src/app/api/publish/_shared/identity.ts +69 -0
  144. package/templates/src/app/api/publish/api.ts +349 -0
  145. package/templates/src/app/api/publish/manifest.yaml +8 -0
  146. package/templates/src/app/api/publish/migrations/0001__publish_credential.mysql.sql +23 -0
  147. package/templates/src/app/api/publish/migrations/0001__publish_credential.pg.sql +23 -0
  148. package/templates/src/app/api/publish/migrations/0001__publish_credential.sql +39 -0
  149. package/templates/src/app/api/publish/schema.yaml +33 -0
  150. package/templates/src/app/api/system/login-methods/api.ts +2 -1
  151. package/templates/src/app/web/_platform/__client/api.schemas.ts +15 -0
  152. package/templates/src/app/web/_platform/__client/index.ts +25 -1
  153. package/templates/src/app/web/entry.ts +9 -5
  154. package/templates/src/app/web/home/pages/components/bar-chart.tsx +5 -3
  155. package/templates/src/app/web/home/pages/components/echarts-setup.ts +30 -0
  156. package/templates/src/app/web/home/pages/components/line-chart.tsx +5 -3
  157. package/templates/src/app/web/home/pages/components/pie-chart.tsx +6 -3
  158. package/templates/src/app/web/home/pages/index.tsx +3 -2
  159. package/templates/src/app/web/home/routes.ts +8 -2
  160. package/templates/src/app/web/login/locales/en-US.json +7 -1
  161. package/templates/src/app/web/login/locales/zh-CN.json +7 -1
  162. package/templates/src/app/web/login/pages/login.tsx +79 -86
  163. package/templates/src/app/web/login/routes.ts +54 -1
  164. package/templates/src/app/web/personal-center/locales/en-US.json +1 -0
  165. package/templates/src/app/web/personal-center/locales/zh-CN.json +1 -0
  166. package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +5 -0
  167. package/templates/src/app/web/system/__client/api.schemas.ts +2 -1
  168. package/templates/src/app/web/system/locales/en-US.json +1 -8
  169. package/templates/src/app/web/system/locales/zh-CN.json +1 -8
  170. package/templates/src/app/web/system/pages/settings/index.tsx +17 -4
  171. package/templates/src/app/web/system/routes.ts +0 -6
  172. package/templates/src/oj-market/web/__tests__/CardGrid.test.tsx +33 -0
  173. package/templates/src/oj-market/web/__tests__/DetailDrawer.test.tsx +69 -0
  174. package/templates/src/oj-market/web/__tests__/marketClient.fake.ts +7 -1
  175. package/templates/src/oj-market/web/api/client.ts +3 -0
  176. package/templates/src/oj-market/web/api/defaultClient.ts +5 -0
  177. package/templates/src/oj-market/web/components/CardItem.tsx +44 -1
  178. package/templates/src/oj-market/web/components/DetailDrawer.tsx +17 -1
  179. package/templates/src/oj-market/web/entry.ts +31 -2
  180. package/templates/src/oj-market/web/locales/en-US.json +5 -1
  181. package/templates/src/oj-market/web/locales/zh-CN.json +5 -1
  182. package/templates/src/oj-market/web/publish/__client/api.schemas.ts +61 -0
  183. package/templates/src/oj-market/web/publish/__client/index.ts +164 -0
  184. package/templates/src/oj-market/web/publish/locales/en-US.json +80 -0
  185. package/templates/src/oj-market/web/publish/locales/zh-CN.json +80 -0
  186. package/templates/src/oj-market/web/publish/pages/history.tsx +112 -0
  187. package/templates/src/oj-market/web/publish/pages/index.tsx +196 -0
  188. package/templates/src/oj-market/web/publish/pages/model.ts +52 -0
  189. package/templates/src/oj-market/web/publish/pages/token-modal.tsx +82 -0
  190. package/templates/src/oj-market/web/publish/routes.ts +41 -0
  191. package/templates/src/oj-market/web/types.ts +30 -0
  192. package/templates/tests/lifecycle/compensate.spec.ts +207 -0
  193. package/templates/tests/lifecycle/deploy-smoke.spec.ts +38 -14
  194. package/templates/tests/lifecycle/installer.spec.ts +28 -9
  195. package/templates/tests/lifecycle/market-api.spec.ts +164 -12
  196. package/templates/tests/lifecycle/preflight.spec.ts +68 -0
  197. package/templates/tests/lifecycle/role-title-translate.spec.ts +2 -32
  198. package/templates/tests/lifecycle/text-edit.spec.ts +45 -27
  199. package/templates/tests/lifecycle/uninstall.spec.ts +36 -0
  200. package/templates/tests/publish-credential.spec.ts +354 -0
  201. package/templates/tests/publish-identity.spec.ts +44 -0
  202. package/templates/tests/wecom-client-timeout.spec.ts +33 -3
  203. package/templates/tests/wecom-landing.spec.ts +63 -1
  204. package/templates/tsconfig.paths.json +1 -0
  205. package/templates/web.config.ts +6 -4
  206. package/vendor/host-versions.json +3 -3
  207. package/shell-dist/assets/ahooks.js +0 -6909
  208. package/shell-dist/assets/antd-es-locale-zh_CN.js +0 -257
  209. package/shell-dist/assets/antd-img-crop.js +0 -1495
  210. package/shell-dist/assets/antd-locale-en_US.js +0 -374
  211. package/shell-dist/assets/antd-locale-zh_CN.js +0 -379
  212. package/shell-dist/assets/antd.js +0 -106874
  213. package/shell-dist/assets/clsx.js +0 -33
  214. package/shell-dist/assets/contract-errors.js +0 -30
  215. package/shell-dist/assets/contract.js +0 -18900
  216. package/shell-dist/assets/cssinjs.js +0 -2595
  217. package/shell-dist/assets/dayjs-plugin-advancedFormat.js +0 -98
  218. package/shell-dist/assets/dayjs-plugin-customParseFormat.js +0 -173
  219. package/shell-dist/assets/dayjs-plugin-isoWeek.js +0 -77
  220. package/shell-dist/assets/dayjs-plugin-localeData.js +0 -126
  221. package/shell-dist/assets/dayjs-plugin-quarterOfYear.js +0 -77
  222. package/shell-dist/assets/dayjs-plugin-relativeTime.js +0 -92
  223. package/shell-dist/assets/dayjs-plugin-weekOfYear.js +0 -73
  224. package/shell-dist/assets/dayjs-plugin-weekYear.js +0 -63
  225. package/shell-dist/assets/dayjs-plugin-weekday.js +0 -63
  226. package/shell-dist/assets/dayjs.js +0 -326
  227. package/shell-dist/assets/dnd-kit-core.js +0 -3601
  228. package/shell-dist/assets/dnd-kit-sortable.js +0 -717
  229. package/shell-dist/assets/dnd-kit-utilities.js +0 -340
  230. package/shell-dist/assets/i18next.js +0 -2321
  231. package/shell-dist/assets/icons-es-components-Context.js +0 -20
  232. package/shell-dist/assets/icons.js +0 -34961
  233. package/shell-dist/assets/jsx-dev-runtime.js +0 -75
  234. package/shell-dist/assets/jsx-runtime.js +0 -97
  235. package/shell-dist/assets/keepalive-for-react.js +0 -283
  236. package/shell-dist/assets/kit.js +0 -151
  237. package/shell-dist/assets/ky.js +0 -1427
  238. package/shell-dist/assets/motion-react.js +0 -13589
  239. package/shell-dist/assets/motion.js +0 -9959
  240. package/shell-dist/assets/nprogress.js +0 -314
  241. package/shell-dist/assets/ojm--ant-design-icons-es-icons-BarsOutlined.js +0 -7
  242. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CalendarOutlined.js +0 -7
  243. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownFilled.js +0 -7
  244. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretDownOutlined.js +0 -7
  245. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CaretUpOutlined.js +0 -7
  246. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckCircleFilled.js +0 -7
  247. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CheckOutlined.js +0 -7
  248. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ClockCircleOutlined.js +0 -7
  249. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseCircleFilled.js +0 -7
  250. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CloseOutlined.js +0 -7
  251. package/shell-dist/assets/ojm--ant-design-icons-es-icons-CopyOutlined.js +0 -7
  252. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DeleteOutlined.js +0 -7
  253. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleLeftOutlined.js +0 -7
  254. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DoubleRightOutlined.js +0 -7
  255. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownOutlined.js +0 -7
  256. package/shell-dist/assets/ojm--ant-design-icons-es-icons-DownloadOutlined.js +0 -7
  257. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EditOutlined.js +0 -7
  258. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EllipsisOutlined.js +0 -7
  259. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EnterOutlined.js +0 -7
  260. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ExclamationCircleFilled.js +0 -7
  261. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeInvisibleOutlined.js +0 -7
  262. package/shell-dist/assets/ojm--ant-design-icons-es-icons-EyeOutlined.js +0 -7
  263. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileOutlined.js +0 -7
  264. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FileTextOutlined.js +0 -7
  265. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FilterFilled.js +0 -7
  266. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOpenOutlined.js +0 -7
  267. package/shell-dist/assets/ojm--ant-design-icons-es-icons-FolderOutlined.js +0 -7
  268. package/shell-dist/assets/ojm--ant-design-icons-es-icons-HolderOutlined.js +0 -7
  269. package/shell-dist/assets/ojm--ant-design-icons-es-icons-InfoCircleFilled.js +0 -7
  270. package/shell-dist/assets/ojm--ant-design-icons-es-icons-LeftOutlined.js +0 -7
  271. package/shell-dist/assets/ojm--ant-design-icons-es-icons-LoadingOutlined.js +0 -7
  272. package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusOutlined.js +0 -7
  273. package/shell-dist/assets/ojm--ant-design-icons-es-icons-MinusSquareOutlined.js +0 -7
  274. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PaperClipOutlined.js +0 -7
  275. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PictureOutlined.js +0 -7
  276. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusOutlined.js +0 -7
  277. package/shell-dist/assets/ojm--ant-design-icons-es-icons-PlusSquareOutlined.js +0 -7
  278. package/shell-dist/assets/ojm--ant-design-icons-es-icons-QuestionCircleOutlined.js +0 -7
  279. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ReloadOutlined.js +0 -7
  280. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RightOutlined.js +0 -7
  281. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateLeftOutlined.js +0 -7
  282. package/shell-dist/assets/ojm--ant-design-icons-es-icons-RotateRightOutlined.js +0 -7
  283. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SearchOutlined.js +0 -7
  284. package/shell-dist/assets/ojm--ant-design-icons-es-icons-StarFilled.js +0 -7
  285. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapOutlined.js +0 -7
  286. package/shell-dist/assets/ojm--ant-design-icons-es-icons-SwapRightOutlined.js +0 -7
  287. package/shell-dist/assets/ojm--ant-design-icons-es-icons-UpOutlined.js +0 -7
  288. package/shell-dist/assets/ojm--ant-design-icons-es-icons-VerticalAlignTopOutlined.js +0 -7
  289. package/shell-dist/assets/ojm--ant-design-icons-es-icons-WarningFilled.js +0 -7
  290. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomInOutlined.js +0 -7
  291. package/shell-dist/assets/ojm--ant-design-icons-es-icons-ZoomOutOutlined.js +0 -7
  292. package/shell-dist/assets/ojm-dayjs-locale-zh-cn.js +0 -81
  293. package/shell-dist/assets/pinyin-pro.js +0 -25175
  294. package/shell-dist/assets/pro-components.js +0 -44627
  295. package/shell-dist/assets/react-countup.js +0 -525
  296. package/shell-dist/assets/react-dom-client.js +0 -12134
  297. package/shell-dist/assets/react-dom.js +0 -266
  298. package/shell-dist/assets/react-error-boundary.js +0 -141
  299. package/shell-dist/assets/react-i18next.js +0 -1773
  300. package/shell-dist/assets/react-jss.js +0 -4089
  301. package/shell-dist/assets/react-query.js +0 -3072
  302. package/shell-dist/assets/react-router-dom.js +0 -9927
  303. package/shell-dist/assets/react-router.js +0 -14584
  304. package/shell-dist/assets/react.js +0 -590
  305. package/shell-dist/assets/runtime.js +0 -28311
  306. package/shell-dist/assets/simplebar-react.js +0 -1119
  307. package/shell-dist/assets/spin-delay.js +0 -111
  308. package/shell-dist/assets/tailwind-merge.js +0 -3364
  309. package/shell-dist/assets/use-sync-external-store-shim.js +0 -130
  310. package/shell-dist/assets/zustand-middleware.js +0 -513
  311. package/shell-dist/assets/zustand-react-shallow.js +0 -27
  312. package/shell-dist/assets/zustand-react.js +0 -39
  313. package/shell-dist/assets/zustand-shallow.js +0 -22
  314. package/shell-dist/assets/zustand-vanilla-shallow.js +0 -71
  315. package/shell-dist/assets/zustand-vanilla.js +0 -40
  316. package/shell-dist/assets/zustand.js +0 -32
  317. package/templates/seed.mysql.sql +0 -6
  318. package/templates/seed.pg.sql +0 -6
  319. package/templates/src/app/api/_platform/migrations/0001__create_users.mysql.sql +0 -9
  320. package/templates/src/app/api/_platform/migrations/0001__create_users.pg.sql +0 -9
  321. package/templates/src/app/api/_platform/migrations/0001__create_users.sql +0 -7
  322. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.mysql.sql +0 -3
  323. package/templates/src/app/api/_platform/migrations/0002__add_users_avatar_base64.sql +0 -2
  324. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.mysql.sql +0 -5
  325. package/templates/src/app/api/_platform/migrations/0003__users_source_display_name.sql +0 -5
  326. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.mysql.sql +0 -70
  327. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.pg.sql +0 -67
  328. package/templates/src/app/api/_platform/migrations/0004__sys_rbac.sql +0 -67
  329. package/templates/src/app/api/_platform/migrations/0005__users_must_change.mysql.sql +0 -3
  330. package/templates/src/app/api/_platform/migrations/0005__users_must_change.sql +0 -2
  331. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.mysql.sql +0 -3
  332. package/templates/src/app/api/_platform/migrations/0006__users_is_forbidden.sql +0 -3
  333. package/templates/src/app/api/_platform/migrations/0007__users_email.sql +0 -3
  334. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.mysql.sql +0 -10
  335. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.pg.sql +0 -10
  336. package/templates/src/app/api/_platform/migrations/0008__sys_refresh_token.sql +0 -11
  337. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.mysql.sql +0 -12
  338. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.pg.sql +0 -12
  339. package/templates/src/app/api/_platform/migrations/0009__sys_throttle.sql +0 -13
  340. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.mysql.sql +0 -17
  341. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.pg.sql +0 -16
  342. package/templates/src/app/api/_platform/migrations/0010__sys_solution_route.sql +0 -18
  343. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.mysql.sql +0 -2
  344. package/templates/src/app/api/_platform/migrations/0011__sys_setting_group_label.sql +0 -4
  345. package/templates/src/app/api/_platform/migrations/0012__market_history.mysql.sql +0 -13
  346. package/templates/src/app/api/_platform/migrations/0012__market_history.pg.sql +0 -12
  347. package/templates/src/app/api/_platform/migrations/0012__market_history.sql +0 -14
  348. package/templates/src/app/api/_platform/migrations/0013__users_profile.sql +0 -4
  349. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.mysql.sql +0 -9
  350. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.pg.sql +0 -7
  351. package/templates/src/app/api/_platform/migrations/0014__reg_source_seq.sql +0 -8
  352. package/templates/src/app/api/_platform/migrations/0015__tenant.mysql.sql +0 -12
  353. package/templates/src/app/api/_platform/migrations/0015__tenant.pg.sql +0 -11
  354. package/templates/src/app/api/_platform/migrations/0015__tenant.sql +0 -44
  355. package/templates/src/app/api/_platform/migrations/0016__org.mysql.sql +0 -41
  356. package/templates/src/app/api/_platform/migrations/0016__org.pg.sql +0 -40
  357. package/templates/src/app/api/_platform/migrations/0016__org.sql +0 -62
  358. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +0 -7
  359. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +0 -4
  360. package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +0 -8
  361. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +0 -3
  362. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +0 -3
  363. package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +0 -8
  364. package/templates/src/app/web/system/pages/login-methods/index.tsx +0 -30
  365. /package/shell-dist/assets/{nprogress-css.js → nprogress-css.1cq2pzkre0.js} +0 -0
  366. /package/shell-dist/assets/{ojm-antd-es-button.js → ojm-antd-es-button.2uriphio50.js} +0 -0
  367. /package/shell-dist/assets/{ojm-antd-es-modal.js → ojm-antd-es-modal.bf3tgdh8v0.js} +0 -0
  368. /package/shell-dist/assets/{ojm-antd-es-slider.js → ojm-antd-es-slider.xyvptuhid0.js} +0 -0
  369. /package/shell-dist/assets/{ojm-antd-es-upload.js → ojm-antd-es-upload.13gx45e0g0.js} +0 -0
@@ -30,12 +30,6 @@ export interface SmokeContext extends InstallContext {
30
30
  modulesJsonPath: string
31
31
  /** 注册快照查询;缺省回落 queryRegistered(isolate db 全局;测试注入 stub) */
32
32
  query?: (name: string) => Promise<SolutionSnapshot | null>
33
- /**
34
- * 本次安装**新追加**进 config.yaml `auth.anonymous_paths` 的路径(reloading 段注入,带前导 /)。
35
- * 匿名接线属 restart_pending(reload 段已明示),本进程内尚未生效——探活对这些路径的
36
- * 401 判「待重启」而非失败;已在配置里却仍 401 才是真失败(说明接线或守卫有问题)。
37
- */
38
- deferredAnonymous?: string[]
39
33
  }
40
34
 
41
35
  export interface StageResult {
@@ -138,17 +132,15 @@ export async function smoke(ctx: SmokeContext): Promise<StageResult> {
138
132
  if (target !== undefined) {
139
133
  const url = probeUrlOf(ctx.apiPrefix, target);
140
134
  const res = await ctx.fetch(url, { headers: { [PROBE_TENANT_HEADER]: PROBE_TENANT } });
141
- if (health !== undefined && !res.ok) {
142
- // health 探针本就是「无凭证预期 401」(文件头注释:非匿名无凭证预期 401;D14/Q-A:health 不强制)。
143
- // 租户化站点上安装/重装/升级后宿主需重启才能加载新配置(含匿名接线、路由),探针在重启前收 401
144
- // 是 restart_pending 的常态,不是包或站点的问题——一律判 deferred,不计入失败(P2 深检可兜底真异常)。
145
- // 非 401(如 500)仍视为真实失败,正常报错。
146
- const deferred = res.status === 401;
147
- if (deferred) {
148
- notes.push(`探活 ${url} 返回 401:health 端点为无凭证探针,宿主重启加载新配置(路由/匿名接线)后即 2xx——属 restart_pending,重启宿主后生效,不计入失败`);
135
+ if (!res.ok) {
136
+ // 无凭证探针(含租户化站点强制 X-TENANT-ID,仍无业务凭证)收 401 是 restart_pending 常态——
137
+ // 宿主重启加载新配置(路由/匿名接线)后即 2xx,不是包或站点问题,一律判 deferred 不计入失败。
138
+ // 非 401(如 404/500)视为真实失败(P0 §3.5:首个路由 404/连通失败 = 冒烟失败,避免假成功)。
139
+ if (res.status === 401) {
140
+ notes.push(`探活 ${url} 返回 401:无凭证探针,宿主重启加载新配置(路由/匿名接线)后即 2xx——属 restart_pending,重启宿主后生效,不计入失败`);
149
141
  }
150
142
  else {
151
- failures.push({ item: "探活", retryable: true, reason: `health 端点 ${url} 返回 HTTP ${res.status}(C2-33 冒烟探针要求 2xx)` });
143
+ failures.push({ item: "探活", retryable: true, reason: `探针 ${url} 返回 HTTP ${res.status}(期望 2xx;404/5xx 视为冒烟失败)` });
152
144
  }
153
145
  }
154
146
  }
@@ -49,25 +49,6 @@ export function ensureReloadApi(content: string): { content: string, changed: bo
49
49
  return { content: insertAnchor(content, "# ojm:reload", "reload_api: true"), changed: true };
50
50
  }
51
51
 
52
- /**
53
- * 安装序号自增(B-11 reload 触发面;PRD E5 实测先例:vars 段语义值改动可热生效,而
54
- * reloadConfig 的 unchanged 判定基于 config 文档 sha——不落盘变更则热更恒 unchanged)。
55
- * R18 同纪律:纯文本行操作,注释/缩进/键序逐字保留,`ojm_install_seq: N` 整行自增为 N+1
56
- * (行内尾注释原样保留)。键缺失/形状不符 = 可读报错不猜位置(键随模板 config.yaml 发布;
57
- * 用户删行 = 显式退出热更触发,安装器拒绝静默安装)。
58
- */
59
- export function bumpInstallSeq(content: string): { content: string, seq: number } {
60
- const lines = content.split("\n");
61
- const idx = lines.findIndex(l => /^\s*ojm_install_seq\s*:\s*\d+\s*(?:#.*)?$/.test(l));
62
- if (idx === -1) {
63
- throw new Error("text-edit: config.yaml 缺 ojm_install_seq: N 行(vars 安装序号,模板 config.yaml 随发,勿删)——reload 热更无变更可落(unchanged 恒真),安装终止于 reloading 段");
64
- }
65
- const m = /^(\s*ojm_install_seq\s*:\s*)(\d+)/.exec(lines[idx]!)!;
66
- const seq = Number(m[2]) + 1;
67
- lines[idx] = `${m[1]}${seq}${lines[idx]!.slice(m[0].length)}`;
68
- return { content: lines.join("\n"), seq };
69
- }
70
-
71
52
  /**
72
53
  * C2-26 anonymous 运行时接线(P2-15③ 承载,观察项 6 收口):把方案的匿名端点追加进
73
54
  * config.yaml `auth.anonymous_paths` 列表(oj 匿名模型 config 独占;热改属
@@ -108,3 +89,74 @@ export function appendAnonymousPaths(content: string, paths: string[]): { conten
108
89
  lines.splice(last + 1, 0, ...added.map(p => `${itemIndent}- ${p}`));
109
90
  return { content: lines.join("\n"), added };
110
91
  }
92
+
93
+ /**
94
+ * `appendAnonymousPaths` 的逆操作(P0 补偿清单 §3.5):把指定匿名路径从 `auth.anonymous_paths`
95
+ * 列表移除。纯文本判定,与 append 同源——按行 `- <path>`(trim 匹配)删除,列表其余项/注释/空行
96
+ * 原样保留;幂等:路径不在列表内则 no-op、返回 removed=[]。键缺失(从未接线)= 没东西可删,no-op。
97
+ * `paths` 形态应与 append 传入一致(方案相对形态),本函数统一补前导 `/` 对齐写入形态。
98
+ */
99
+ export function removeAnonymousPaths(content: string, paths: string[]): { content: string, removed: string[] } {
100
+ if (paths.length === 0) {
101
+ return { content, removed: [] };
102
+ }
103
+ const wanted = new Set(paths.map(p => (p.startsWith("/") ? p : `/${p}`)));
104
+ const lines = content.split("\n");
105
+ const idx = lines.findIndex(l => /^\s*anonymous_paths\s*:/.test(l));
106
+ if (idx === -1) {
107
+ return { content, removed: [] };
108
+ }
109
+ // 收集列表项行区间(键行之后连续 `- item`,跳过空行/注释,遇首个其他行即止)
110
+ const itemLines: number[] = [];
111
+ for (let i = idx + 1; i < lines.length; i++) {
112
+ const line = lines[i]!;
113
+ if (line.trim() === "" || /^\s*#/.test(line)) {
114
+ continue;
115
+ }
116
+ const stripped = line.replace(/#.*$/, "").trim();
117
+ if (!stripped.startsWith("- ")) {
118
+ break;
119
+ }
120
+ itemLines.push(i);
121
+ }
122
+ const removeSet = new Set<number>();
123
+ const removed: string[] = [];
124
+ for (const i of itemLines) {
125
+ const val = lines[i]!.replace(/#.*$/, "").trim().slice(2).trim();
126
+ if (wanted.has(val)) {
127
+ removeSet.add(i);
128
+ removed.push(val);
129
+ }
130
+ }
131
+ if (removed.length === 0) {
132
+ return { content, removed: [] };
133
+ }
134
+ const next = lines.filter((_, i) => !removeSet.has(i));
135
+ return { content: next.join("\n"), removed };
136
+ }
137
+
138
+ /**
139
+ * 纯文本解析 `auth.anonymous_paths` 列表(P0 §3.2 质辩1 / E8 残留检测消费面):与 append/remove
140
+ * 同源的列表收集口径——从 `anonymous_paths:` 键行起,连续 `- item` 行(跳过空行/注释)逐行取值。
141
+ * 用于「读」已装站点的匿名条目,不修改文本。键缺失 = 返回 []。
142
+ */
143
+ export function readAnonymousPaths(content: string): string[] {
144
+ const lines = content.split("\n");
145
+ const idx = lines.findIndex(l => /^\s*anonymous_paths\s*:/.test(l));
146
+ if (idx === -1) {
147
+ return [];
148
+ }
149
+ const out: string[] = [];
150
+ for (let i = idx + 1; i < lines.length; i++) {
151
+ const line = lines[i]!;
152
+ if (line.trim() === "" || /^\s*#/.test(line)) {
153
+ continue;
154
+ }
155
+ const stripped = line.replace(/#.*$/, "").trim();
156
+ if (!stripped.startsWith("- ")) {
157
+ break;
158
+ }
159
+ out.push(stripped.slice(2).trim());
160
+ }
161
+ return out;
162
+ }
@@ -23,6 +23,22 @@ export interface InstallContext {
23
23
  hostVersions?: Record<string, string>
24
24
  /** 宿主平台编排面 API 版本(C2-11 peerPlatform 比对真源;镜像 GET /api/_platform/market/meta 的 apiVersion,即 market/api.ts 的 API_VERSION 常量,与 _platform/manifest.yaml 版本手工同步) */
25
25
  hostApiVersion?: string
26
+ /**
27
+ * 宿主能力集(P0 §3.9:ojInfo().capabilities,装配期冻结、任何模块可读)。由调用方从 ojInfo 注入;
28
+ * 与 manifest.requiresCapabilities 配对做写锁前门禁。缺省 undefined = 宿主未上报,
29
+ * 此时若模板声明了 requiresCapabilities 则 fail-closed(视为能力缺失)。
30
+ */
31
+ capabilities?: string[]
32
+ /**
33
+ * 站点 config.yaml 已存在的 auth.anonymous_paths(P0 §3.2 质辩1 / E8:装前残留匿名检测真源)。
34
+ * 由调用方在 preflight 前读 config 注入(preflight 保持只读 ctx 的纯校验段纪律);缺省 [] 视为无残留。
35
+ */
36
+ existingAnonymousPaths?: string[]
37
+ /**
38
+ * 本次热更返回的待重启段(reloading 段捕获自 reloadAndAssert;非空 = 部分生效、需宿主重启后完全生效)。
39
+ * installer 终态判定据其标 partial + restartRequired(无守护形态,P0 §3.6 / 验收 15)。瞬态,不落盘。
40
+ */
41
+ restartPending?: string[]
26
42
  /** 目标站点数据库句柄(本段不消费;P1-8 register 段起使用) */
27
43
  db?: unknown
28
44
  /**
@@ -31,6 +47,12 @@ export interface InstallContext {
31
47
  * 跨方案碰撞仍由 apiSeg/route_prefix 首段占用兜住;缺省 false 保持 P1-5「同名拒装」钉面。
32
48
  */
33
49
  reinstall?: boolean
50
+ /**
51
+ * 强制热更(oj 0.1.123+ reloadConfig(force)):绕过「unchanged=已是最新装配」幂等短路,
52
+ * 强制触发一次重装配——运维显式重装配用,不依赖锁 diff / 文档 sha 变化。缺省 false。
53
+ * 仅供 install 路径消费(reloading 段透传给 reload 面);uninstall 恒严格(忽略 force)。
54
+ */
55
+ force?: boolean
34
56
  }
35
57
 
36
58
  /** 阶段结果(全 stage 通用结构形状;stage 取值为各 step 自己的字面量,编排层以 StageDef.name 为准) */
@@ -87,8 +109,8 @@ export interface TaskRecord {
87
109
  /** 0-100 整体进度(按 STAGES 表完成数折算) */
88
110
  progress: number
89
111
  message: string
90
- /** 各 stage 明细日志(UI 详情日志区数据源) */
91
- stages: { stage: InstallStage, ok: boolean, message: string }[]
112
+ /** 各 stage 明细日志(UI 详情日志区数据源;补偿子步形如 `compensate.<step>`,故 stage 为 string 而非窄类型 InstallStage) */
113
+ stages: { stage: string, ok: boolean, message: string }[]
92
114
  /** 失败/partial 终态:reason + retryable + 指引文案 key(契约附录 A) */
93
115
  error?: { reason: string, retryable: boolean, hintKey?: string }
94
116
  /** needs_trust 终态:待确认的发布方 key(POST /market/trust {task_id} 消费;指纹供人确认) */
@@ -99,4 +121,6 @@ export interface TaskRecord {
99
121
  appliedSeq?: number
100
122
  /** 取消安装标记(U5,P3-8):用户中止触发的终态(status 仍取 failed/partial——D11 共用失败终态,此标记供 UI 区分「取消」与「失败」) */
101
123
  cancelled?: boolean
124
+ /** 无守护形态部分生效标记(P0 §3.6 / 验收 15):热更返回待重启段非空、且无 supervisor 自动换进程 → 装完仍须宿主重启才完全生效。UI 据其展示「重启提示」而非「成功」 */
125
+ restartRequired?: boolean
102
126
  }
@@ -9,12 +9,14 @@
9
9
 
10
10
  import type { OpEntry } from "../_shared/service/infra/audit";
11
11
  import type { StateStore } from "./state";
12
+ import type { ReloadFace, ReloadResult } from "./steps/reload";
12
13
  import { uninstallSolution } from "../_shared/service/domain/solution-perms";
13
14
  import { invalidateAllUsers } from "../_shared/service/infra/access";
14
15
  import { auditOp } from "../_shared/service/infra/audit";
15
16
  import { atomicWriteText, fsFace } from "./atomic";
16
17
  import { recordHistory } from "./history";
17
18
  import { readLock, writeLock } from "./lock";
19
+ import { assertReloadApplied } from "./steps/reload";
18
20
 
19
21
  // db 为 oj isolate 注入全局(同模板 service 层惯例,installer.ts 同款;测试由夹具装 globalThis.db)
20
22
  declare const db: {
@@ -65,6 +67,21 @@ export function moduleTablePrefix(name: string): string {
65
67
  return `${name.replace(/-/g, "_")}_`;
66
68
  }
67
69
 
70
+ /**
71
+ * 卸载期判断方案是否含 api 模块(决定 oj 是否产出 -name@ver 装配条目):读版本目录内 C2 manifest.yaml
72
+ * 的顶层 `api:` 段。reload 断言时版本目录仍在(删除在 reload 之后),故可读。读失败/无 api 段 → false
73
+ * (web-only 方案 oj 不产模块条目,符号不强制,仅校验 reload 已探测锁变更)。
74
+ */
75
+ async function uninstallHasApi(name: string, version: string, sharedRoot: string): Promise<boolean> {
76
+ try {
77
+ const text = new TextDecoder().decode(await fsFace().readFile(`${sharedRoot}/${name}-${version}/manifest.yaml`));
78
+ return /^api\s*:/m.test(text);
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+
68
85
  /** 收集需保留的业务表(Q4):声明 + 前缀兜底;仅返回实际存在的表名 */
69
86
  export async function collectRetainedTables(name: string, manifestPath: string): Promise<string[]> {
70
87
  const candidates = new Set<string>();
@@ -91,6 +108,18 @@ export async function collectRetainedTables(name: string, manifestPath: string):
91
108
  return [...candidates].filter(t => existing.has(t));
92
109
  }
93
110
 
111
+ /**
112
+ * 回退某方案的 DB 注册(P0 补偿清单 §3.5 复用):单一事务内删 sys_solution_route + 级联清
113
+ * 角色/权限(uninstallSolution 双维度级联)。与 runUninstall 的 DB 步同原语,避免两套 DB 回滚逻辑。
114
+ * 行已不存在 = no-op(幂等安全)。
115
+ */
116
+ export async function revertRegistrations(name: string): Promise<void> {
117
+ await db.tx(async (t) => {
118
+ await t.table("sys_solution_route").where({ field: "module", op: "eq", value: name }).delete().run();
119
+ await uninstallSolution(name, t);
120
+ });
121
+ }
122
+
94
123
  /** 卸载影响面预检(GET uninstall-impact 消费面):返回前端二次确认所需的影响计数 */
95
124
  export interface UninstallImpact {
96
125
  name: string
@@ -111,6 +140,8 @@ export interface UninstallInput {
111
140
  now?: number
112
141
  /** 审计出口(缺省 auditOp;测试注入记录器) */
113
142
  audit?: (entry: OpEntry) => void
143
+ /** 热更面(P0 §3.4 第5步:卸载摘锁后 reload 触达装配以真正摘除模块;缺省不 reload——依赖 US-1 上游 manifests 摘要驱动才实际掉挂载)。reload 失败 → 锁写回 + 再 reload 回旧代(模块仍挂载、可重试) */
144
+ reload?: ReloadFace
114
145
  }
115
146
 
116
147
  export interface UninstallResult {
@@ -184,16 +215,73 @@ export async function runUninstall(input: UninstallInput): Promise<UninstallResu
184
215
  return { ok: false, message: `卸载失败:权限级联清理失败(${String(e)})——事务已回滚,锁/路由/角色/权限未改动(fail-closed)` };
185
216
  }
186
217
 
187
- // ② sidecar 删条目(patch 值 null = 删除该方案键)
218
+ // ① 锁摘除(先失可达性:模块停止装配;在此之前任一失败锁均保留 = fail-closed)
219
+ try {
220
+ await writeLock(input.lockPath, remaining);
221
+ }
222
+ catch (e) {
223
+ audit(false, `锁写失败:${String(e)}`);
224
+ return { ok: false, message: `卸载失败:锁写失败(${String(e)})——DB 级联已回滚、sidecar/modules 未动(fail-closed)` };
225
+ }
226
+
227
+ // ② reload 触达装配以真正摘除模块(P0 §3.4 第5步:先失可达性);缺省无 reload 面则跳过(依赖
228
+ // US-1 上游 manifests 摘要驱动才实际掉挂载)。reload 失败 / 返回 unchanged / 未真正摘除模块 →
229
+ // 锁写回 + 再 reload 回旧代——模块仍挂载,且此时 sidecar/modules.json/版本目录均未删(下面才删),
230
+ // 故锁写回即**一致回滚**,不残留半卸状态,返回失败可重试(fail-closed)。
231
+ if (input.reload !== undefined) {
232
+ let r: ReloadResult;
233
+ try {
234
+ r = await input.reload.reloadConfig();
235
+ }
236
+ catch (e) {
237
+ try {
238
+ await writeLock(input.lockPath, lock);
239
+ }
240
+ catch {
241
+ // 锁写回失败不掩盖 reload 失败终态
242
+ }
243
+ try {
244
+ await input.reload.reloadConfig();
245
+ }
246
+ catch {
247
+ // 回滚 reload 也失败:模块仍按原锁挂载,下次卸载重试
248
+ }
249
+ audit(false, `reload 失败,已回写锁并恢复旧代:${String(e)}`);
250
+ return { ok: false, message: `卸载失败:reload 失败(${String(e)})——已回写锁恢复旧代(模块仍挂载、元数据未删),请稍后重试` };
251
+ }
252
+ // 卸载空转回归守卫(§2.7):reload 须真实摘除模块——unchanged 即「锁摘了但装配没掉挂载」,
253
+ // 正是本 PR 修复的回归;api 模块还须 applied 含 -name@ver(web-only 无 api 段,oj 不产模块条目,仅校验 unchanged)。
254
+ const hasApi = await uninstallHasApi(name, version, input.sharedRoot);
255
+ const a = assertReloadApplied(r, { hasApi, kind: "uninstall", name, version });
256
+ if (!a.ok) {
257
+ try {
258
+ await writeLock(input.lockPath, lock);
259
+ }
260
+ catch {
261
+ // 锁写回失败不掩盖 reload 断言失败终态
262
+ }
263
+ try {
264
+ await input.reload.reloadConfig();
265
+ }
266
+ catch {
267
+ // 回滚 reload 也失败:模块仍按原锁挂载,下次卸载重试
268
+ }
269
+ audit(false, `reload 未真正摘除模块,已回写锁并恢复旧代:${a.message}`);
270
+ return { ok: false, message: `卸载失败:${a.message}——已回写锁恢复旧代(模块仍挂载、元数据未删),请稍后重试` };
271
+ }
272
+ }
273
+
274
+ // ③ 再失文件前先清元数据:sidecar 删条目 / modules.json 删条目(reload 成功才走到这里,回滚已不可达)
275
+ // sidecar 删条目(patch 值 null = 删除该方案键)
188
276
  try {
189
277
  await input.state.write({ solutions: { [name]: null } } as unknown as Parameters<typeof input.state.write>[0]);
190
278
  }
191
279
  catch (e) {
192
280
  audit(false, `sidecar 写失败:${String(e)}`);
193
- return { ok: false, message: `卸载失败:sidecar 写失败(${String(e)})——DB 级联已提交,锁未摘(fail-closed)` };
281
+ return { ok: false, message: `卸载失败:sidecar 写失败(${String(e)})——锁已摘、reload 已生效,模块已停装配;sidecar 残留待重装自愈` };
194
282
  }
195
283
 
196
- // ③ modules.json 删条目(条目不存在 = api-only 方案,天然一致)
284
+ // modules.json 删条目(条目不存在 = api-only 方案,天然一致)
197
285
  try {
198
286
  const list = JSON.parse(new TextDecoder().decode(await f.readFile(input.modulesJsonPath))) as unknown[];
199
287
  if (!Array.isArray(list)) {
@@ -204,19 +292,10 @@ export async function runUninstall(input: UninstallInput): Promise<UninstallResu
204
292
  }
205
293
  catch (e) {
206
294
  audit(false, `modules.json 写失败:${String(e)}`);
207
- return { ok: false, message: `卸载失败:modules.json 写失败(${String(e)})——DB 级联已提交、sidecar 已删,锁未摘(fail-closed)` };
208
- }
209
-
210
- // ① 锁摘除(最后执行:模块停止装配;在此之前任一失败锁均保留 = fail-closed)
211
- try {
212
- await writeLock(input.lockPath, remaining);
213
- }
214
- catch (e) {
215
- audit(false, `锁写失败:${String(e)}`);
216
- return { ok: false, message: `卸载失败:锁写失败(${String(e)})——DB 级联/sidecar/modules 已更新,锁残留` };
295
+ return { ok: false, message: `卸载失败:modules.json 写失败(${String(e)})——锁已摘、reload 已生效、sidecar 已删,modules.json 残留待重装自愈` };
217
296
  }
218
297
 
219
- // 版本目录移除(缺失不报错,幂等)
298
+ // ④ 版本目录移除(缺失不报错,幂等);再失文件(P0 §3.4:先失可达性再失文件)
220
299
  // —— 但 Q4 业务表清单须在版本目录移除前从 manifest 取得(manifest 在版本目录内)——
221
300
  let retained: string[] = [];
222
301
  try {
@@ -68,11 +68,15 @@ export async function updateSetting(actorId: number, key: string, value: string)
68
68
  await recordOp({ action: "setting.update", module: String(row.module), target: key });
69
69
  }
70
70
 
71
- /** C5/D2:登录方式发现的数据源——local 恒在,ldap/sso/wecom 由设置项开关。 */
72
- export async function listLoginMethods(): Promise<{ methods: string[] }> {
73
- const rows = await db.table("sys_setting").select(["key", "value"]).where({ field: "key", op: "in", value: ["ldap.enabled", "sso.enabled", "wecom.enabled"] }).all() as Array<{ key: string, value: string | null }>;
71
+ /**
72
+ * C5/D2:登录方式发现的数据源——local 恒在,ldap/sso/wecom 由设置项开关。
73
+ * 同时回传站点标题(framework.site_title,非 secret),供登录页匿名设置浏览器标签。
74
+ */
75
+ export async function listLoginMethods(): Promise<{ methods: string[], site_title: string }> {
76
+ const rows = await db.table("sys_setting").select(["key", "value"]).where({ field: "key", op: "in", value: ["ldap.enabled", "sso.enabled", "wecom.enabled", "framework.site_title"] }).all() as Array<{ key: string, value: string | null }>;
74
77
  const enabled = (k: string) => rows.find(r => r.key === k)?.value === "1";
78
+ const siteTitle = rows.find(r => r.key === "framework.site_title")?.value ?? "";
75
79
  // wecom 的凭据在部署常量(config vars),这里只报开关:开关开了但凭据没配,
76
80
  // 点进企微登录会拿到 400「企业微信未配置」——比登录页凭空少一个 tab 更容易排查。
77
- return { methods: ["local", ...(enabled("ldap.enabled") ? ["ldap" as const] : []), ...(enabled("sso.enabled") ? ["sso" as const] : []), ...(enabled("wecom.enabled") ? ["wecom" as const] : [])] };
81
+ return { methods: ["local", ...(enabled("ldap.enabled") ? ["ldap" as const] : []), ...(enabled("sso.enabled") ? ["sso" as const] : []), ...(enabled("wecom.enabled") ? ["wecom" as const] : [])], site_title: siteTitle };
78
82
  }
@@ -13,6 +13,7 @@ tables:
13
13
  - sys_user_role
14
14
  - sys_refresh_token
15
15
  - market_history
16
+ - market_release
16
17
  - sys_rate_window
17
18
  - sys_login_throttle
18
19
  - reg_source_seq