@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
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
// 命令构造为纯函数,argv 逐字断言(与平台 exec 白名单逐字对齐,S1-2 基座);
|
|
7
7
|
// exec/fetch/sha256 面经 ctx 注入 stub,不真跑网络;合法夹具集成用例的 exec stub 落到真实系统 tar
|
|
8
8
|
// (与生产同路径:isolate 不内嵌解压,exec.run 系统 tar)。
|
|
9
|
-
import type { FsFace } from "../../src/
|
|
10
|
-
import type { StateStore } from "../../src/
|
|
11
|
-
import type { DownloadContext } from "../../src/
|
|
12
|
-
import type { ExecFace, ExtractContext } from "../../src/
|
|
13
|
-
import type { VerifyContext } from "../../src/
|
|
9
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
10
|
+
import type { StateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
11
|
+
import type { DownloadContext } from "../../src/app/api/_platform/_lifecycle/steps/download";
|
|
12
|
+
import type { ExecFace, ExtractContext } from "../../src/app/api/_platform/_lifecycle/steps/extract";
|
|
13
|
+
import type { VerifyContext } from "../../src/app/api/_platform/_lifecycle/steps/verify";
|
|
14
14
|
import { execFile as execFileCb } from "node:child_process";
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import * as fsp from "node:fs/promises";
|
|
@@ -19,10 +19,10 @@ import { join } from "node:path";
|
|
|
19
19
|
import { promisify } from "node:util";
|
|
20
20
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
21
21
|
import { defaultTestKey, nodeVerifyEd25519, signedArchiveFor } from "../../../src/lifecycle/__tests__/helpers";
|
|
22
|
-
import { archiveFileOf, download } from "../../src/
|
|
23
|
-
import { buildExtractCmd, buildListCmd, checkModuleManifest, extract } from "../../src/
|
|
24
|
-
import { verify } from "../../src/
|
|
25
|
-
import { createTrustStore } from "../../src/
|
|
22
|
+
import { archiveFileOf, download } from "../../src/app/api/_platform/_lifecycle/steps/download";
|
|
23
|
+
import { buildExtractCmd, buildListCmd, checkModuleManifest, extract } from "../../src/app/api/_platform/_lifecycle/steps/extract";
|
|
24
|
+
import { verify } from "../../src/app/api/_platform/_lifecycle/steps/verify";
|
|
25
|
+
import { createTrustStore } from "../../src/app/api/_platform/_lifecycle/trust";
|
|
26
26
|
|
|
27
27
|
const execFileP = promisify(execFileCb);
|
|
28
28
|
const g = globalThis as any;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as fsp from "node:fs/promises";
|
|
6
6
|
import { describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
|
-
import { appendAnonymousPaths, bumpInstallSeq, ensureReloadApi, hasAnchor, insertAnchor } from "../../src/
|
|
8
|
+
import { appendAnonymousPaths, bumpInstallSeq, ensureReloadApi, hasAnchor, insertAnchor } from "../../src/app/api/_platform/_lifecycle/text-edit";
|
|
9
9
|
|
|
10
10
|
describe("insertAnchor(R18)", () => {
|
|
11
11
|
it("带注释的 config.yaml 插入后注释/缩进/空行/键序逐字保留", () => {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
// 拒绝:绝对路径、任何 `..` 段、l/h 条目、空成员名、反斜杠路径;`./` 前缀相对合法。
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { MAX_ENTRIES, MAX_PACKAGE_BYTES, MAX_SINGLE_ENTRY_BYTES, MAX_UNPACKED_BYTES } from "../../src/
|
|
8
|
-
import { accumulateTarVolume, checkTarVolumeLimits, extractTarEntrySize, validateTarListing } from "../../src/
|
|
7
|
+
import { MAX_ENTRIES, MAX_PACKAGE_BYTES, MAX_SINGLE_ENTRY_BYTES, MAX_UNPACKED_BYTES } from "../../src/app/api/_platform/_lifecycle/limits";
|
|
8
|
+
import { accumulateTarVolume, checkTarVolumeLimits, extractTarEntrySize, validateTarListing } from "../../src/app/api/_platform/_lifecycle/tgz-guard";
|
|
9
9
|
|
|
10
10
|
describe("validateTarListing(R1)", () => {
|
|
11
11
|
it("正常成员列表通过", () => {
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
// store 层:空库/幂等/首次绑定不可改/多 key/吊销/损坏 fail-closed/.bak 回落/并发读不见半截/审计。
|
|
3
3
|
// 端点层:GET /market/trust、POST /market/trust/key、DELETE /market/trust/key?key_id=(del 动词 + query,system/roles 同款先例)。
|
|
4
4
|
/* eslint-disable test/prefer-lowercase-title -- 端点动词/路径是验收锚点,保留大写(market-api.spec 同约定) */
|
|
5
|
-
import type { FsFace } from "../../src/
|
|
6
|
-
import type { MarketEnv } from "../../src/
|
|
5
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
6
|
+
import type { MarketEnv } from "../../src/app/api/_platform/market/api";
|
|
7
7
|
import { Buffer } from "node:buffer";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import * as fsp from "node:fs/promises";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
13
|
-
import { createTrustStore, isValidKeyId } from "../../src/
|
|
14
|
-
import { invalidateAllUsers } from "../../src/
|
|
15
|
-
import { createMarketApi, marketEnv } from "../../src/
|
|
13
|
+
import { createTrustStore, isValidKeyId } from "../../src/app/api/_platform/_lifecycle/trust";
|
|
14
|
+
import { invalidateAllUsers } from "../../src/app/api/_platform/_shared/service/infra/access";
|
|
15
|
+
import { createMarketApi, marketEnv } from "../../src/app/api/_platform/market/api";
|
|
16
16
|
import { installDb } from "../fixture";
|
|
17
17
|
|
|
18
18
|
const g = globalThis as any;
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
// 夹具:本仓范式(node:sqlite 真实迁移建表 + 真实 fs 面 g.fs);market_history 表由平台迁移
|
|
6
6
|
// 0012(IF NOT EXISTS)随 installDb 重放建立,守卫语义(表不存在静默跳过)单列一例。
|
|
7
7
|
/* eslint-disable test/prefer-lowercase-title -- 端点动词/路径是验收锚点,保留大写(market-api.spec 同约定) */
|
|
8
|
-
import type { FsFace } from "../../src/
|
|
9
|
-
import type { MarketEnv } from "../../src/
|
|
8
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
9
|
+
import type { MarketEnv } from "../../src/app/api/_platform/market/api";
|
|
10
10
|
import * as fsp from "node:fs/promises";
|
|
11
11
|
import { tmpdir } from "node:os";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
13
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
14
|
-
import { readLock, writeLock } from "../../src/
|
|
15
|
-
import { createStateStore } from "../../src/
|
|
16
|
-
import { collectRetainedTables, moduleTablePrefix } from "../../src/
|
|
17
|
-
import { invalidateAllUsers } from "../../src/
|
|
18
|
-
import { createMarketApi } from "../../src/
|
|
14
|
+
import { readLock, writeLock } from "../../src/app/api/_platform/_lifecycle/lock";
|
|
15
|
+
import { createStateStore } from "../../src/app/api/_platform/_lifecycle/state";
|
|
16
|
+
import { collectRetainedTables, moduleTablePrefix } from "../../src/app/api/_platform/_lifecycle/uninstall";
|
|
17
|
+
import { invalidateAllUsers } from "../../src/app/api/_platform/_shared/service/infra/access";
|
|
18
|
+
import { createMarketApi } from "../../src/app/api/_platform/market/api";
|
|
19
19
|
import { installDb } from "../fixture";
|
|
20
20
|
|
|
21
21
|
const g = globalThis as any;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// BDD:深检后端四项 + 端点(P2-7,C2-42)+ SSRF 三钉。
|
|
2
2
|
// 纯 diff 函数 / 探针分类 / SSRF 钉(出站拦截 / header 清洗 / 不跟随重定向)+ 端点门(401/403/404)+ 编排。
|
|
3
3
|
/* eslint-disable test/prefer-lowercase-title -- 端点动词/路径是验收锚点,保留大写(market-api.spec 同约定) */
|
|
4
|
-
import type { FsFace } from "../../src/
|
|
5
|
-
import type { SolutionRouteRow } from "../../src/
|
|
4
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
5
|
+
import type { SolutionRouteRow } from "../../src/app/api/_platform/_lifecycle/verify-checks";
|
|
6
6
|
import * as fsp from "node:fs/promises";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
@@ -18,9 +18,9 @@ import {
|
|
|
18
18
|
sha384B64,
|
|
19
19
|
|
|
20
20
|
verifyRouteReachability,
|
|
21
|
-
} from "../../src/
|
|
22
|
-
import { siteOrigin } from "../../src/
|
|
23
|
-
import { createSolutionsApi, solutionsEnv } from "../../src/
|
|
21
|
+
} from "../../src/app/api/_platform/_lifecycle/verify-checks";
|
|
22
|
+
import { siteOrigin } from "../../src/app/api/_platform/market/api";
|
|
23
|
+
import { createSolutionsApi, solutionsEnv } from "../../src/app/api/_platform/solutions/api";
|
|
24
24
|
import { installDb } from "../fixture";
|
|
25
25
|
|
|
26
26
|
const g = globalThis as any;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// BDD:P2-8 深检报告结构 + 留存 N=10 + 可信性项(trust_state)+ i18n 降级项 + 设值不进报告。
|
|
2
2
|
// 纯模块单测(verify-report.ts)+ 端点编排(persist-on-POST / GET verify/last / 降级项 / secret 不泄漏)。
|
|
3
3
|
/* eslint-disable test/prefer-lowercase-title -- 端点动词/路径是验收锚点,保留大写(verify-checks.spec 同约定) */
|
|
4
|
-
import type { FsFace } from "../../src/
|
|
5
|
-
import type { VerifyReport } from "../../src/
|
|
4
|
+
import type { FsFace } from "../../src/app/api/_platform/_lifecycle/atomic";
|
|
5
|
+
import type { VerifyReport } from "../../src/app/api/_platform/_lifecycle/verify-report";
|
|
6
6
|
import * as fsp from "node:fs/promises";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
persistReport,
|
|
13
13
|
VERIFY_REPORTS_KEEP,
|
|
14
14
|
verifyReportsDirOf,
|
|
15
|
-
} from "../../src/
|
|
16
|
-
import { createSolutionsApi, solutionsEnv } from "../../src/
|
|
15
|
+
} from "../../src/app/api/_platform/_lifecycle/verify-report";
|
|
16
|
+
import { createSolutionsApi, solutionsEnv } from "../../src/app/api/_platform/solutions/api";
|
|
17
17
|
import { installDb } from "../fixture";
|
|
18
18
|
|
|
19
19
|
const g = globalThis as any;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OrgDeps } from "../src/
|
|
1
|
+
import type { OrgDeps } from "../src/app/api/_platform/_shared/service/domain/org";
|
|
2
2
|
|
|
3
3
|
// BDD:组织架构领域(0016,方案 A1+A2)——CRUD 基线 + 归属权(D13)+ 保底出口(D14)。
|
|
4
4
|
//
|
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
updateDepartment,
|
|
24
24
|
updateMember,
|
|
25
25
|
upsertDepartment,
|
|
26
|
-
} from "../src/
|
|
27
|
-
import { deleteUser, listUsers, updateUserProfile } from "../src/
|
|
26
|
+
} from "../src/app/api/_platform/_shared/service/domain/org";
|
|
27
|
+
import { deleteUser, listUsers, updateUserProfile } from "../src/app/api/_platform/_shared/service/domain/users";
|
|
28
28
|
import { ADMIN, installDb } from "./fixture";
|
|
29
29
|
|
|
30
30
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -263,12 +263,16 @@ describe("用户侧(改资料 / 删号)", () => {
|
|
|
263
263
|
expect(dbo.prepare("SELECT COUNT(*) c FROM sys_refresh_token WHERE user_id = ?").get(uid)).toMatchObject({ c: 0 });
|
|
264
264
|
});
|
|
265
265
|
|
|
266
|
-
it("
|
|
266
|
+
it("删号:禁止删自己;非 superadmin 删 superadmin → 403(最后超管的实际防线)", async () => {
|
|
267
267
|
await expect(deleteUser(ADMIN, ADMIN)).rejects.toMatchObject({ status: 400 });
|
|
268
268
|
const solo = mkUser("u_sup");
|
|
269
269
|
dbo.prepare("INSERT INTO sys_user_role (user_id, role_name) VALUES (?, 'superadmin')").run(solo);
|
|
270
|
-
|
|
271
|
-
//
|
|
270
|
+
// 目标门禁先于「最后一个 superadmin」计数:普通 admin 连碰都碰不到它。
|
|
271
|
+
// 计数兜底(400)因此在真实路径上不可达——操作者本身是 superadmin 时,
|
|
272
|
+
// 库里必然已有 ≥2 个 superadmin——保留它只为挡住未来的新写路径。
|
|
273
|
+
await expect(deleteUser(ADMIN, solo)).rejects.toMatchObject({ status: 403 });
|
|
274
|
+
expect(dbo.prepare("SELECT COUNT(*) c FROM users WHERE id = ?").get(solo)).toMatchObject({ c: 1 });
|
|
275
|
+
// 操作者升为 superadmin 后允许删(第二个超管在场)
|
|
272
276
|
dbo.prepare("INSERT INTO sys_user_role (user_id, role_name) VALUES (?, 'superadmin')").run(ADMIN);
|
|
273
277
|
await deleteUser(ADMIN, solo);
|
|
274
278
|
expect(dbo.prepare("SELECT COUNT(*) c FROM users WHERE id = ?").get(solo)).toMatchObject({ c: 0 });
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
// 反过来也钉住:返回字段与 scope 无关,消费模块不该按档位分支解析。
|
|
9
9
|
//
|
|
10
10
|
// 另外钉住 §9.1 阻断项:通讯录只出 activated=1,同步灌进来的「从未登录」账号不得被检索到。
|
|
11
|
-
import type { OrgDeps } from "../src/
|
|
11
|
+
import type { OrgDeps } from "../src/app/api/_platform/_shared/service/domain/org";
|
|
12
12
|
|
|
13
13
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
14
|
-
import { contactDetail, searchContacts } from "../src/
|
|
14
|
+
import { contactDetail, searchContacts } from "../src/app/api/_platform/_shared/service/domain/contacts";
|
|
15
15
|
import {
|
|
16
16
|
addMember,
|
|
17
17
|
createDepartment,
|
|
18
18
|
deleteDepartment,
|
|
19
|
-
} from "../src/
|
|
19
|
+
} from "../src/app/api/_platform/_shared/service/domain/org";
|
|
20
20
|
import {
|
|
21
21
|
isMemberOf,
|
|
22
22
|
pageDepartments,
|
|
@@ -28,10 +28,10 @@ import {
|
|
|
28
28
|
resolveReader,
|
|
29
29
|
resolveReadFace,
|
|
30
30
|
resolveUserIds,
|
|
31
|
-
} from "../src/
|
|
32
|
-
import { createUser } from "../src/
|
|
33
|
-
import { invalidateUser } from "../src/
|
|
34
|
-
import { ensureWecomUser } from "../src/
|
|
31
|
+
} from "../src/app/api/_platform/_shared/service/domain/org-read";
|
|
32
|
+
import { createUser } from "../src/app/api/_platform/_shared/service/domain/users";
|
|
33
|
+
import { invalidateUser } from "../src/app/api/_platform/_shared/service/infra/access";
|
|
34
|
+
import { ensureWecomUser } from "../src/app/api/auth/_shared/wecom/login";
|
|
35
35
|
import { ADMIN, installDb } from "./fixture";
|
|
36
36
|
|
|
37
37
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
4
4
|
import { beforeAll, describe, expect, it } from "vitest";
|
|
5
5
|
|
|
6
|
-
import { likePattern, paged, pagedFactory } from "../src/
|
|
6
|
+
import { likePattern, paged, pagedFactory } from "../src/app/api/_platform/_shared/service/infra/query";
|
|
7
7
|
import { installDb } from "./fixture";
|
|
8
8
|
|
|
9
9
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
4
4
|
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
5
5
|
|
|
6
|
-
import { auditDeny, auditOp, recordOp, resetDenyAudit } from "../src/
|
|
6
|
+
import { auditDeny, auditOp, recordOp, resetDenyAudit } from "../src/app/api/_platform/_shared/service/infra/audit";
|
|
7
7
|
import { installDb } from "./fixture";
|
|
8
8
|
|
|
9
9
|
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, vi } from "vitest";
|
|
7
7
|
|
|
8
|
-
import { contactDetail, searchContacts } from "../src/
|
|
8
|
+
import { contactDetail, searchContacts } from "../src/app/api/_platform/_shared/service/domain/contacts";
|
|
9
9
|
import { installDb } from "./fixture";
|
|
10
10
|
|
|
11
11
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -84,7 +84,7 @@ describe("详情与限速", () => {
|
|
|
84
84
|
it("接口级限速:同用户突发超限 → 429", async () => {
|
|
85
85
|
const uid = mkUser("c_rate");
|
|
86
86
|
g.http = { user: { id: uid } };
|
|
87
|
-
const { rateLimit } = await import("../src/
|
|
87
|
+
const { rateLimit } = await import("../src/app/api/_platform/_shared/service/infra/rate");
|
|
88
88
|
// 窗口 60s / 限额 3(测试参数;生产端点各自定额)
|
|
89
89
|
for (let i = 0; i < 3; i++)
|
|
90
90
|
await rateLimit(`contacts:${uid}`, 3, 60_000);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
5
5
|
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { assertPermission, assertSuperAdmin, assertSystemAdmin, currentAccess, invalidateUser } from "../src/
|
|
7
|
+
import { assertPermission, assertSuperAdmin, assertSystemAdmin, currentAccess, invalidateUser } from "../src/app/api/_platform/_shared/service/infra/access";
|
|
8
8
|
import { installDb } from "./fixture";
|
|
9
9
|
|
|
10
10
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -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 { createRole, deleteRole, listPermissions, listRoles, updateBindings } from "../src/
|
|
8
|
-
import { assertPermission } from "../src/
|
|
7
|
+
import { createRole, deleteRole, listPermissions, listRoles, updateBindings } from "../src/app/api/_platform/_shared/service/domain/roles";
|
|
8
|
+
import { assertPermission } from "../src/app/api/_platform/_shared/service/infra/access";
|
|
9
9
|
import { installDb } from "./fixture";
|
|
10
10
|
|
|
11
11
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -156,4 +156,12 @@ describe("列表支撑(C2 页面数据源)", () => {
|
|
|
156
156
|
expect(perms.find(p => p.code === "wiki.old")?.deprecated).toBe(true);
|
|
157
157
|
expect(perms.find(p => p.code === "wiki.new")?.deprecated).toBe(false);
|
|
158
158
|
});
|
|
159
|
+
|
|
160
|
+
it("listRoles 原样返回 superadmin(只在 /system/roles 展示层隐去)", async () => {
|
|
161
|
+
// 成员资格页(users/roles.tsx)把 superadmin 当可授予项(仅 superadmin 可勾选),
|
|
162
|
+
// 页面数据源里少了它会让「授予超级管理员」直接不可用。过滤只做在展示层。
|
|
163
|
+
dbo.prepare("INSERT INTO sys_role (name, module, builtin) VALUES ('superadmin', 'framework', 1)").run();
|
|
164
|
+
const roles = await listRoles();
|
|
165
|
+
expect(roles.map(r => r.name)).toContain("superadmin");
|
|
166
|
+
});
|
|
159
167
|
});
|
|
@@ -8,7 +8,7 @@ import { beforeAll, describe, expect, it } from "vitest";
|
|
|
8
8
|
|
|
9
9
|
import { installDb } from "./fixture";
|
|
10
10
|
|
|
11
|
-
const SEED = join(dirname(fileURLToPath(import.meta.url)), "..", "src", "
|
|
11
|
+
const SEED = join(dirname(fileURLToPath(import.meta.url)), "..", "src", "app", "api", "_platform", "seed.sql");
|
|
12
12
|
let dbo: ReturnType<typeof installDb>;
|
|
13
13
|
|
|
14
14
|
beforeAll(() => {
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
3
3
|
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
4
4
|
|
|
5
|
-
import { listLoginMethods, listSettings, updateSetting } from "../src/
|
|
6
|
-
import {
|
|
5
|
+
import { listLoginMethods, listSettings, updateSetting } from "../src/app/api/_platform/_shared/service/domain/settings";
|
|
6
|
+
import { recordOp } from "../src/app/api/_platform/_shared/service/infra/audit";
|
|
7
|
+
import { searchOplog } from "../src/app/api/_platform/_shared/service/infra/oplog";
|
|
7
8
|
import { installDb } from "./fixture";
|
|
8
9
|
|
|
9
10
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -27,6 +28,8 @@ describe("AC1-29/D13:操作日志查询(admin 可查)", () => {
|
|
|
27
28
|
// 按 api-manual §1153 契约建模(引擎语义的忠实复刻,非新逻辑)。
|
|
28
29
|
function fakeTable() {
|
|
29
30
|
const conds: Array<{ test: unknown, cond: any }> = [];
|
|
31
|
+
// 分页同样只记录不执行:count 查询不该带 limit/offset,list 查询必须带上
|
|
32
|
+
const paging: { limit: number | null, offset: number | null } = { limit: null, offset: null };
|
|
30
33
|
const b: any = {
|
|
31
34
|
whereIf: (test: unknown, cond: any) => {
|
|
32
35
|
if (test !== undefined && test !== null && test !== false && !(Array.isArray(test) && test.length === 0))
|
|
@@ -35,17 +38,23 @@ describe("AC1-29/D13:操作日志查询(admin 可查)", () => {
|
|
|
35
38
|
},
|
|
36
39
|
select: () => b,
|
|
37
40
|
orderBy: () => b,
|
|
38
|
-
limit: () =>
|
|
39
|
-
|
|
41
|
+
limit: (n: number) => {
|
|
42
|
+
paging.limit = n;
|
|
43
|
+
return b;
|
|
44
|
+
},
|
|
45
|
+
offset: (n: number) => {
|
|
46
|
+
paging.offset = n;
|
|
47
|
+
return b;
|
|
48
|
+
},
|
|
40
49
|
// 固定非零 total:保证 count/list 两条路径都构造(total=0 跳过 list 的行为
|
|
41
50
|
// 由 query-utils.spec 的 pagedFactory 用例覆盖,这里只关心条件发射)
|
|
42
51
|
all: async () => [{ c: 42 }],
|
|
43
52
|
};
|
|
44
|
-
return { b, conds };
|
|
53
|
+
return { b, conds, paging };
|
|
45
54
|
}
|
|
46
55
|
|
|
47
|
-
/** 以假构造器跑 searchOplog,回传 count
|
|
48
|
-
async function
|
|
56
|
+
/** 以假构造器跑 searchOplog,回传 count/list 两次构造([0]=count,[1]=list) */
|
|
57
|
+
async function captureBuilt(filter: Parameters<typeof searchOplog>[0]) {
|
|
49
58
|
const built: Array<ReturnType<typeof fakeTable>> = [];
|
|
50
59
|
const prevDb = g.db;
|
|
51
60
|
g.db = {
|
|
@@ -63,6 +72,12 @@ describe("AC1-29/D13:操作日志查询(admin 可查)", () => {
|
|
|
63
72
|
}
|
|
64
73
|
expect(built).toHaveLength(2); // count + list 各构造一次
|
|
65
74
|
expect(built[1].conds).toEqual(built[0].conds); // mk 工厂:两组条件一致
|
|
75
|
+
return built;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** 回传 count 构造发射的条件 */
|
|
79
|
+
async function captureConds(filter: Parameters<typeof searchOplog>[0]) {
|
|
80
|
+
const built = await captureBuilt(filter);
|
|
66
81
|
return built[0].conds;
|
|
67
82
|
}
|
|
68
83
|
|
|
@@ -87,6 +102,61 @@ describe("AC1-29/D13:操作日志查询(admin 可查)", () => {
|
|
|
87
102
|
]);
|
|
88
103
|
expect(conds.some(c => (c.cond as { field?: string }).field === "level")).toBe(false);
|
|
89
104
|
});
|
|
105
|
+
|
|
106
|
+
it("page/limit 只作用在 list 查询:limit=size、offset=(page-1)*size,count 不带分页", async () => {
|
|
107
|
+
const [count, list] = await captureBuilt({ action: "user.create", page: 3, limit: 10 });
|
|
108
|
+
expect(count!.paging).toEqual({ limit: null, offset: null });
|
|
109
|
+
expect(list!.paging).toEqual({ limit: 10, offset: 20 });
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("缺省/非法分页参数:第 1 页 20 条,size 静默钳 200", async () => {
|
|
113
|
+
expect((await captureBuilt({}))[1]!.paging).toEqual({ limit: 20, offset: 0 });
|
|
114
|
+
expect((await captureBuilt({ page: 0, limit: "abc" }))[1]!.paging).toEqual({ limit: 20, offset: 0 });
|
|
115
|
+
expect((await captureBuilt({ page: 2, limit: 10_000 }))[1]!.paging).toEqual({ limit: 200, offset: 200 });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// 真库分页语义:上面用假构造器只钉「参数怎么发」,这里钉「切片/总数/还剩多少」算得对——
|
|
120
|
+
// 页导航能否正确显示页数全靠 total,靠 truncated 提示「结果被截断」的旧交互已删除。
|
|
121
|
+
describe("AC1-29:操作日志分页(真库切片 + total)", () => {
|
|
122
|
+
async function seedOplog(n: number) {
|
|
123
|
+
for (let i = 1; i <= n; i++)
|
|
124
|
+
await recordOp({ action: "test.page", module: "framework", target: `t${i}` });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
it("按 id 倒序切页:total 是全量而不是本页条数", async () => {
|
|
128
|
+
await seedOplog(5);
|
|
129
|
+
const p1 = await searchOplog({ page: 1, limit: 2 });
|
|
130
|
+
expect(p1.total).toBe(5);
|
|
131
|
+
expect(p1.list.map(r => r.target)).toEqual(["t5", "t4"]);
|
|
132
|
+
expect(p1.truncated).toBe(true);
|
|
133
|
+
|
|
134
|
+
const p2 = await searchOplog({ page: 2, limit: 2 });
|
|
135
|
+
expect(p2.list.map(r => r.target)).toEqual(["t3", "t2"]);
|
|
136
|
+
expect(p2.truncated).toBe(true);
|
|
137
|
+
|
|
138
|
+
// 末页:5 条 / 每页 2 → 第 3 页只剩 1 条,truncated=false(页导航据此停在第 3 页)
|
|
139
|
+
const p3 = await searchOplog({ page: 3, limit: 2 });
|
|
140
|
+
expect(p3.list.map(r => r.target)).toEqual(["t1"]);
|
|
141
|
+
expect(p3.truncated).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("越界页:list 为空但 total 仍为全量(前端据此纠正页码,而不是显示 0 条)", async () => {
|
|
145
|
+
await seedOplog(3);
|
|
146
|
+
const far = await searchOplog({ page: 99, limit: 20 });
|
|
147
|
+
expect(far.list).toEqual([]);
|
|
148
|
+
expect(far.total).toBe(3);
|
|
149
|
+
expect(far.truncated).toBe(false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("过滤与分页叠加:total 按过滤后的集合算", async () => {
|
|
153
|
+
await seedOplog(5);
|
|
154
|
+
await recordOp({ action: "other.act", module: "framework", target: "x" });
|
|
155
|
+
const r = await searchOplog({ action: "test.page", page: 1, limit: 2 });
|
|
156
|
+
expect(r.total).toBe(5);
|
|
157
|
+
expect(r.list).toHaveLength(2);
|
|
158
|
+
expect(r.list.every(x => x.action === "test.page")).toBe(true);
|
|
159
|
+
});
|
|
90
160
|
});
|
|
91
161
|
|
|
92
162
|
describe("PRD §4.3:系统设置", () => {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
5
5
|
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { uninstallSolution, upsertSolutionPerms } from "../src/
|
|
7
|
+
import { uninstallSolution, upsertSolutionPerms } from "../src/app/api/_platform/_shared/service/domain/solution-perms";
|
|
8
8
|
import { installDb } from "./fixture";
|
|
9
9
|
|
|
10
10
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -61,3 +61,32 @@ describe("users 表扩展(PRD §4.2 数据模型)", () => {
|
|
|
61
61
|
expect(String(source?.dflt_value)).toContain("local");
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
|
+
|
|
65
|
+
// 回归:0017 给 users 加工号列。事故形态是「列进了库、schema.yaml 白名单漏了」,
|
|
66
|
+
// 构造器在发 SQL 前就拒成 `unknown column 'employee_no' in on 'users'`,日志里没有 SQL 可查。
|
|
67
|
+
// 白名单那半边在 packages/cli/src/__tests__/templates-schema-columns.test.ts 钉;
|
|
68
|
+
// 这里钉库侧语义:列真的落库、租户内唯一、NULL 不占位、跨租户可重复。
|
|
69
|
+
describe("users.employee_no(0017 工号列)", () => {
|
|
70
|
+
function addUser(username: string, tenant: string, employeeNo: string | null) {
|
|
71
|
+
dbo.prepare("INSERT INTO users (username, password_hash, tenant_id, employee_no) VALUES (?, 'x', ?, ?)")
|
|
72
|
+
.run(username, tenant, employeeNo);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
it("迁移落出 employee_no 列", () => {
|
|
76
|
+
expect(colsOf("users")).toContain("employee_no");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("唯一索引按 (tenant_id, employee_no) 且是部分索引(NULL 不占位)", () => {
|
|
80
|
+
const idx = dbo.prepare("SELECT sql FROM sqlite_master WHERE type = 'index' AND name = 'uk_users_employee_no'").get() as { sql: string | null } | undefined;
|
|
81
|
+
expect(idx?.sql).toContain("tenant_id");
|
|
82
|
+
expect(idx?.sql).toContain("employee_no IS NOT NULL");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("同租户工号重复被拒,跨租户可重复,NULL 可多行", () => {
|
|
86
|
+
addUser("eno-a", "acme", "E-100");
|
|
87
|
+
expect(() => addUser("eno-b", "acme", "E-100")).toThrow(/UNIQUE/);
|
|
88
|
+
expect(() => addUser("eno-c", "globex", "E-100")).not.toThrow();
|
|
89
|
+
expect(() => addUser("eno-d", "acme", null)).not.toThrow();
|
|
90
|
+
expect(() => addUser("eno-e", "acme", null)).not.toThrow();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
// 禁止操作自己(AC1-10 注);roles 写 sys_user_role 唯一权威源 + 写时失效(AC1-7/D10);
|
|
4
4
|
// 禁用/重置口令级联删 refresh(§3.1 吊销联动)。
|
|
5
5
|
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写 */
|
|
6
|
-
import type { SessionDeps } from "../src/
|
|
6
|
+
import type { SessionDeps } from "../src/app/api/auth/_shared/session";
|
|
7
7
|
|
|
8
8
|
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
9
|
-
import { changePasswordByAdmin, createUser, listUsers, setForbidden, updateUserRoles } from "../src/
|
|
10
|
-
import { createSession } from "../src/
|
|
9
|
+
import { changePasswordByAdmin, createUser, deleteUser, listUsers, setForbidden, updateUserProfile, updateUserRoles } from "../src/app/api/_platform/_shared/service/domain/users";
|
|
10
|
+
import { createSession } from "../src/app/api/auth/_shared/session";
|
|
11
11
|
import { installDb } from "./fixture";
|
|
12
12
|
|
|
13
13
|
let dbo: ReturnType<typeof installDb>;
|
|
@@ -150,6 +150,58 @@ describe("B7:口令重置与禁用(级联吊销)", () => {
|
|
|
150
150
|
});
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
describe("红线:只有 superadmin 能改 superadmin 账号", () => {
|
|
154
|
+
function mkUserWithRole(username: string, role: string): number {
|
|
155
|
+
seedRole(role);
|
|
156
|
+
const uid = mkUser(username);
|
|
157
|
+
dbo.prepare("INSERT INTO sys_user_role (user_id, role_name) VALUES (?, ?)").run(uid, role);
|
|
158
|
+
return uid;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
it("admin 重置 superadmin 口令 / 启停 / 改资料 / 删除 → 403,且库里一个字段都没动", async () => {
|
|
162
|
+
seedRole("admin");
|
|
163
|
+
const actor = mkUserWithRole("u_admin1", "admin");
|
|
164
|
+
const target = mkUserWithRole("u_super1", "superadmin");
|
|
165
|
+
await expect(changePasswordByAdmin(actor, target, "newpw123", bcryptDeps)).rejects.toMatchObject({ status: 403 });
|
|
166
|
+
await expect(setForbidden(actor, target, true)).rejects.toMatchObject({ status: 403 });
|
|
167
|
+
await expect(updateUserProfile(actor, target, { displayName: "renamed", email: "x@y.z" })).rejects.toMatchObject({ status: 403 });
|
|
168
|
+
await expect(deleteUser(actor, target)).rejects.toMatchObject({ status: 403 });
|
|
169
|
+
const row = dbo.prepare("SELECT password_hash, is_forbidden, display_name, email FROM users WHERE id = ?").get(target) as { password_hash: string, is_forbidden: number, display_name: string | null, email: string | null };
|
|
170
|
+
expect(row.password_hash).toBe("x");
|
|
171
|
+
expect(Number(row.is_forbidden)).toBe(0);
|
|
172
|
+
expect(row.display_name).toBeNull();
|
|
173
|
+
expect(row.email).toBeNull();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("admin 清空 superadmin 的角色 → 403(成员资格只拦授予方向,反向降级靠这条)", async () => {
|
|
177
|
+
seedRole("admin");
|
|
178
|
+
const actor = mkUserWithRole("u_admin2", "admin");
|
|
179
|
+
const target = mkUserWithRole("u_super2", "superadmin");
|
|
180
|
+
await expect(updateUserRoles(actor, target, [])).rejects.toMatchObject({ status: 403 });
|
|
181
|
+
await expect(updateUserRoles(actor, target, ["viewer"])).rejects.toMatchObject({ status: 403 });
|
|
182
|
+
expect(rolesOf(target)).toEqual(["superadmin"]);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("superadmin 操作 superadmin → 放行(红线不是禁止改超管,而是限定谁能改)", async () => {
|
|
186
|
+
const actor = mkUserWithRole("u_super3", "superadmin");
|
|
187
|
+
const target = mkUserWithRole("u_super4", "superadmin");
|
|
188
|
+
await changePasswordByAdmin(actor, target, "newpw123", bcryptDeps);
|
|
189
|
+
await setForbidden(actor, target, true);
|
|
190
|
+
const row = dbo.prepare("SELECT password_hash, is_forbidden FROM users WHERE id = ?").get(target) as { password_hash: string, is_forbidden: number };
|
|
191
|
+
expect(row.password_hash).toBe("hashed:newpw123");
|
|
192
|
+
expect(Number(row.is_forbidden)).toBe(1);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("admin 操作普通用户照旧放行(门禁只盯 superadmin 目标,不能把整页封死)", async () => {
|
|
196
|
+
seedRole("admin");
|
|
197
|
+
const actor = mkUserWithRole("u_admin3", "admin");
|
|
198
|
+
const target = mkUser("u_plain");
|
|
199
|
+
await changePasswordByAdmin(actor, target, "newpw123", bcryptDeps);
|
|
200
|
+
await setForbidden(actor, target, true);
|
|
201
|
+
expect(Number((dbo.prepare("SELECT is_forbidden FROM users WHERE id = ?").get(target) as { is_forbidden: number }).is_forbidden)).toBe(1);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
153
205
|
describe("B7:列表(用户管理页数据源)", () => {
|
|
154
206
|
it("listUsers 带角色数组,排除口令哈希", async () => {
|
|
155
207
|
seedRole("editor");
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// BDD:/system/roles 展示页隐去 superadmin(事故:角色页把平台级角色当成站点可分配角色列出)。
|
|
2
|
+
//
|
|
3
|
+
// 过滤只发生在**展示层**,所以这里测纯函数而不是整页:页面本身只做 query + 渲染,
|
|
4
|
+
// 真正会回归的是「哪些行算可见」。后端那半边(listRoles 必须原样返回 superadmin)在
|
|
5
|
+
// tests/rbac-roles.spec.ts 里钉,两处合起来才防住「顺手把后端也过滤掉」的改法。
|
|
6
|
+
import { describe, expect, it } from "vitest";
|
|
7
|
+
|
|
8
|
+
import { HIDDEN_ROLE, visibleRoles } from "../src/app/web/system/pages/roles/visible-roles";
|
|
9
|
+
|
|
10
|
+
const ROWS = [
|
|
11
|
+
{ name: "superadmin", module: "_platform" },
|
|
12
|
+
{ name: "admin", module: "_platform" },
|
|
13
|
+
{ name: "custom.wiki", module: "wiki" },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
describe("角色展示页:隐去 superadmin、其余原样", () => {
|
|
17
|
+
it("不列 superadmin,其余顺序不变", () => {
|
|
18
|
+
expect(visibleRoles(ROWS).map(r => r.name)).toEqual(["admin", "custom.wiki"]);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("只按名字精确匹配:superadmin.* / 前缀相近的角色照常显示", () => {
|
|
22
|
+
const rows = [...ROWS, { name: "superadmin.readonly", module: "_platform" }, { name: "Admin", module: "_platform" }];
|
|
23
|
+
expect(visibleRoles(rows).map(r => r.name)).toEqual(["admin", "custom.wiki", "superadmin.readonly", "Admin"]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("不改入参(useQuery 缓存对象不能被就地改写)", () => {
|
|
27
|
+
const input = ROWS.map(r => ({ ...r }));
|
|
28
|
+
const before = input.map(r => r.name);
|
|
29
|
+
visibleRoles(input);
|
|
30
|
+
expect(input.map(r => r.name)).toEqual(before);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("空列表不炸(查询未返回时的形态)", () => {
|
|
34
|
+
expect(visibleRoles([])).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("隐藏项与后端保留角色名同值(改名必须两处一起改)", () => {
|
|
38
|
+
expect(HIDDEN_ROLE).toBe("superadmin");
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -16,7 +16,7 @@ import { beforeAll, describe, expect, it } from "vitest";
|
|
|
16
16
|
const req = createRequire(import.meta.url);
|
|
17
17
|
const { DatabaseSync: Db } = req("node:sqlite") as { DatabaseSync: typeof DatabaseSync };
|
|
18
18
|
|
|
19
|
-
const PLATFORM_API = join(dirname(fileURLToPath(import.meta.url)), "..", "src", "
|
|
19
|
+
const PLATFORM_API = join(dirname(fileURLToPath(import.meta.url)), "..", "src", "app", "api", "_platform");
|
|
20
20
|
|
|
21
21
|
let dbo: InstanceType<typeof DatabaseSync>;
|
|
22
22
|
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// 这里把「同一 uid 换租户必须重查」钉死,顺手钉住写时失效不得漏掉别的租户。
|
|
12
12
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
13
13
|
|
|
14
|
-
import { currentAccess, invalidateAllUsers, invalidateUser, isSelfTenant } from "../src/
|
|
14
|
+
import { currentAccess, invalidateAllUsers, invalidateUser, isSelfTenant } from "../src/app/api/_platform/_shared/service/infra/access";
|
|
15
15
|
import { installDb } from "./fixture";
|
|
16
16
|
|
|
17
17
|
const g = globalThis as any;
|