@oj-module/cli 0.2.54 → 0.2.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/README.md +7 -4
- package/devkit/SKILL.md +7 -4
- package/devkit/manual.md +63 -54
- package/devkit/module-dev-and-cdn-playground.md +7 -0
- package/devkit/publish-walkthrough.md +199 -0
- package/package.json +2 -2
- package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
- package/shell-dist/assets/runtime.js +5 -5
- package/shell-dist/index.html +3 -3
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/layout.test.ts +30 -1
- package/src/__tests__/templates-schema-columns.test.ts +99 -0
- package/src/__tests__/vendor-devkit.test.ts +87 -0
- package/src/alias-paths.ts +11 -12
- package/src/build/backend.ts +131 -0
- package/src/build/module-build.ts +364 -0
- package/src/build/module-def.ts +381 -0
- package/src/build/site-merge.ts +33 -0
- package/src/build.ts +16 -885
- package/src/builtin.ts +10 -3
- package/src/bundle.ts +61 -0
- package/src/cli.ts +4 -1
- package/src/contract/__tests__/emit-client.test.ts +4 -4
- package/src/contract/__tests__/market-client.integration.test.ts +2 -2
- package/src/contract/__tests__/run-api.test.ts +2 -2
- package/src/contract/check.ts +6 -2
- package/src/contract/emit-client.ts +10 -3
- package/src/contract/run.ts +10 -2
- package/src/init.ts +31 -46
- package/src/layout.ts +72 -16
- package/src/lifecycle/__tests__/bundle-summary.test.ts +106 -0
- package/src/lifecycle/__tests__/bundle.test.ts +6 -0
- package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
- package/src/market/__tests__/bootstrap.test.ts +1 -1
- package/src/site.ts +1 -1
- package/src/vendor.ts +34 -0
- package/templates/README.md +30 -20
- package/templates/init.include.yaml +19 -11
- package/templates/openapi.json +102 -86
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/installer.ts +8 -3
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/register.ts +53 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/roles.ts +4 -1
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/solution-perms.ts +7 -3
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/users.ts +27 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/oplog.ts +4 -2
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +7 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +4 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +8 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +3 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +3 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +8 -0
- package/templates/src/{_platform/api → app/api/_platform}/schema.yaml +7 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/replay.ts +9 -3
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/tenant-admin.ts +18 -27
- package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
- package/templates/src/{system/api → app/api/system}/roles/api.ts +2 -1
- package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +5 -2
- package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +5 -2
- package/templates/src/app/web/notification/pages/center/index.tsx +1 -1
- package/templates/src/app/web/notification/routes.ts +1 -1
- package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +1 -1
- package/templates/src/app/web/personal-center/routes.ts +1 -1
- package/templates/src/app/web/system/__client/api.schemas.ts +2 -0
- package/templates/src/app/web/system/locales/en-US.json +2 -3
- package/templates/src/app/web/system/locales/zh-CN.json +2 -3
- package/templates/src/app/web/system/pages/departments/index.tsx +2 -2
- package/templates/src/app/web/system/pages/login-methods/index.tsx +1 -1
- package/templates/src/app/web/system/pages/oplog/index.tsx +44 -19
- package/templates/src/app/web/system/pages/roles/index.tsx +12 -4
- package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
- package/templates/src/app/web/system/pages/settings/index.tsx +2 -2
- package/templates/src/app/web/system/pages/users/can-manage.ts +21 -0
- package/templates/src/app/web/system/pages/users/index.tsx +25 -17
- package/templates/src/app/web/system/pages/users/roles.tsx +1 -1
- package/templates/src/app/web/system/routes.ts +1 -1
- package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +5 -2
- package/templates/src/oj-market/web/api/defaultClient.ts +1 -1
- package/templates/tests/auth-ldap.spec.ts +2 -2
- package/templates/tests/auth-session.spec.ts +3 -3
- package/templates/tests/auth-throttle.spec.ts +1 -1
- package/templates/tests/fixture.ts +6 -4
- package/templates/tests/guard.spec.ts +1 -1
- package/templates/tests/lifecycle/atomic-state.spec.ts +3 -3
- package/templates/tests/lifecycle/bootstrap.spec.ts +3 -3
- package/templates/tests/lifecycle/deploy-smoke.spec.ts +8 -8
- package/templates/tests/lifecycle/installer.spec.ts +10 -10
- package/templates/tests/lifecycle/market-api.spec.ts +14 -14
- package/templates/tests/lifecycle/migrate.spec.ts +6 -6
- package/templates/tests/lifecycle/preflight.spec.ts +3 -3
- package/templates/tests/lifecycle/register.spec.ts +1 -1
- package/templates/tests/lifecycle/role-title-translate.spec.ts +171 -0
- package/templates/tests/lifecycle/semver.spec.ts +1 -1
- package/templates/tests/lifecycle/sha384.spec.ts +1 -1
- package/templates/tests/lifecycle/solutions-api.spec.ts +1 -1
- package/templates/tests/lifecycle/source-seq.spec.ts +1 -1
- package/templates/tests/lifecycle/steps-fs.spec.ts +9 -9
- package/templates/tests/lifecycle/text-edit.spec.ts +1 -1
- package/templates/tests/lifecycle/tgz-guard.spec.ts +2 -2
- package/templates/tests/lifecycle/trust.spec.ts +5 -5
- package/templates/tests/lifecycle/uninstall.spec.ts +7 -7
- package/templates/tests/lifecycle/verify-checks.spec.ts +5 -5
- package/templates/tests/lifecycle/verify-report.spec.ts +4 -4
- package/templates/tests/org-departments.spec.ts +10 -6
- package/templates/tests/org-read.spec.ts +7 -7
- package/templates/tests/query-utils.spec.ts +1 -1
- package/templates/tests/rbac-audit.spec.ts +1 -1
- package/templates/tests/rbac-contacts.spec.ts +2 -2
- package/templates/tests/rbac-guard.spec.ts +1 -1
- package/templates/tests/rbac-roles.spec.ts +19 -2
- package/templates/tests/rbac-seed.spec.ts +1 -1
- package/templates/tests/rbac-settings.spec.ts +77 -7
- package/templates/tests/rbac-solution-perms.spec.ts +1 -1
- package/templates/tests/rbac-tables.spec.ts +29 -0
- package/templates/tests/rbac-users.spec.ts +55 -3
- package/templates/tests/roles-page.spec.ts +40 -0
- package/templates/tests/seed-role-accounts.spec.ts +1 -1
- package/templates/tests/tenant-access-cache.spec.ts +1 -1
- package/templates/tests/tenant-forgery.spec.ts +5 -5
- package/templates/tests/tenant-isolation.spec.ts +5 -4
- package/templates/tests/username-namespace.spec.ts +3 -3
- package/templates/tests/users-page.spec.ts +39 -0
- package/templates/tests/wecom-admin.spec.ts +6 -6
- package/templates/tests/wecom-client-timeout.spec.ts +1 -1
- package/templates/tests/wecom-connector.spec.ts +9 -9
- package/templates/tests/wecom-corp.spec.ts +9 -9
- package/templates/tests/wecom-crypt.spec.ts +1 -1
- package/templates/tests/wecom-endpoints.spec.ts +2 -2
- package/templates/tests/wecom-landing.spec.ts +1 -1
- package/templates/tests/wecom-org-sync.spec.ts +7 -7
- package/templates/tests/wecom-sync.spec.ts +3 -3
- package/templates/tsconfig.paths.json +11 -11
- package/templates/vitest.config.ts +2 -2
- package/templates/web.config.ts +5 -2
- package/vendor/host-versions.json +3 -3
- package/templates/src/{_platform/api → app/api/_platform}/README.md +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/atomic.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/history.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/limits.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/lock.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/semver.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/sha384.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/source-seq.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/state.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/deploy-web.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/download.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/extract.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/migrate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/preflight.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/reload.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/smoke.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/verify.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tasks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/text-edit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tgz-guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/trust.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/types.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/uninstall.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-checks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-report.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/respond.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/contacts.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org-read.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/settings.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/access.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/audit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/query.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/rate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/site-facade.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/contacts/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/fixtures/l1-test-user.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/manifest.yaml +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/bootstrap.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/index-source.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0007__users_email.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0013__users_profile.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/departments/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/is-member/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/members/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/picker/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/resolve/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/tree/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/user/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap-login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/login-throttle.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/session.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/admin.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/client.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/config.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/contacts.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/crypt.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/events.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/payload.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/store.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/sync.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/manifest.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/schema.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/api.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/password/api.ts +1 -1
- /package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +0 -0
- /package/templates/src/{auth/api → app/api/auth}/wecom/sync/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/line/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/manifest.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0001__create_home_tables.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.mysql.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/pie/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/schema.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/seed.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/_shared/notify.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/api.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/del/api.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/manifest.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0001__create_notifications.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0002__notifications_user.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0003__notifications_broadcast.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.mysql.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/schema.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/seed.sql +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/manifest.yaml +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/profile/api.ts +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/upload/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/detach/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/members/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/move/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/login-methods/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/manifest.yaml +0 -0
- /package/templates/src/{system/api → app/api/system}/permissions/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/settings/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/password/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/roles/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/get-async-routes/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/hello/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
- /package/templates/src/{web/api → app/api/web}/user-info/api.ts +0 -0
- /package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +0 -0
- /package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +0 -0
- /package/templates/src/app/web/home/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/notification/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/personal-center/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/system/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/{web → app/web}/web/__client/api.schemas.ts +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useQuery } from "@tanstack/react-query";
|
|
2
|
-
import {
|
|
2
|
+
import { Button, Form, Input, Space, Table, Tooltip } from "antd";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
|
|
7
|
-
import { systemOplogGet } from "../../__client
|
|
7
|
+
import { systemOplogGet } from "../../__client";
|
|
8
8
|
import { isForbidden } from "../errors";
|
|
9
9
|
import { ForbiddenPanel } from "../forbidden";
|
|
10
10
|
|
|
@@ -12,20 +12,26 @@ interface OplogFilters {
|
|
|
12
12
|
action?: string
|
|
13
13
|
username?: string
|
|
14
14
|
module?: string
|
|
15
|
-
limit?: number
|
|
16
15
|
}
|
|
17
16
|
|
|
17
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
18
|
+
const PAGE_SIZE_OPTIONS = [20, 50, 100];
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
|
-
* 操作日志(AC1-29/D13):action 精确 / username
|
|
20
|
-
*
|
|
21
|
+
* 操作日志(AC1-29/D13):action 精确 / username 包含 / module 精确。
|
|
22
|
+
*
|
|
23
|
+
* 分页交给服务端:`page` + `limit`(每页条数,钳 200),响应带 `total`,页面按 total 出页码。
|
|
24
|
+
* 不再有「结果被截断」的横幅——记录再多也能通过页码翻到,不必靠缩小过滤范围。
|
|
21
25
|
*/
|
|
22
26
|
export default function OplogPage() {
|
|
23
27
|
const { t } = useTranslation();
|
|
24
28
|
const [filters, setFilters] = useState<OplogFilters>({});
|
|
29
|
+
const [page, setPage] = useState(1);
|
|
30
|
+
const [size, setSize] = useState(DEFAULT_PAGE_SIZE);
|
|
25
31
|
|
|
26
32
|
const query = useQuery({
|
|
27
|
-
queryKey: ["system", "oplog", filters],
|
|
28
|
-
queryFn: () => systemOplogGet(filters),
|
|
33
|
+
queryKey: ["system", "oplog", filters, page, size],
|
|
34
|
+
queryFn: () => systemOplogGet({ ...filters, page, limit: size }),
|
|
29
35
|
});
|
|
30
36
|
|
|
31
37
|
if (query.error && isForbidden(query.error))
|
|
@@ -50,12 +56,14 @@ export default function OplogPage() {
|
|
|
50
56
|
<Space direction="vertical" style={{ width: "100%", paddingTop: 16 }}>
|
|
51
57
|
<Form
|
|
52
58
|
layout="inline"
|
|
53
|
-
onFinish={values =>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
onFinish={(values) => {
|
|
60
|
+
setFilters({
|
|
61
|
+
action: values.action || undefined,
|
|
62
|
+
username: values.username || undefined,
|
|
63
|
+
module: values.module || undefined,
|
|
64
|
+
});
|
|
65
|
+
setPage(1);
|
|
66
|
+
}}
|
|
59
67
|
>
|
|
60
68
|
<Form.Item name="action" label={t("system:oplog.filterAction")}>
|
|
61
69
|
<Input allowClear />
|
|
@@ -66,25 +74,42 @@ export default function OplogPage() {
|
|
|
66
74
|
<Form.Item name="module" label={t("system:oplog.filterModule")}>
|
|
67
75
|
<Input allowClear />
|
|
68
76
|
</Form.Item>
|
|
69
|
-
<Form.Item name="limit" label={t("system:oplog.filterLimit")} initialValue={50}>
|
|
70
|
-
<InputNumber min={1} max={200} />
|
|
71
|
-
</Form.Item>
|
|
72
77
|
<Form.Item>
|
|
73
78
|
<Space>
|
|
74
79
|
<Button type="primary" htmlType="submit">{t("system:common.search")}</Button>
|
|
75
|
-
<Button
|
|
80
|
+
<Button
|
|
81
|
+
onClick={() => {
|
|
82
|
+
setFilters({});
|
|
83
|
+
setPage(1);
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
76
86
|
{t("system:common.reset")}
|
|
77
87
|
</Button>
|
|
78
88
|
</Space>
|
|
79
89
|
</Form.Item>
|
|
80
90
|
</Form>
|
|
81
|
-
{query.data?.truncated ? <Alert type="warning" showIcon message={t("system:oplog.truncated")} /> : null}
|
|
82
91
|
<Table
|
|
83
92
|
rowKey="id"
|
|
84
93
|
loading={query.isLoading}
|
|
85
94
|
dataSource={query.data?.list ?? []}
|
|
86
95
|
columns={columns}
|
|
87
|
-
pagination={{
|
|
96
|
+
pagination={{
|
|
97
|
+
current: page,
|
|
98
|
+
pageSize: size,
|
|
99
|
+
total: query.data?.total ?? 0,
|
|
100
|
+
showSizeChanger: true,
|
|
101
|
+
pageSizeOptions: PAGE_SIZE_OPTIONS,
|
|
102
|
+
showTotal: total => t("system:oplog.total", { total }),
|
|
103
|
+
onChange: (nextPage, nextSize) => {
|
|
104
|
+
// 改每页条数后原页码可能越界:统一回第 1 页
|
|
105
|
+
if (nextSize !== size) {
|
|
106
|
+
setSize(nextSize);
|
|
107
|
+
setPage(1);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
setPage(nextPage);
|
|
111
|
+
},
|
|
112
|
+
}}
|
|
88
113
|
/>
|
|
89
114
|
</Space>
|
|
90
115
|
);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { SystemPermissionsGetData, SystemRolesGetData } from "../../__client
|
|
1
|
+
import type { SystemPermissionsGetData, SystemRolesGetData } from "../../__client";
|
|
2
2
|
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
4
|
import { Alert, Space, Table, Tabs, Tag } from "antd";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
|
|
7
|
-
import { systemPermissionsGet, systemRolesGet } from "../../__client
|
|
7
|
+
import { systemPermissionsGet, systemRolesGet } from "../../__client";
|
|
8
8
|
import { isForbidden } from "../errors";
|
|
9
9
|
import { ForbiddenPanel } from "../forbidden";
|
|
10
|
+
import { visibleRoles } from "./visible-roles";
|
|
10
11
|
|
|
11
12
|
type RoleRow = SystemRolesGetData[number];
|
|
12
13
|
type PermRow = SystemPermissionsGetData[number];
|
|
@@ -19,6 +20,7 @@ export default function RolesPage() {
|
|
|
19
20
|
const { t } = useTranslation();
|
|
20
21
|
const rolesQuery = useQuery({ queryKey: ["system", "roles"], queryFn: systemRolesGet });
|
|
21
22
|
const permsQuery = useQuery({ queryKey: ["system", "permissions"], queryFn: systemPermissionsGet });
|
|
23
|
+
const rows = visibleRoles(rolesQuery.data ?? []);
|
|
22
24
|
|
|
23
25
|
if ((rolesQuery.error && isForbidden(rolesQuery.error)) || (permsQuery.error && isForbidden(permsQuery.error)))
|
|
24
26
|
return <ForbiddenPanel t={t} error={rolesQuery.error ?? permsQuery.error} />;
|
|
@@ -36,7 +38,13 @@ export default function RolesPage() {
|
|
|
36
38
|
),
|
|
37
39
|
},
|
|
38
40
|
{ title: "module", dataIndex: "module" },
|
|
39
|
-
{
|
|
41
|
+
{
|
|
42
|
+
// R2:solution 角色带 title_key → 按当前语言实时翻译,title(安装期解析文本)兜底;
|
|
43
|
+
// custom/builtin 无 key 原样显示 title(对齐下方权限点 title_key 的渲染先例)
|
|
44
|
+
title: "title",
|
|
45
|
+
dataIndex: "title",
|
|
46
|
+
render: (_: string, row: RoleRow) => (row.title_key ? t(row.title_key, { defaultValue: row.title ?? "" }) : row.title),
|
|
47
|
+
},
|
|
40
48
|
{ title: t("system:rolesPage.holders"), dataIndex: "holders" },
|
|
41
49
|
{
|
|
42
50
|
title: t("system:rolesPage.permissions"),
|
|
@@ -75,7 +83,7 @@ export default function RolesPage() {
|
|
|
75
83
|
children: (
|
|
76
84
|
<>
|
|
77
85
|
<Alert style={{ marginBottom: 12 }} type="info" showIcon message={t("system:rolesPage.readonlyHint")} />
|
|
78
|
-
<Table rowKey="name" loading={rolesQuery.isLoading} dataSource={
|
|
86
|
+
<Table rowKey="name" loading={rolesQuery.isLoading} dataSource={rows} columns={roleColumns} pagination={{ hideOnSinglePage: true }} />
|
|
79
87
|
</>
|
|
80
88
|
),
|
|
81
89
|
},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 角色展示页的可见范围(纯函数,便于用例直接钉住,不必起 React)。
|
|
3
|
+
*
|
|
4
|
+
* superadmin 是平台级角色(跨租户),不属于「站点可分配的角色目录」;列在角色页只会让人
|
|
5
|
+
* 误以为能改它的绑定,故展示层隐去。
|
|
6
|
+
*
|
|
7
|
+
* **只在这一层过滤**:后端 listRoles() 必须原样返回 superadmin——成员资格页
|
|
8
|
+
* (users/roles.tsx)还要拿它作为可授予项(仅 superadmin 可勾选,见那里的 disabled 逻辑)。
|
|
9
|
+
*/
|
|
10
|
+
export const HIDDEN_ROLE = "superadmin";
|
|
11
|
+
|
|
12
|
+
export function visibleRoles<T extends { name: string }>(roles: readonly T[]): T[] {
|
|
13
|
+
return roles.filter(r => r.name !== HIDDEN_ROLE);
|
|
14
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { TFunction } from "i18next";
|
|
2
2
|
|
|
3
|
-
import type { SystemSettingsGetData } from "../../__client
|
|
3
|
+
import type { SystemSettingsGetData } from "../../__client";
|
|
4
4
|
|
|
5
5
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
6
|
import { App, Button, Card, Input, Space, Switch, Tooltip } from "antd";
|
|
7
7
|
import { useState } from "react";
|
|
8
8
|
import { useTranslation } from "react-i18next";
|
|
9
9
|
|
|
10
|
-
import { systemSettingsGet, systemSettingsPut } from "../../__client
|
|
10
|
+
import { systemSettingsGet, systemSettingsPut } from "../../__client";
|
|
11
11
|
import { explainError, isForbidden } from "../errors";
|
|
12
12
|
import { ForbiddenPanel } from "../forbidden";
|
|
13
13
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /system/users 行级操作门禁:只有 superadmin 能改 superadmin 账号。
|
|
3
|
+
*
|
|
4
|
+
* 与后端 `domain/users.ts::assertCanManageTarget` 同一条红线(只有 superadmin 能改
|
|
5
|
+
* superadmin 的口令/状态/资料/角色)。前端这层只为「不给会 403 的按钮」——灰色可点却不
|
|
6
|
+
* 生效比报错更糟——真正的防线在服务端:admin 直打接口同样会被 403 挡住。
|
|
7
|
+
*
|
|
8
|
+
* 单独成文件是为了可测:vitest 跑在 node 环境,没有 jsdom,整页 render 不了。
|
|
9
|
+
*/
|
|
10
|
+
export const PLATFORM_ROLE = "superadmin";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param myRoles 当前登录者的角色
|
|
14
|
+
* @param targetRoles 行上用户的角色
|
|
15
|
+
* @returns 是否允许对目标账号执行管理操作(改密/启停/改资料/成员资格)
|
|
16
|
+
*/
|
|
17
|
+
export function canManageUser(myRoles: readonly string[], targetRoles: readonly string[]): boolean {
|
|
18
|
+
if (!targetRoles.includes(PLATFORM_ROLE))
|
|
19
|
+
return true;
|
|
20
|
+
return myRoles.includes(PLATFORM_ROLE);
|
|
21
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SystemUsersGetData } from "../../__client
|
|
1
|
+
import type { SystemUsersGetData } from "../../__client";
|
|
2
2
|
|
|
3
3
|
import { PlusOutlined } from "@ant-design/icons";
|
|
4
4
|
import { useUserStore } from "@oj-module/runtime";
|
|
@@ -9,16 +9,19 @@ import { useTranslation } from "react-i18next";
|
|
|
9
9
|
|
|
10
10
|
import { useNavigate } from "react-router";
|
|
11
11
|
|
|
12
|
-
import { systemDepartmentsGet, systemUsersForbiddenPut, systemUsersGet, systemUsersPasswordPut, systemUsersPost } from "../../__client
|
|
12
|
+
import { systemDepartmentsGet, systemUsersForbiddenPut, systemUsersGet, systemUsersPasswordPut, systemUsersPost } from "../../__client";
|
|
13
13
|
import { buildTreeData, subtreeIds } from "../departments/tree";
|
|
14
14
|
import { explainError, isForbidden } from "../errors";
|
|
15
15
|
import { ForbiddenPanel } from "../forbidden";
|
|
16
|
+
import { canManageUser } from "./can-manage";
|
|
16
17
|
|
|
17
18
|
type UserRow = SystemUsersGetData[number];
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* 用户管理(C1):GET /system/users 列表 + 建号 / 禁用切换 / 重置口令。
|
|
21
22
|
* 本人行禁用一切自操作(后端 assertNotSelf 400 兜底,前端不给会失败的按钮,R3);
|
|
23
|
+
* superadmin 行也禁用一切操作,除非当前登录者是 superadmin(红线:只有 superadmin 能改
|
|
24
|
+
* superadmin——后端 assertCanManageTarget 403 兜底,前端把按钮置灰);
|
|
22
25
|
* 成员资格入口:superadmin 与 **本租户 admin** 均可见(授予 admin 已下放到租户内,
|
|
23
26
|
* 但授予 superadmin 仍只许 superadmin——见 domain/users.ts::assertMembershipAllowed)。
|
|
24
27
|
* 部门列标出主部门,顶部可按部门筛选(含子部门)——筛选在前端做,名单本来就是一页全量。
|
|
@@ -117,8 +120,10 @@ export default function UsersPage() {
|
|
|
117
120
|
title={t("system:users.forbidden")}
|
|
118
121
|
description={`${row.username} → ${forbidden ? "false" : "true"}`}
|
|
119
122
|
onConfirm={() => forbiddenMut.mutate({ uid: row.id, forbidden: !forbidden })}
|
|
123
|
+
// 置灰的 Switch 不会触发 Popconfirm,这里只是把「为什么点不了」挡在确认框之前
|
|
124
|
+
disabled={String(row.id) === me || !canManageUser(myRoles, row.roles)}
|
|
120
125
|
>
|
|
121
|
-
<Switch size="small" checked={forbidden} disabled={String(row.id) === me} />
|
|
126
|
+
<Switch size="small" checked={forbidden} disabled={String(row.id) === me || !canManageUser(myRoles, row.roles)} />
|
|
122
127
|
</Popconfirm>
|
|
123
128
|
{row.must_change ? <Tag color="orange">{t("system:users.firstLoginHint")}</Tag> : null}
|
|
124
129
|
</Space>
|
|
@@ -127,20 +132,23 @@ export default function UsersPage() {
|
|
|
127
132
|
{
|
|
128
133
|
title: t("system:users.columns.actions"),
|
|
129
134
|
key: "actions",
|
|
130
|
-
render: (_: unknown, row: UserRow) =>
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
135
|
+
render: (_: unknown, row: UserRow) => {
|
|
136
|
+
const manageable = canManageUser(myRoles, row.roles);
|
|
137
|
+
return (
|
|
138
|
+
<Space>
|
|
139
|
+
<Button size="small" disabled={String(row.id) === me || !manageable} onClick={() => setPwdTarget(row)}>
|
|
140
|
+
{t("system:users.resetPwd")}
|
|
141
|
+
</Button>
|
|
142
|
+
{canManageMembership
|
|
143
|
+
? (
|
|
144
|
+
<Button size="small" type="link" disabled={!manageable} onClick={() => navigate(`/system/users/${row.id}/roles`)}>
|
|
145
|
+
{t("system:users.membership")}
|
|
146
|
+
</Button>
|
|
147
|
+
)
|
|
148
|
+
: null}
|
|
149
|
+
</Space>
|
|
150
|
+
);
|
|
151
|
+
},
|
|
144
152
|
},
|
|
145
153
|
];
|
|
146
154
|
|
|
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
|
|
6
6
|
|
|
7
7
|
import { useNavigate, useParams } from "react-router";
|
|
8
8
|
|
|
9
|
-
import { systemRolesGet, systemUsersGet, systemUsersRolesPut } from "../../__client
|
|
9
|
+
import { systemRolesGet, systemUsersGet, systemUsersRolesPut } from "../../__client";
|
|
10
10
|
import { explainError, isForbidden } from "../errors";
|
|
11
11
|
import { ForbiddenPanel } from "../forbidden";
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@ import { SettingOutlined } from "@ant-design/icons";
|
|
|
4
4
|
|
|
5
5
|
import { createElement, lazy } from "react";
|
|
6
6
|
|
|
7
|
-
import { createSystemClient } from "./__client
|
|
7
|
+
import { createSystemClient } from "./__client";
|
|
8
8
|
|
|
9
9
|
const Users = lazy(() => import("./pages/users"));
|
|
10
10
|
const UserRoles = lazy(() => import("./pages/users/roles"));
|
|
@@ -17,6 +17,9 @@ export const API_PREFIX = "/web";
|
|
|
17
17
|
/** 认领身份前缀(契约 apiPrefix,字面等于模块目录名):跨模块认领护栏对比基准 */
|
|
18
18
|
export const MODULE_PREFIX = "/web";
|
|
19
19
|
|
|
20
|
+
/** 认领方模块(web.config clientOwners 指定):跨模块认领护栏对比基准 */
|
|
21
|
+
export const MODULE_OWNER = "/app";
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* 模块 entry 的 onInit 里一行创建(构造即 install):完成 apiPrefix 登记 +
|
|
22
25
|
* scoped request 绑定,返回绑好前缀的端点函数集合。一模块一 client;
|
|
@@ -28,8 +31,8 @@ export function createWebClient(ctx: ModuleContext) {
|
|
|
28
31
|
// 单槽、卸载互相耦合;跨模块需求应由本模块创建后经 provider 暴露。
|
|
29
32
|
// 注意对比基准是 MODULE_PREFIX(目录名)而非 API_PREFIX——D-M8 映射时线上前缀
|
|
30
33
|
// 属于别的命名空间,认领身份仍按目录名。
|
|
31
|
-
if (import.meta.env.DEV && ctx.module.name !==
|
|
32
|
-
console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${
|
|
34
|
+
if (import.meta.env.DEV && ctx.module.name !== MODULE_OWNER.slice(1)) {
|
|
35
|
+
console.warn(`[ojm-api] 模块 "${ctx.module.name}" 正在认领 ${MODULE_PREFIX} 的 client——跨模块认领会共享 request 单槽、卸载互相耦合;应由 "${MODULE_OWNER.slice(1)}" 模块在自身 onInit 创建,跨模块需求经 provider 暴露。`);
|
|
33
36
|
}
|
|
34
37
|
ctx.register.apiPrefix(API_PREFIX);
|
|
35
38
|
bindRequest(ctx.utils.request);
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
platformMarketTrustPost,
|
|
29
29
|
platformMarketUninstallImpactGet,
|
|
30
30
|
platformMarketUninstallPost,
|
|
31
|
-
} from "../../../
|
|
31
|
+
} from "../../../app/web/_platform/__client";
|
|
32
32
|
|
|
33
33
|
// 绑定运行时 request 到生成 client 的模块级单槽(生成 client 是静态单例,必须由某处
|
|
34
34
|
// bindRequest;此处兜底确保市场子应用无论挂载顺序都能拿到请求实例)。与 _platform 模块
|
|
@@ -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/
|
|
8
|
-
import { createLdapLogin } from "../src/
|
|
7
|
+
import { esc, firstAttr } from "../src/app/api/auth/_shared/ldap";
|
|
8
|
+
import { createLdapLogin } from "../src/app/api/auth/_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/
|
|
4
|
+
import type { SessionDeps } from "../src/app/api/auth/_shared/session";
|
|
5
5
|
|
|
6
6
|
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
7
|
-
import { assertPermission } from "../src/
|
|
8
|
-
import { createSession } from "../src/
|
|
7
|
+
import { assertPermission } from "../src/app/api/_platform/_shared/service/infra/access";
|
|
8
|
+
import { createSession } from "../src/app/api/auth/_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/
|
|
8
|
+
import { loginBlocked, loginFailed, loginSucceeded, resetLoginThrottle } from "../src/app/api/_platform/_shared/service/infra/rate";
|
|
9
9
|
import { installDb } from "./fixture";
|
|
10
10
|
|
|
11
11
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// 后端 BDD 夹具:node:sqlite 内存库 + **真实迁移文件**建表,装到 globalThis.db——
|
|
2
2
|
// 与 oj 运行时注入的全局同名同面,service 代码不改一行即可被测。
|
|
3
|
-
// 夹具直接读 src/<模块>/
|
|
3
|
+
// 夹具直接读 src/app/api/<模块>/migrations/*.sql,与迁移不可能漂移(沿用 oj-wiki 先例)。
|
|
4
4
|
//
|
|
5
5
|
// **构造器垫片(db.table / listTables)**:oj 的构造器是二进制内的 Rust 实现,Node 侧无可复用
|
|
6
6
|
// 模块,故这里按手册契约(oj-api-dev api-manual「查询构造器」)写一层**最小 JS 渲染层**——
|
|
@@ -33,6 +33,8 @@ const { join, dirname } = req("node:path");
|
|
|
33
33
|
const { fileURLToPath } = req("node:url");
|
|
34
34
|
|
|
35
35
|
const SRC = join(dirname(fileURLToPath(import.meta.url)), "..", "src");
|
|
36
|
+
/** 后端模块根(0.2.55 布局:`src/app/api/<模块>`);迁移按目录发现,不在夹具里抄模块清单。 */
|
|
37
|
+
const API_ROOT = join(SRC, "app", "api");
|
|
36
38
|
|
|
37
39
|
export const ADMIN = 1;
|
|
38
40
|
|
|
@@ -465,9 +467,9 @@ function listTables(dbo: any, prefix?: string): string[] {
|
|
|
465
467
|
/** 建内存库 + 注入全局;返回 DatabaseSync 供用例直插数据/断言。 */
|
|
466
468
|
export function installDb(): any {
|
|
467
469
|
const dbo = new DatabaseSync(":memory:");
|
|
468
|
-
// 重放 src 下全部模块的迁移(方言专属文件除外)
|
|
469
|
-
for (const mod of readdirSync(
|
|
470
|
-
const dir = join(
|
|
470
|
+
// 重放 src/app/api 下全部模块的迁移(方言专属文件除外)
|
|
471
|
+
for (const mod of readdirSync(API_ROOT)) {
|
|
472
|
+
const dir = join(API_ROOT, mod, "migrations");
|
|
471
473
|
if (!existsSync(dir))
|
|
472
474
|
continue;
|
|
473
475
|
for (const f of readdirSync(dir).filter((f: string) => f.endsWith(".sql") && !/\.(?:mysql|pg)\.sql$/.test(f)).sort())
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// (真实迁移建表 / 运行时全局 db 同面 / 事务往返)——S0 spike 的「一条真实判权 AC + 形态证明」。
|
|
4
4
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
5
5
|
|
|
6
|
-
import { decideAccess, moduleOf } from "../src/
|
|
6
|
+
import { decideAccess, moduleOf } from "../src/app/api/_platform/_shared/service/infra/guard";
|
|
7
7
|
import { ADMIN, installDb } from "./fixture";
|
|
8
8
|
|
|
9
9
|
const as = (roles: string[], bindings: Record<string, string[]> = {}) => ({ roles, bindings });
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
// 只保证读回自己写出的内容;任何不符格式的字节一律视为损坏 → 空状态,损坏上下文并入
|
|
5
5
|
// 读结果(corruptNote 出口,禁 console——release isolate console 抛 BadResource,Finding A)。
|
|
6
6
|
// fs 依赖经 globalThis.fs 注入(平台 isolate 注入 FsApi;测试注入 node:fs/promises 适配)。
|
|
7
|
-
import type { FsFace } from "../../src/
|
|
7
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
8
8
|
import * as fsp from "node:fs/promises";
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
|
|
12
12
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
13
|
-
import { atomicWriteText } from "../../src/
|
|
14
|
-
import { createStateStore } from "../../src/
|
|
13
|
+
import { atomicWriteText } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
14
|
+
import { createStateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
15
15
|
|
|
16
16
|
const g = globalThis as any;
|
|
17
17
|
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
// 与 PEM 私钥块实体(header 后跟 ≥100 字符 base64 体;tasks.ts redact 正则与测试假体
|
|
6
6
|
// 体长 <100 不误伤)双口径扫描。
|
|
7
7
|
// ③ 集成(market-api.spec):信任库为空 + bootstrapKey 注入 → cdn 安装直达 done 不落 needs_trust。
|
|
8
|
-
import type { FsFace } from "../../src/
|
|
8
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
9
9
|
import * as fsp from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { dirname, join } from "node:path";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
14
|
-
import { createTrustStore } from "../../src/
|
|
15
|
-
import { BOOTSTRAP_KEY, seedBootstrapKey } from "../../src/
|
|
14
|
+
import { createTrustStore } from "../../src/app/api/_platform/_lifecycle/trust";
|
|
15
|
+
import { BOOTSTRAP_KEY, seedBootstrapKey } from "../../src/app/api/_platform/market/bootstrap";
|
|
16
16
|
|
|
17
17
|
const g = globalThis as any;
|
|
18
18
|
|
|
@@ -8,19 +8,19 @@
|
|
|
8
8
|
// 快照逐数组 ⊇ 声明,少 = 注册丢失判失败)collect-all 全败齐报。
|
|
9
9
|
// entry 浏览器加载不在安装器验(Node import 必假绿——设计 §4.1),注释钉口径。
|
|
10
10
|
// fetch/sha384/query/reload 面经 ctx 注入 stub(同 steps-fs 范式),fs 为 globalThis.fs 面。
|
|
11
|
-
import type { FsFace } from "../../src/
|
|
12
|
-
import type { StateStore } from "../../src/
|
|
13
|
-
import type { DeployWebContext, ModuleEntry } from "../../src/
|
|
14
|
-
import type { ReloadContext, ReloadFace, ReloadResult } from "../../src/
|
|
15
|
-
import type { SmokeContext } from "../../src/
|
|
11
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
12
|
+
import type { StateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
13
|
+
import type { DeployWebContext, ModuleEntry } from "../../src/app/api/_platform/_lifecycle/steps/deploy-web";
|
|
14
|
+
import type { ReloadContext, ReloadFace, ReloadResult } from "../../src/app/api/_platform/_lifecycle/steps/reload";
|
|
15
|
+
import type { SmokeContext } from "../../src/app/api/_platform/_lifecycle/steps/smoke";
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
17
|
import * as fsp from "node:fs/promises";
|
|
18
18
|
import { tmpdir } from "node:os";
|
|
19
19
|
import { join } from "node:path";
|
|
20
20
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
21
|
-
import { deployWeb, posixPath, upsertModulesJson } from "../../src/
|
|
22
|
-
import { reloadAndAssert } from "../../src/
|
|
23
|
-
import { probeUrlOf, smoke } from "../../src/
|
|
21
|
+
import { deployWeb, posixPath, upsertModulesJson } from "../../src/app/api/_platform/_lifecycle/steps/deploy-web";
|
|
22
|
+
import { reloadAndAssert } from "../../src/app/api/_platform/_lifecycle/steps/reload";
|
|
23
|
+
import { probeUrlOf, smoke } from "../../src/app/api/_platform/_lifecycle/steps/smoke";
|
|
24
24
|
|
|
25
25
|
const g = globalThis as any;
|
|
26
26
|
|
|
@@ -12,22 +12,22 @@
|
|
|
12
12
|
// 过期(30min)可接管。setEnabled 四处同写(D12/AC-P1-6):锁摘除/恢复 + sidecar + route + modules。
|
|
13
13
|
// 步骤面全 stub 注入(DIP):fetch/exec/tar/reload 不真跑;register/smoke/audit 走真实内存库夹具。
|
|
14
14
|
/* eslint-disable test/prefer-lowercase-title -- 任务/AC 编号是验收锚点,保留大写(register.spec 同约定) */
|
|
15
|
-
import type { FsFace } from "../../src/
|
|
16
|
-
import type { InstallRequest } from "../../src/
|
|
17
|
-
import type { StateStore } from "../../src/
|
|
18
|
-
import type { ExecFace } from "../../src/
|
|
15
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
16
|
+
import type { InstallRequest } from "../../src/app/api/_platform/_lifecycle/installer";
|
|
17
|
+
import type { StateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
18
|
+
import type { ExecFace } from "../../src/app/api/_platform/_lifecycle/steps/extract";
|
|
19
19
|
import { createHash } from "node:crypto";
|
|
20
20
|
import * as fsp from "node:fs/promises";
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
import { join } from "node:path";
|
|
23
23
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
24
24
|
import { defaultTestKey, nodeVerifyEd25519, signedArchiveFor } from "../../../src/lifecycle/__tests__/helpers";
|
|
25
|
-
import { atomicWriteText } from "../../src/
|
|
26
|
-
import { gcVersions, reconcile, runInstall, setEnabled, STAGES } from "../../src/
|
|
27
|
-
import { acquireTaskLock, commitLockEntry, parseLock, readLock, serializeLock, writeLock } from "../../src/
|
|
28
|
-
import { createStateStore } from "../../src/
|
|
29
|
-
import { getTask, readTasks, redact, sweepTimedOut, writeTask } from "../../src/
|
|
30
|
-
import { createTrustStore } from "../../src/
|
|
25
|
+
import { atomicWriteText } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
26
|
+
import { gcVersions, reconcile, runInstall, setEnabled, STAGES } from "../../src/app/api/_platform/_lifecycle/installer";
|
|
27
|
+
import { acquireTaskLock, commitLockEntry, parseLock, readLock, serializeLock, writeLock } from "../../src/app/api/_platform/_lifecycle/lock";
|
|
28
|
+
import { createStateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
29
|
+
import { getTask, readTasks, redact, sweepTimedOut, writeTask } from "../../src/app/api/_platform/_lifecycle/tasks";
|
|
30
|
+
import { createTrustStore } from "../../src/app/api/_platform/_lifecycle/trust";
|
|
31
31
|
import { installDb } from "../fixture";
|
|
32
32
|
|
|
33
33
|
const g = globalThis as any;
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
// 简报 `task/:id` 段参数形态在模板 http 面无先例(contacts/detail?id= 同款 query 惯例),备案于任务报告。
|
|
8
8
|
// 步骤面全 stub 注入(DIP):fetch/exec/reload 不真跑;register/smoke/audit 走真实内存库夹具。
|
|
9
9
|
/* eslint-disable test/prefer-lowercase-title -- 端点动词/路径是验收锚点,保留大写(installer.spec 同约定) */
|
|
10
|
-
import type { FsFace } from "../../src/
|
|
11
|
-
import type { FetchFace } from "../../src/
|
|
12
|
-
import type { ExecFace } from "../../src/
|
|
13
|
-
import type { ReloadFace } from "../../src/
|
|
14
|
-
import type { MarketEnv } from "../../src/
|
|
10
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
11
|
+
import type { FetchFace } from "../../src/app/api/_platform/_lifecycle/steps/download";
|
|
12
|
+
import type { ExecFace } from "../../src/app/api/_platform/_lifecycle/steps/extract";
|
|
13
|
+
import type { ReloadFace } from "../../src/app/api/_platform/_lifecycle/steps/reload";
|
|
14
|
+
import type { MarketEnv } from "../../src/app/api/_platform/market/api";
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import { readFileSync } from "node:fs";
|
|
17
17
|
import * as fsp from "node:fs/promises";
|
|
@@ -22,14 +22,14 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
22
22
|
import { parse } from "yaml";
|
|
23
23
|
import { defaultTestKey, nodeVerifyEd25519, signedArchiveFor } from "../../../src/lifecycle/__tests__/helpers";
|
|
24
24
|
import { signIndex } from "../../../src/publish";
|
|
25
|
-
import { readLock, writeLock } from "../../src/
|
|
26
|
-
import { compareVersions } from "../../src/
|
|
27
|
-
import { createStateStore } from "../../src/
|
|
28
|
-
import { getTask, writeTask } from "../../src/
|
|
29
|
-
import { createTrustStore } from "../../src/
|
|
30
|
-
import { invalidateAllUsers } from "../../src/
|
|
31
|
-
import { createMarketApi, marketEnv, parseVersionsJson, versionsJsonPathOf } from "../../src/
|
|
32
|
-
import { localIndexSource } from "../../src/
|
|
25
|
+
import { readLock, writeLock } from "../../src/app/api/_platform/_lifecycle/lock";
|
|
26
|
+
import { compareVersions } from "../../src/app/api/_platform/_lifecycle/semver";
|
|
27
|
+
import { createStateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
28
|
+
import { getTask, writeTask } from "../../src/app/api/_platform/_lifecycle/tasks";
|
|
29
|
+
import { createTrustStore } from "../../src/app/api/_platform/_lifecycle/trust";
|
|
30
|
+
import { invalidateAllUsers } from "../../src/app/api/_platform/_shared/service/infra/access";
|
|
31
|
+
import { createMarketApi, marketEnv, parseVersionsJson, versionsJsonPathOf } from "../../src/app/api/_platform/market/api";
|
|
32
|
+
import { localIndexSource } from "../../src/app/api/_platform/market/index-source";
|
|
33
33
|
import { installDb } from "../fixture";
|
|
34
34
|
|
|
35
35
|
function hexToBytes(hex: string): Uint8Array {
|
|
@@ -305,7 +305,7 @@ describe("权限门(R9:市场编排 superadmin 独占,meta 登录即可)
|
|
|
305
305
|
it("pair-pin:meta apiVersion === _platform/manifest.yaml version(手工镜像漂移防护,P2-9)", async () => {
|
|
306
306
|
// API_VERSION(market/api.ts)与 _platform/manifest.yaml version 为手工同步的双真源;
|
|
307
307
|
// 本测试经 meta 端点间接钉住 API_VERSION,漂移即红(peerPlatform 预检口径失真)。
|
|
308
|
-
const manifestPath = join(dirname(fileURLToPath(import.meta.url)), "../../src/
|
|
308
|
+
const manifestPath = join(dirname(fileURLToPath(import.meta.url)), "../../src/app/api/_platform/manifest.yaml");
|
|
309
309
|
const manifestVersion = (parse(readFileSync(manifestPath, "utf8")) as { version: string }).version;
|
|
310
310
|
const api = createMarketApi(makeEnv());
|
|
311
311
|
g.http = { user: { id: 1 } };
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
// rollbackGuard 纯函数:目标产物 max seq < 账本 head = 降版部署,禁止(OJ-9/M003 同源红线);
|
|
8
8
|
// seq 为数值非版本号,直接数值比较(semver.ts 不适用)。
|
|
9
9
|
// exec/fs 面注入 stub(同 steps-fs 范式),不真跑 oj/sqlite。
|
|
10
|
-
import type { FsFace } from "../../src/
|
|
11
|
-
import type { StateStore } from "../../src/
|
|
12
|
-
import type { ExecFace } from "../../src/
|
|
13
|
-
import type { MigrateContext } from "../../src/
|
|
10
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
11
|
+
import type { StateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
12
|
+
import type { ExecFace } from "../../src/app/api/_platform/_lifecycle/steps/extract";
|
|
13
|
+
import type { MigrateContext } from "../../src/app/api/_platform/_lifecycle/steps/migrate";
|
|
14
14
|
import * as fsp from "node:fs/promises";
|
|
15
15
|
import { tmpdir } from "node:os";
|
|
16
16
|
import { join } from "node:path";
|
|
17
17
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
18
|
-
import { parseLock } from "../../src/
|
|
19
|
-
import { buildMigrateCmd, maxAppliedSeq, migrate, migrateSvcDirOf, parseMigrateOutput, rollbackGuard } from "../../src/
|
|
18
|
+
import { parseLock } from "../../src/app/api/_platform/_lifecycle/lock";
|
|
19
|
+
import { buildMigrateCmd, maxAppliedSeq, migrate, migrateSvcDirOf, parseMigrateOutput, rollbackGuard } from "../../src/app/api/_platform/_lifecycle/steps/migrate";
|
|
20
20
|
|
|
21
21
|
const g = globalThis as any;
|
|
22
22
|
const DB_BYTES = new TextEncoder().encode("sqlite-header-bytes\n");
|