@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.
- package/devkit/README.md +4 -4
- package/devkit/SKILL.md +41 -37
- package/devkit/framework-dev.md +6 -5
- package/devkit/manual.md +260 -162
- package/devkit/menu-rules.md +3 -4
- package/devkit/module-dev-and-cdn-playground.md +31 -22
- package/devkit/sql-builder-missing-capabilities-pr.md +11 -6
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +2 -2
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/build-backend.test.ts +54 -0
- package/src/__tests__/layout.test.ts +176 -0
- package/src/__tests__/module-list.test.ts +66 -0
- package/src/__tests__/oj-caps.test.ts +114 -0
- package/src/alias-paths.ts +102 -0
- package/src/build.ts +41 -9
- package/src/bundle.ts +25 -13
- package/src/config.ts +82 -9
- package/src/contract/__tests__/market-client.integration.test.ts +2 -2
- package/src/contract/check.ts +56 -28
- package/src/contract/emit-stub.ts +21 -9
- package/src/contract/handler-scan.ts +19 -10
- package/src/contract/run.ts +14 -4
- package/src/dev.ts +22 -7
- package/src/index.ts +1 -1
- package/src/info.ts +20 -3
- package/src/init.ts +91 -21
- package/src/layout.ts +282 -24
- package/src/lifecycle/__tests__/bundle.test.ts +16 -1
- package/src/lifecycle/__tests__/manifest-contract.test.ts +17 -58
- package/src/manifest-contract.ts +2 -25
- package/src/market/__tests__/bootstrap.test.ts +17 -9
- package/src/market/bootstrap.ts +30 -17
- package/src/oj-caps.ts +133 -0
- package/src/oj.ts +27 -4
- package/src/preview-config.ts +1 -1
- package/src/preview.ts +2 -1
- package/src/site.ts +2 -2
- package/src/usage.ts +6 -6
- package/src/vendor.ts +5 -1
- package/templates/{api/config.yaml → config.yaml} +13 -8
- package/templates/global.d.ts +7 -6
- package/templates/init.include.yaml +41 -36
- package/templates/package.json +1 -1
- package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/installer.ts +4 -0
- package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/smoke.ts +21 -2
- package/templates/{api/src/_platform → src/_platform/api}/market/api.ts +25 -15
- package/templates/{api/src/_platform → src/_platform/api}/solutions/api.ts +7 -3
- package/templates/{api/src/auth → src/auth/api}/_shared/login-throttle.ts +2 -2
- package/templates/{api/src/auth → src/auth/api}/_shared/session.ts +2 -2
- package/templates/{api/src/auth → src/auth/api}/api.ts +1 -1
- package/templates/{api/src/auth → src/auth/api}/ldap-login/api.ts +1 -1
- package/templates/src/auth/api/manifest.yaml +6 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/InstallDialog.test.tsx +53 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/marketClient.fake.ts +6 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/api/client.ts +5 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/api/defaultClient.ts +7 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/components/InstallDialog.tsx +80 -5
- package/templates/{web/src/oj-market → src/oj-market/web}/hooks/useMarket.ts +6 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/locales/en-US.json +10 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/locales/zh-CN.json +10 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/types.ts +15 -2
- package/templates/{api/src/system → src/system/api}/login-methods/api.ts +2 -2
- package/templates/src/system/api/manifest.yaml +6 -0
- package/templates/{api/src/system → src/system/api}/oplog/api.ts +4 -4
- package/templates/{api/src/system → src/system/api}/permissions/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/roles/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/roles/bindings/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/settings/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/forbidden/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/password/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/roles/api.ts +3 -3
- package/templates/src/tsconfig.json +16 -0
- package/templates/{api/tests → tests}/auth-ldap.spec.ts +2 -2
- package/templates/{api/tests → tests}/auth-session.spec.ts +3 -3
- package/templates/{api/tests → tests}/auth-throttle.spec.ts +1 -1
- package/templates/tests/fixture.ts +434 -0
- package/templates/{api/tests → tests}/guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/atomic-state.spec.ts +3 -3
- package/templates/{api/tests → tests}/lifecycle/bootstrap.spec.ts +8 -4
- package/templates/{api/tests → tests}/lifecycle/deploy-smoke.spec.ts +31 -8
- package/templates/{api/tests → tests}/lifecycle/installer.spec.ts +15 -15
- package/templates/{api/tests → tests}/lifecycle/market-api.spec.ts +30 -29
- package/templates/{api/tests → tests}/lifecycle/migrate.spec.ts +6 -6
- package/templates/{api/tests → tests}/lifecycle/preflight.spec.ts +4 -4
- package/templates/{api/tests → tests}/lifecycle/register.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/semver.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/sha384.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/sig-fixtures.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/solutions-api.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/steps-fs.spec.ts +12 -12
- package/templates/{api/tests → tests}/lifecycle/text-edit.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/tgz-guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/trust.spec.ts +5 -5
- package/templates/{api/tests → tests}/lifecycle/uninstall.spec.ts +7 -7
- package/templates/{api/tests → tests}/lifecycle/verify-checks.spec.ts +9 -6
- package/templates/{api/tests → tests}/lifecycle/verify-report.spec.ts +7 -5
- package/templates/{api/tests → tests}/query-utils.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-audit.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-contacts.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-roles.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-seed.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-settings.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-solution-perms.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-users.spec.ts +3 -3
- package/templates/tsconfig.json +5 -1
- package/templates/tsconfig.paths.json +19 -0
- package/templates/types/oj-modules.d.ts +17 -0
- package/templates/vitest.config.ts +22 -0
- package/templates/web.config.ts +23 -13
- package/vendor/host-versions.json +3 -3
- package/templates/api/src/auth/manifest.yaml +0 -5
- package/templates/api/src/system/manifest.yaml +0 -5
- package/templates/api/tests/fixture.ts +0 -58
- package/templates/api/tsconfig.json +0 -8
- package/templates/api/vitest.config.ts +0 -12
- package/templates/logs/task-events.jsonl +0 -0
- /package/templates/{api/.ojm-api-exempt.json → .ojm-api-exempt.json} +0 -0
- /package/templates/{api/seed.mysql.sql → seed.mysql.sql} +0 -0
- /package/templates/{api/seed.pg.sql → seed.pg.sql} +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/README.md +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/atomic.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/history.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/lock.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/semver.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/sha384.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/state.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/deploy-web.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/download.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/extract.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/migrate.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/preflight.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/register.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/reload.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/verify.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tasks.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/text-edit.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tgz-guard.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/trust.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/types.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/uninstall.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-checks.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-report.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/respond.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/contacts.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/roles.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/settings.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/solution-perms.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/users.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/access.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/audit.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/guard.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/oplog.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/query.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/rate.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/site-facade.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/contacts/api.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/contacts/detail/api.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/fixtures/l1-test-user.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/manifest.yaml +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/market/bootstrap.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0007__users_email.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0013__users_profile.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/schema.yaml +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.sql +0 -0
- /package/templates/{web/src/_platform → src/_platform/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/_platform → src/_platform/web}/__client/api.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/entry.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/about → src/about/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/about → src/about/web}/pages/constants.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/entry.ts +0 -0
- /package/templates/{web/src/access → src/access/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/access → src/access/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/access-mode/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/admin-visible/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/button-control/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/common-visible/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/page-control/index.tsx +0 -0
- /package/templates/{api/src/auth → src/auth/api}/_shared/ldap-login.ts +0 -0
- /package/templates/{api/src/auth → src/auth/api}/_shared/ldap.ts +0 -0
- /package/templates/{web/src/auth → src/auth/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/auth → src/auth/web}/__client/api.ts +0 -0
- /package/templates/{api/src/demo → src/demo/api}/manifest.yaml +0 -0
- /package/templates/{api/src/demo → src/demo/api}/migrations/0001__create_todos.sql +0 -0
- /package/templates/{api/src/demo → src/demo/api}/schema.yaml +0 -0
- /package/templates/{api/src/demo → src/demo/api}/seed.sql +0 -0
- /package/templates/{api/src/demo → src/demo/api}/todos/api.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/__client/api.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/entry.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/demo → src/demo/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/demo → src/demo/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/entry.ts +0 -0
- /package/templates/{web/src/exception → src/exception/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/exception → src/exception/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/403/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/404/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/500/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/unknown-component/index.tsx +0 -0
- /package/templates/{api/src/home → src/home/api}/line/api.ts +0 -0
- /package/templates/{api/src/home → src/home/api}/manifest.yaml +0 -0
- /package/templates/{api/src/home → src/home/api}/migrations/0001__create_home_tables.sql +0 -0
- /package/templates/{api/src/home → src/home/api}/pie/api.ts +0 -0
- /package/templates/{api/src/home → src/home/api}/schema.yaml +0 -0
- /package/templates/{api/src/home → src/home/api}/seed.sql +0 -0
- /package/templates/{web/src/home → src/home/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/__client/api.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/entry.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/home → src/home/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/bar-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/card-list.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/line-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/pie-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/login → src/login/web}/entry.ts +0 -0
- /package/templates/{web/src/login → src/login/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/login → src/login/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/login → src/login/web}/pages/change-password.tsx +0 -0
- /package/templates/{web/src/login → src/login/web}/pages/login.tsx +0 -0
- /package/templates/{api/src/notification → src/notification/api}/_shared/notify.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/api.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/del/api.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/manifest.yaml +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0001__create_notifications.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0002__notifications_user.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0003__notifications_broadcast.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/schema.yaml +0 -0
- /package/templates/{api/src/notification → src/notification/api}/seed.sql +0 -0
- /package/templates/{web/src/notification → src/notification/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/__client/api.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/entry.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/notification → src/notification/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/notification → src/notification/web}/pages/center/index.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/CardGrid.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/HistoryDrawer.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/RollbackDialog.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/UninstallConfirm.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/poll.test.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/render.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/runtime-stub.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/semver.test.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/api/MarketClientProvider.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/api/context.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardGrid.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardItem.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/DetailDrawer.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/HistoryDrawer.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/RollbackDialog.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/UninstallConfirm.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/entry.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/pages/MarketApp.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/utils/poll.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/utils/semver.ts +0 -0
- /package/templates/{web/src/outside → src/outside/web}/entry.ts +0 -0
- /package/templates/{web/src/outside → src/outside/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/outside → src/outside/web}/locales/zh-CN.json +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/manifest.yaml +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/profile/api.ts +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/upload/api.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/entry.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/pages/my-profile/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/entry.ts +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-1/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-2/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu2/index.tsx +0 -0
- /package/templates/{web/src → src}/styles.css +0 -0
- /package/templates/{web/src/system → src/system/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/__client/api.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/entry.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/system → src/system/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/errors.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/forbidden.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/login-methods/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/oplog/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/roles/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/settings/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/users/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/users/roles.tsx +0 -0
- /package/templates/{api/src/web → src/web/api}/get-async-routes/api.ts +0 -0
- /package/templates/{api/src/web → src/web/api}/hello/api.ts +0 -0
- /package/templates/{api/src/web → src/web/api}/manifest.yaml +0 -0
- /package/templates/{api/src/web → src/web/api}/user-info/api.ts +0 -0
- /package/templates/{web/src → src/web}/web/__client/api.schemas.ts +0 -0
- /package/templates/{web/src → src/web}/web/__client/api.ts +0 -0
- /package/templates/{api/tests → tests}/l1-builder.test.ts +0 -0
- /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
|
|
57
|
-
|
|
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 ? (
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
/**
|
|
9
|
-
|
|
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 "
|
|
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 "
|
|
4
|
+
import { listLoginMethods } from "#/_platform/_shared/service/domain/settings";
|
|
5
5
|
|
|
6
6
|
async function get() {
|
|
7
7
|
await respond(async () => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { respond } from "
|
|
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 "
|
|
5
|
-
import { recordOp } from "
|
|
6
|
-
import { searchOplog } from "
|
|
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 "
|
|
2
|
-
import { listPermissions } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { createRole, deleteRole, listRoles } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { updateBindings } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { listSettings, updateSetting } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { createUser, listUsers } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { setForbidden } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { changePasswordByAdmin } from "
|
|
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 "
|
|
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 "
|
|
2
|
-
import { updateUserRoles } from "
|
|
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 "
|
|
4
|
+
import { assertSystemAdmin } from "#/_platform/_shared/service/infra/access";
|
|
5
5
|
|
|
6
6
|
async function put() {
|
|
7
7
|
await respond(async () => {
|
|
@@ -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>;
|