@oj-module/cli 0.2.53 → 0.2.56
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/SKILL.md +4 -4
- package/devkit/manual.md +79 -65
- package/package.json +2 -2
- package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
- package/shell-dist/assets/runtime.js +7 -4
- 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__/templates-tenant-scope.test.ts +3 -2
- package/src/alias-paths.ts +11 -12
- package/src/builtin.ts +10 -3
- package/src/config.ts +9 -0
- package/src/contract/__tests__/client-path.test.ts +30 -0
- package/src/contract/__tests__/emit-client.test.ts +20 -2
- package/src/contract/__tests__/handler-scan.test.ts +23 -0
- 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 +11 -7
- package/src/contract/client-path.ts +30 -0
- package/src/contract/emit-client.ts +27 -6
- package/src/contract/handler-scan.ts +40 -3
- package/src/contract/run.ts +15 -5
- package/src/init.ts +29 -3
- package/src/layout.ts +72 -16
- 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/templates/README.md +49 -43
- package/templates/init.include.yaml +31 -19
- package/templates/openapi.json +1488 -120
- 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/{_platform/api → app/api/_platform}/contacts/api.ts +29 -1
- package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +25 -1
- 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/{_platform/api → app/api/_platform}/schema.yaml +5 -0
- package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +60 -1
- 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/{auth/api → app/api/auth}/api.ts +59 -0
- package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +37 -1
- package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +23 -0
- package/templates/src/{notification/api → app/api/notification}/api.ts +17 -0
- package/templates/src/{notification/api → app/api/notification}/del/api.ts +2 -0
- package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
- package/templates/src/{system/api → app/api/system}/roles/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/settings/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/password/api.ts +3 -0
- package/templates/src/{system/api → app/api/system}/users/roles/api.ts +3 -0
- package/templates/src/app/api/web/get-async-routes/api.ts +23 -0
- package/templates/src/app/api/web/hello/api.ts +22 -0
- package/templates/src/{web/api → app/api/web}/user-info/api.ts +21 -1
- package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +99 -35
- package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +108 -61
- package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +133 -13
- package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +134 -33
- package/templates/src/app/web/entry.ts +77 -0
- package/templates/src/{home/web/__client/api.ts → app/web/home/__client/index.ts} +5 -2
- package/templates/src/app/web/home/routes.ts +41 -0
- package/templates/src/app/web/login/routes.ts +71 -0
- package/templates/src/{notification/web → app/web/notification}/__client/api.schemas.ts +14 -0
- package/templates/src/{notification/web/__client/api.ts → app/web/notification/__client/index.ts} +67 -20
- package/templates/src/{notification/web → app/web/notification}/pages/center/index.tsx +1 -1
- package/templates/src/app/web/notification/routes.ts +70 -0
- package/templates/src/{personal-center/web/__client/api.ts → app/web/personal-center/__client/index.ts} +5 -2
- package/templates/src/{personal-center/web → app/web/personal-center}/pages/my-profile/index.tsx +1 -1
- package/templates/src/app/web/personal-center/routes.ts +49 -0
- package/templates/src/{system/web → app/web/system}/__client/api.schemas.ts +29 -22
- package/templates/src/{system/web/__client/api.ts → app/web/system/__client/index.ts} +103 -58
- package/templates/src/{system/web → app/web/system}/locales/en-US.json +2 -3
- package/templates/src/{system/web → app/web/system}/locales/zh-CN.json +2 -3
- package/templates/src/{system/web → app/web/system}/pages/departments/index.tsx +2 -2
- package/templates/src/{system/web → app/web/system}/pages/login-methods/index.tsx +1 -1
- package/templates/src/{system/web → app/web/system}/pages/oplog/index.tsx +44 -19
- package/templates/src/{system/web → app/web/system}/pages/roles/index.tsx +5 -3
- package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
- package/templates/src/{system/web → 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/{system/web → app/web/system}/pages/users/index.tsx +23 -15
- package/templates/src/{system/web → app/web/system}/pages/users/roles.tsx +1 -1
- package/templates/src/{system/web → app/web/system}/pages/wecom/index.tsx +12 -3
- package/templates/src/{system/web/entry.ts → app/web/system/routes.ts} +25 -36
- package/templates/src/app/web/web/__client/api.schemas.ts +36 -0
- package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +38 -11
- 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/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 +10 -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 +24 -15
- package/vendor/host-versions.json +3 -3
- package/templates/src/home/web/entry.ts +0 -49
- package/templates/src/login/web/entry.ts +0 -79
- package/templates/src/notification/web/entry.ts +0 -84
- package/templates/src/personal-center/web/entry.ts +0 -60
- package/templates/src/web/api/get-async-routes/api.ts +0 -8
- package/templates/src/web/api/hello/api.ts +0 -10
- package/templates/src/web/web/__client/api.schemas.ts +0 -8
- 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/installer.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/register.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/roles.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/domain/solution-perms.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}/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/{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}/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/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}/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}/users/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
- /package/templates/src/{home/web → app/web/home}/__client/api.schemas.ts +0 -0
- /package/templates/src/{home/web → app/web/home}/locales/en-US.json +0 -0
- /package/templates/src/{home/web → app/web/home}/locales/zh-CN.json +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/bar-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/card-list.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/line-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/components/pie-chart.tsx +0 -0
- /package/templates/src/{home/web → app/web/home}/pages/index.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/auth-provider.ts +0 -0
- /package/templates/src/{login/web → app/web/login}/locales/en-US.json +0 -0
- /package/templates/src/{login/web → app/web/login}/locales/zh-CN.json +0 -0
- /package/templates/src/{login/web → app/web/login}/pages/change-password.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/pages/login.tsx +0 -0
- /package/templates/src/{login/web → app/web/login}/wecom.ts +0 -0
- /package/templates/src/{notification/web → app/web/notification}/locales/en-US.json +0 -0
- /package/templates/src/{notification/web → app/web/notification}/locales/zh-CN.json +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/__client/api.schemas.ts +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/locales/en-US.json +0 -0
- /package/templates/src/{personal-center/web → app/web/personal-center}/locales/zh-CN.json +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/departments/sync-bar.tsx +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/departments/tree.ts +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/errors.ts +0 -0
- /package/templates/src/{system/web → app/web/system}/pages/forbidden.tsx +0 -0
|
@@ -191,7 +191,7 @@ export default function WecomAdminPage() {
|
|
|
191
191
|
queryKey: ["system", "wecom-tenant-admin", corps.map(c => c.corpId).join(",")],
|
|
192
192
|
queryFn: async () => {
|
|
193
193
|
const out: Record<string, TenantAdminState> = {};
|
|
194
|
-
await Promise.all(corps.map(async c => {
|
|
194
|
+
await Promise.all(corps.map(async (c) => {
|
|
195
195
|
out[c.corpId] = await fetchTenantAdmin(c.corpId);
|
|
196
196
|
}));
|
|
197
197
|
return out;
|
|
@@ -244,7 +244,13 @@ export default function WecomAdminPage() {
|
|
|
244
244
|
title: t("system:wecom.tenantAdmin.action"),
|
|
245
245
|
key: "action",
|
|
246
246
|
render: (_: unknown, row: { corpId: string, name: string | null }) => (
|
|
247
|
-
<Button
|
|
247
|
+
<Button
|
|
248
|
+
size="small"
|
|
249
|
+
onClick={() => {
|
|
250
|
+
setResetTarget(row);
|
|
251
|
+
setResetPwd("");
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
248
254
|
{t("system:wecom.tenantAdmin.reset")}
|
|
249
255
|
</Button>
|
|
250
256
|
),
|
|
@@ -433,7 +439,10 @@ export default function WecomAdminPage() {
|
|
|
433
439
|
<Modal
|
|
434
440
|
open={resetTarget != null}
|
|
435
441
|
title={t("system:wecom.tenantAdmin.resetTitle")}
|
|
436
|
-
onCancel={() => {
|
|
442
|
+
onCancel={() => {
|
|
443
|
+
setResetTarget(null);
|
|
444
|
+
setResetPwd("");
|
|
445
|
+
}}
|
|
437
446
|
onOk={() => resetMut.mutate({ corpId: resetTarget!.corpId, password: resetPwd })}
|
|
438
447
|
confirmLoading={resetMut.isPending}
|
|
439
448
|
okButtonProps={{ disabled: resetPwd.length < 6 }}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import type { AppRouteRecordRaw } from "@oj-module/runtime";
|
|
1
|
+
import type { AppRouteRecordRaw, ModuleContext } from "@oj-module/runtime";
|
|
2
2
|
|
|
3
3
|
import { SettingOutlined } from "@ant-design/icons";
|
|
4
|
-
import { defineModule } from "@oj-module/runtime";
|
|
5
4
|
|
|
6
5
|
import { createElement, lazy } from "react";
|
|
7
6
|
|
|
8
|
-
import { createSystemClient } from "./__client
|
|
7
|
+
import { createSystemClient } from "./__client";
|
|
9
8
|
|
|
10
9
|
const Users = lazy(() => import("./pages/users"));
|
|
11
10
|
const UserRoles = lazy(() => import("./pages/users/roles"));
|
|
@@ -16,7 +15,24 @@ const Settings = lazy(() => import("./pages/settings"));
|
|
|
16
15
|
const LoginMethods = lazy(() => import("./pages/login-methods"));
|
|
17
16
|
const WecomAdmin = lazy(() => import("./pages/wecom"));
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* `/system` 根的角色门禁(对齐后端 assertSystemAdmin,access.ts:87)——
|
|
20
|
+
* superadmin **或** admin 均可,两者必须同时保留:D12(2026-10-22)起账号名=角色名,
|
|
21
|
+
* admin 与 superadmin 是两个独立账号(seed.sql),只留 ["admin"] 会把 superadmin
|
|
22
|
+
* 挡在门外(注册期过滤 → 路由消失 → 登录后 404 兜底)。改这两个值前先跑
|
|
23
|
+
* tests/system-guard.regression.spec.ts。
|
|
24
|
+
*/
|
|
25
|
+
const SYSTEM_ROLES = ["admin", "superadmin"];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 系统管理根 `/system`:框架管理面(用户/成员资格/角色权限/操作日志/站点设置/登录方式),
|
|
29
|
+
* 数据源为 oj 后端 /api/system/*(模板 api 模块)。__client 由 `ojm api` 生成。
|
|
30
|
+
*
|
|
31
|
+
* 路由级门禁(B16)挂在根上:非系统管理员整棵子树不注入、菜单不可见(等价于原先的
|
|
32
|
+
* 模块级 requiredRoles——聚合后模块级会把 /home 一起挡掉,故必须下移到根路由);
|
|
33
|
+
* API 级 403 由 assertSystemAdmin + service 层硬 enforcement 兜底。
|
|
34
|
+
*/
|
|
35
|
+
export const routes: AppRouteRecordRaw[] = [
|
|
20
36
|
{
|
|
21
37
|
path: "/system",
|
|
22
38
|
handle: {
|
|
@@ -25,6 +41,7 @@ const routes: AppRouteRecordRaw[] = [
|
|
|
25
41
|
// 负 order = 底部固定区:系统管理 pin 在侧边栏底部(2026-10-20 序轴约定)
|
|
26
42
|
order: -100,
|
|
27
43
|
layout: "container",
|
|
44
|
+
roles: SYSTEM_ROLES,
|
|
28
45
|
},
|
|
29
46
|
children: [
|
|
30
47
|
{
|
|
@@ -74,35 +91,7 @@ const routes: AppRouteRecordRaw[] = [
|
|
|
74
91
|
},
|
|
75
92
|
];
|
|
76
93
|
|
|
77
|
-
/**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* devkit manual §2.2)。
|
|
82
|
-
*/
|
|
83
|
-
export default defineModule({
|
|
84
|
-
name: "system",
|
|
85
|
-
description: "系统管理模块(框架管理面)",
|
|
86
|
-
version: "0.1.0",
|
|
87
|
-
peerRuntime: ">=0.0.0",
|
|
88
|
-
// 路由级门禁(B16):非系统管理员不注入 /system 路由、菜单不可见;
|
|
89
|
-
// API 级 403 由 assertSystemAdmin + service 层硬 enforcement 兜底。
|
|
90
|
-
// 角色口径对齐后端 assertSystemAdmin(access.ts:87)——superadmin **或**
|
|
91
|
-
// admin 均可,两者必须同时保留:D12(2026-10-22)起账号名=角色名,admin 与
|
|
92
|
-
// superadmin 是两个独立账号(seed.sql),只留 ["admin"] 会把 superadmin 挡在
|
|
93
|
-
// 门外(注册期过滤 → 路由消失 → 登录后 404 兜底)。改这两个值前先跑
|
|
94
|
-
// tests/system-guard.regression.spec.ts(只留 ["admin"] 会立刻变红)。
|
|
95
|
-
config: { requiredRoles: ["admin", "superadmin"] },
|
|
96
|
-
routes,
|
|
97
|
-
i18n: {
|
|
98
|
-
"zh-CN": () => import("./locales/zh-CN.json"),
|
|
99
|
-
"en-US": () => import("./locales/en-US.json"),
|
|
100
|
-
},
|
|
101
|
-
lifecycle: {
|
|
102
|
-
async onInit(ctx) {
|
|
103
|
-
// 构造即接线:登记 /system 前缀 + 绑定 scoped request(D11 前缀收敛),
|
|
104
|
-
// 页面直接 import 生成的端点函数(模块级单槽 req 已由本调用绑定)。
|
|
105
|
-
createSystemClient(ctx);
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
});
|
|
94
|
+
/** 构造即接线:登记 /system 前缀 + 绑定 scoped request(D11 前缀收敛)。 */
|
|
95
|
+
export async function onInit(ctx: ModuleContext) {
|
|
96
|
+
createSystemClient(ctx);
|
|
97
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// 生成物:ojm api 从契约生成,勿手改(改动请改契约文件后重跑 ojm api)
|
|
3
|
+
// AC-D15:仅供 DEV 校验动态 import,生产构建不进产物
|
|
4
|
+
import { z } from "@oj-module/runtime";
|
|
5
|
+
|
|
6
|
+
export const schemas = {
|
|
7
|
+
"webGetAsyncRoutesGet": {
|
|
8
|
+
data: z.array(z.object({
|
|
9
|
+
"path": z.string().optional(),
|
|
10
|
+
"component": z.string().optional(),
|
|
11
|
+
"children": z.array(z.object({
|
|
12
|
+
|
|
13
|
+
})).optional()
|
|
14
|
+
})),
|
|
15
|
+
},
|
|
16
|
+
"webHelloGet": {
|
|
17
|
+
data: z.object({
|
|
18
|
+
"message": z.string(),
|
|
19
|
+
"user": z.number().nullable()
|
|
20
|
+
}),
|
|
21
|
+
},
|
|
22
|
+
"webUserInfoGet": {
|
|
23
|
+
data: z.object({
|
|
24
|
+
"id": z.string(),
|
|
25
|
+
"avatar": z.string(),
|
|
26
|
+
"username": z.string(),
|
|
27
|
+
"displayName": z.string(),
|
|
28
|
+
"email": z.string(),
|
|
29
|
+
"phoneNumber": z.string(),
|
|
30
|
+
"description": z.string(),
|
|
31
|
+
"roles": z.array(z.string()),
|
|
32
|
+
"mustChange": z.boolean(),
|
|
33
|
+
"permissions": z.array(z.string())
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -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);
|
|
@@ -64,14 +67,22 @@ async function toApiError(e: unknown): Promise<unknown> {
|
|
|
64
67
|
return e;
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
export
|
|
70
|
+
export type WebGetAsyncRoutesGetData = z.infer<(typeof schemas)["webGetAsyncRoutesGet"]["data"]>;
|
|
71
|
+
|
|
72
|
+
export async function webGetAsyncRoutesGet(): Promise<WebGetAsyncRoutesGetData> {
|
|
68
73
|
const client = ensureReq();
|
|
69
74
|
try {
|
|
70
|
-
const env = await client.get(`web/get-async-routes`).json<OjEnvelope<
|
|
75
|
+
const env = await client.get(`web/get-async-routes`).json<OjEnvelope<WebGetAsyncRoutesGetData>>();
|
|
71
76
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
72
77
|
if (typeof env.code === "number" && env.code !== 0)
|
|
73
78
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
74
|
-
const data = env.data as
|
|
79
|
+
const data = env.data as WebGetAsyncRoutesGetData;
|
|
80
|
+
if (import.meta.env.DEV) {
|
|
81
|
+
const { schemas } = await import("./api.schemas");
|
|
82
|
+
const r = schemas["webGetAsyncRoutesGet"].data.safeParse(data);
|
|
83
|
+
if (!r.success)
|
|
84
|
+
throw new ContractApiError(-1, `[契约违例] webGetAsyncRoutesGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
85
|
+
}
|
|
75
86
|
return data;
|
|
76
87
|
}
|
|
77
88
|
catch (e) {
|
|
@@ -79,14 +90,22 @@ export async function webGetAsyncRoutesGet(): Promise<unknown> {
|
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
|
|
82
|
-
export
|
|
93
|
+
export type WebHelloGetData = z.infer<(typeof schemas)["webHelloGet"]["data"]>;
|
|
94
|
+
|
|
95
|
+
export async function webHelloGet(): Promise<WebHelloGetData> {
|
|
83
96
|
const client = ensureReq();
|
|
84
97
|
try {
|
|
85
|
-
const env = await client.get(`web/hello`).json<OjEnvelope<
|
|
98
|
+
const env = await client.get(`web/hello`).json<OjEnvelope<WebHelloGetData>>();
|
|
86
99
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
87
100
|
if (typeof env.code === "number" && env.code !== 0)
|
|
88
101
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
89
|
-
const data = env.data as
|
|
102
|
+
const data = env.data as WebHelloGetData;
|
|
103
|
+
if (import.meta.env.DEV) {
|
|
104
|
+
const { schemas } = await import("./api.schemas");
|
|
105
|
+
const r = schemas["webHelloGet"].data.safeParse(data);
|
|
106
|
+
if (!r.success)
|
|
107
|
+
throw new ContractApiError(-1, `[契约违例] webHelloGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
108
|
+
}
|
|
90
109
|
return data;
|
|
91
110
|
}
|
|
92
111
|
catch (e) {
|
|
@@ -94,14 +113,22 @@ export async function webHelloGet(): Promise<unknown> {
|
|
|
94
113
|
}
|
|
95
114
|
}
|
|
96
115
|
|
|
97
|
-
export
|
|
116
|
+
export type WebUserInfoGetData = z.infer<(typeof schemas)["webUserInfoGet"]["data"]>;
|
|
117
|
+
|
|
118
|
+
export async function webUserInfoGet(): Promise<WebUserInfoGetData> {
|
|
98
119
|
const client = ensureReq();
|
|
99
120
|
try {
|
|
100
|
-
const env = await client.get(`web/user-info`).json<OjEnvelope<
|
|
121
|
+
const env = await client.get(`web/user-info`).json<OjEnvelope<WebUserInfoGetData>>();
|
|
101
122
|
// 2xx + code!==0 也是业务错误(§6.2 通道 a):oj 不会这么发,但契约机制的价值恰是防漂移
|
|
102
123
|
if (typeof env.code === "number" && env.code !== 0)
|
|
103
124
|
throw new ContractApiError(env.code, env.msg ?? "业务错误(信封 code 非 0)");
|
|
104
|
-
const data = env.data as
|
|
125
|
+
const data = env.data as WebUserInfoGetData;
|
|
126
|
+
if (import.meta.env.DEV) {
|
|
127
|
+
const { schemas } = await import("./api.schemas");
|
|
128
|
+
const r = schemas["webUserInfoGet"].data.safeParse(data);
|
|
129
|
+
if (!r.success)
|
|
130
|
+
throw new ContractApiError(-1, `[契约违例] webUserInfoGet 响应与契约不符:${r.error.issues.map(i => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ")}`);
|
|
131
|
+
}
|
|
105
132
|
return data;
|
|
106
133
|
}
|
|
107
134
|
catch (e) {
|
|
@@ -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");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SolutionState, StateStore } from "../../src/
|
|
2
|
-
import type { InstallContext } from "../../src/
|
|
1
|
+
import type { SolutionState, StateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
2
|
+
import type { InstallContext } from "../../src/app/api/_platform/_lifecycle/steps/preflight";
|
|
3
3
|
// BDD:安装预检规则引擎(P1-5,R7/R8/R9/R24,十阶段状态机 stage 1)。
|
|
4
4
|
// 规则真源:docs/prd/solution/202610171254-lifecycle-manifest-contract.md(C2-01~33 安装列);
|
|
5
5
|
// 期望真源:packages/cli/src/lifecycle/__tests__/fixtures/(fixture-valid 零违规、fixture-invalid 七码齐报)。
|
|
@@ -12,7 +12,7 @@ import { fileURLToPath } from "node:url";
|
|
|
12
12
|
|
|
13
13
|
import { describe, expect, it } from "vitest";
|
|
14
14
|
import { parse } from "yaml";
|
|
15
|
-
import { preflight } from "../../src/
|
|
15
|
+
import { preflight } from "../../src/app/api/_platform/_lifecycle/steps/preflight";
|
|
16
16
|
|
|
17
17
|
const FIXTURES = join(dirname(fileURLToPath(import.meta.url)), "../../../src/lifecycle/__tests__/fixtures");
|
|
18
18
|
const VALID = parse(readFileSync(join(FIXTURES, "fixture-valid/manifest.yaml"), "utf8")) as any;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/* eslint-disable test/prefer-lowercase-title -- 任务/AC 编号是验收锚点,保留大写(DB/P1-5) */
|
|
9
9
|
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
10
10
|
|
|
11
|
-
import { checkOccupancy, queryAllRegistered, queryRegistered, registerSolution } from "../../src/
|
|
11
|
+
import { checkOccupancy, queryAllRegistered, queryRegistered, registerSolution } from "../../src/app/api/_platform/_lifecycle/steps/register";
|
|
12
12
|
import { installDb } from "../fixture";
|
|
13
13
|
|
|
14
14
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// 无 prerelease > 有 prerelease;「1.0」「1.0.0」「1.0.0.0」视为相等(安装器容错口径)。
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
5
|
|
|
6
|
-
import { compareVersions } from "../../src/
|
|
6
|
+
import { compareVersions } from "../../src/app/api/_platform/_lifecycle/semver";
|
|
7
7
|
|
|
8
8
|
const cases: Array<[a: string, b: string, expected: -1 | 0 | 1]> = [
|
|
9
9
|
// 主版本数值比较(非字典序)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { Buffer } from "node:buffer";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { describe, expect, it } from "vitest";
|
|
7
|
-
import { bytesToBase64, sha384B64, sha384Bytes } from "../../src/
|
|
7
|
+
import { bytesToBase64, sha384B64, sha384Bytes } from "../../src/app/api/_platform/_lifecycle/sha384";
|
|
8
8
|
|
|
9
9
|
const hex = (bytes: Uint8Array): string => Array.from(bytes, b => b.toString(16).padStart(2, "0")).join("");
|
|
10
10
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/* eslint-disable test/prefer-lowercase-title -- 端点路径是验收锚点 */
|
|
6
6
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
|
-
import api from "../../src/
|
|
8
|
+
import api from "../../src/app/api/_platform/solutions/api";
|
|
9
9
|
import { installDb } from "../fixture";
|
|
10
10
|
|
|
11
11
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// 四条负向是 G7 的重点:水位写坏 / 表不存在 / 值非法都必须**拒**,不能静默当「第一次见」——
|
|
5
5
|
// 静默重置等于把「防回放」降级成「每次都当第一次见」,攻击者先破坏状态再回放即可穿透。
|
|
6
6
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
7
|
-
import { guardAndRecordSourceSeq, readSourceSeq, SOURCE_SEQ_TABLE } from "../../src/
|
|
7
|
+
import { guardAndRecordSourceSeq, readSourceSeq, SOURCE_SEQ_TABLE } from "../../src/app/api/_platform/_lifecycle/source-seq";
|
|
8
8
|
import { installDb } from "../fixture";
|
|
9
9
|
|
|
10
10
|
const SRC = "https://cdn.example.com/solutions";
|