@oj-module/cli 0.2.54 → 0.2.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/README.md +7 -4
- package/devkit/SKILL.md +7 -4
- package/devkit/manual.md +63 -54
- package/devkit/module-dev-and-cdn-playground.md +7 -0
- package/devkit/publish-walkthrough.md +199 -0
- package/package.json +2 -2
- package/shell-dist/assets/{index-e_Mp2mb5.js → index-CImwskAz.js} +24 -11
- package/shell-dist/assets/runtime.js +5 -5
- package/shell-dist/index.html +3 -3
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/layout.test.ts +30 -1
- package/src/__tests__/templates-schema-columns.test.ts +99 -0
- package/src/__tests__/vendor-devkit.test.ts +87 -0
- package/src/alias-paths.ts +11 -12
- package/src/build/backend.ts +131 -0
- package/src/build/module-build.ts +364 -0
- package/src/build/module-def.ts +381 -0
- package/src/build/site-merge.ts +33 -0
- package/src/build.ts +16 -885
- package/src/builtin.ts +10 -3
- package/src/bundle.ts +61 -0
- package/src/cli.ts +4 -1
- package/src/contract/__tests__/emit-client.test.ts +4 -4
- package/src/contract/__tests__/market-client.integration.test.ts +2 -2
- package/src/contract/__tests__/run-api.test.ts +2 -2
- package/src/contract/check.ts +6 -2
- package/src/contract/emit-client.ts +10 -3
- package/src/contract/run.ts +10 -2
- package/src/init.ts +31 -46
- package/src/layout.ts +72 -16
- package/src/lifecycle/__tests__/bundle-summary.test.ts +106 -0
- package/src/lifecycle/__tests__/bundle.test.ts +6 -0
- package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
- package/src/market/__tests__/bootstrap.test.ts +1 -1
- package/src/site.ts +1 -1
- package/src/vendor.ts +34 -0
- package/templates/README.md +30 -20
- package/templates/init.include.yaml +19 -11
- package/templates/openapi.json +102 -86
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/installer.ts +8 -3
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/register.ts +53 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/roles.ts +4 -1
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/solution-perms.ts +7 -3
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/users.ts +27 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/oplog.ts +4 -2
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.mysql.sql +7 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.pg.sql +4 -0
- package/templates/src/app/api/_platform/migrations/0017__users_employee_no.sql +8 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.mysql.sql +3 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.pg.sql +3 -0
- package/templates/src/app/api/_platform/migrations/0018__sys_role_title_key.sql +8 -0
- package/templates/src/{_platform/api → app/api/_platform}/schema.yaml +7 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/replay.ts +9 -3
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/tenant-admin.ts +18 -27
- package/templates/src/{system/api → app/api/system}/oplog/api.ts +5 -3
- package/templates/src/{system/api → app/api/system}/roles/api.ts +2 -1
- package/templates/src/{_platform/web/__client/api.ts → app/web/_platform/__client/index.ts} +5 -2
- package/templates/src/{auth/web/__client/api.ts → app/web/auth/__client/index.ts} +5 -2
- package/templates/src/app/web/notification/pages/center/index.tsx +1 -1
- package/templates/src/app/web/notification/routes.ts +1 -1
- package/templates/src/app/web/personal-center/pages/my-profile/index.tsx +1 -1
- package/templates/src/app/web/personal-center/routes.ts +1 -1
- package/templates/src/app/web/system/__client/api.schemas.ts +2 -0
- package/templates/src/app/web/system/locales/en-US.json +2 -3
- package/templates/src/app/web/system/locales/zh-CN.json +2 -3
- package/templates/src/app/web/system/pages/departments/index.tsx +2 -2
- package/templates/src/app/web/system/pages/login-methods/index.tsx +1 -1
- package/templates/src/app/web/system/pages/oplog/index.tsx +44 -19
- package/templates/src/app/web/system/pages/roles/index.tsx +12 -4
- package/templates/src/app/web/system/pages/roles/visible-roles.ts +14 -0
- package/templates/src/app/web/system/pages/settings/index.tsx +2 -2
- package/templates/src/app/web/system/pages/users/can-manage.ts +21 -0
- package/templates/src/app/web/system/pages/users/index.tsx +25 -17
- package/templates/src/app/web/system/pages/users/roles.tsx +1 -1
- package/templates/src/app/web/system/routes.ts +1 -1
- package/templates/src/{web/web/__client/api.ts → app/web/web/__client/index.ts} +5 -2
- package/templates/src/oj-market/web/api/defaultClient.ts +1 -1
- package/templates/tests/auth-ldap.spec.ts +2 -2
- package/templates/tests/auth-session.spec.ts +3 -3
- package/templates/tests/auth-throttle.spec.ts +1 -1
- package/templates/tests/fixture.ts +6 -4
- package/templates/tests/guard.spec.ts +1 -1
- package/templates/tests/lifecycle/atomic-state.spec.ts +3 -3
- package/templates/tests/lifecycle/bootstrap.spec.ts +3 -3
- package/templates/tests/lifecycle/deploy-smoke.spec.ts +8 -8
- package/templates/tests/lifecycle/installer.spec.ts +10 -10
- package/templates/tests/lifecycle/market-api.spec.ts +14 -14
- package/templates/tests/lifecycle/migrate.spec.ts +6 -6
- package/templates/tests/lifecycle/preflight.spec.ts +3 -3
- package/templates/tests/lifecycle/register.spec.ts +1 -1
- package/templates/tests/lifecycle/role-title-translate.spec.ts +171 -0
- package/templates/tests/lifecycle/semver.spec.ts +1 -1
- package/templates/tests/lifecycle/sha384.spec.ts +1 -1
- package/templates/tests/lifecycle/solutions-api.spec.ts +1 -1
- package/templates/tests/lifecycle/source-seq.spec.ts +1 -1
- package/templates/tests/lifecycle/steps-fs.spec.ts +9 -9
- package/templates/tests/lifecycle/text-edit.spec.ts +1 -1
- package/templates/tests/lifecycle/tgz-guard.spec.ts +2 -2
- package/templates/tests/lifecycle/trust.spec.ts +5 -5
- package/templates/tests/lifecycle/uninstall.spec.ts +7 -7
- package/templates/tests/lifecycle/verify-checks.spec.ts +5 -5
- package/templates/tests/lifecycle/verify-report.spec.ts +4 -4
- package/templates/tests/org-departments.spec.ts +10 -6
- package/templates/tests/org-read.spec.ts +7 -7
- package/templates/tests/query-utils.spec.ts +1 -1
- package/templates/tests/rbac-audit.spec.ts +1 -1
- package/templates/tests/rbac-contacts.spec.ts +2 -2
- package/templates/tests/rbac-guard.spec.ts +1 -1
- package/templates/tests/rbac-roles.spec.ts +19 -2
- package/templates/tests/rbac-seed.spec.ts +1 -1
- package/templates/tests/rbac-settings.spec.ts +77 -7
- package/templates/tests/rbac-solution-perms.spec.ts +1 -1
- package/templates/tests/rbac-tables.spec.ts +29 -0
- package/templates/tests/rbac-users.spec.ts +55 -3
- package/templates/tests/roles-page.spec.ts +40 -0
- package/templates/tests/seed-role-accounts.spec.ts +1 -1
- package/templates/tests/tenant-access-cache.spec.ts +1 -1
- package/templates/tests/tenant-forgery.spec.ts +5 -5
- package/templates/tests/tenant-isolation.spec.ts +5 -4
- package/templates/tests/username-namespace.spec.ts +3 -3
- package/templates/tests/users-page.spec.ts +39 -0
- package/templates/tests/wecom-admin.spec.ts +6 -6
- package/templates/tests/wecom-client-timeout.spec.ts +1 -1
- package/templates/tests/wecom-connector.spec.ts +9 -9
- package/templates/tests/wecom-corp.spec.ts +9 -9
- package/templates/tests/wecom-crypt.spec.ts +1 -1
- package/templates/tests/wecom-endpoints.spec.ts +2 -2
- package/templates/tests/wecom-landing.spec.ts +1 -1
- package/templates/tests/wecom-org-sync.spec.ts +7 -7
- package/templates/tests/wecom-sync.spec.ts +3 -3
- package/templates/tsconfig.paths.json +11 -11
- package/templates/vitest.config.ts +2 -2
- package/templates/web.config.ts +5 -2
- package/vendor/host-versions.json +3 -3
- package/templates/src/{_platform/api → app/api/_platform}/README.md +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/atomic.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/history.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/limits.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/lock.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/semver.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/sha384.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/source-seq.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/state.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/deploy-web.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/download.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/extract.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/migrate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/preflight.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/reload.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/smoke.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/steps/verify.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tasks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/text-edit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/tgz-guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/trust.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/types.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/uninstall.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-checks.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_lifecycle/verify-report.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/respond.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/contacts.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org-read.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/org.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/domain/settings.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/access.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/audit.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/guard.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/query.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/service/infra/rate.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/_shared/site-facade.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/contacts/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/contacts/detail/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/fixtures/l1-test-user.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/manifest.yaml +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/bootstrap.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/market/index-source.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0001__create_users.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0002__add_users_avatar_base64.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0003__users_source_display_name.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0004__sys_rbac.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0005__users_must_change.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0006__users_is_forbidden.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0007__users_email.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0008__sys_refresh_token.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0009__sys_throttle.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0010__sys_solution_route.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0011__sys_setting_group_label.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0012__market_history.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0013__users_profile.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0014__reg_source_seq.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0015__tenant.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/migrations/0016__org.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/departments/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/is-member/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/members/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/picker/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/resolve/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/tree/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/org/user/api.ts +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.mysql.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.pg.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/seed.sql +0 -0
- package/templates/src/{_platform/api → app/api/_platform}/solutions/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap-login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/ldap.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/login-throttle.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/session.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/admin.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/client.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/config.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/contacts.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/crypt.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/events.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/login.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/payload.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/store.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/_shared/wecom/sync.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/ldap-login/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/manifest.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0001__wecom.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0002__org_sync.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.mysql.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.pg.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/migrations/0003__credential_kind.sql +0 -0
- package/templates/src/{auth/api → app/api/auth}/schema.yaml +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/api.ts +0 -0
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/api.ts +1 -1
- package/templates/src/{auth/api → app/api/auth}/wecom/admin/tenant-admin/password/api.ts +1 -1
- /package/templates/src/{auth/api → app/api/auth}/wecom/api.ts +0 -0
- /package/templates/src/{auth/api → app/api/auth}/wecom/sync/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/line/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/manifest.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0001__create_home_tables.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.mysql.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/migrations/0002__tenant.sql +0 -0
- /package/templates/src/{home/api → app/api/home}/pie/api.ts +0 -0
- /package/templates/src/{home/api → app/api/home}/schema.yaml +0 -0
- /package/templates/src/{home/api → app/api/home}/seed.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/_shared/notify.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/api.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/del/api.ts +0 -0
- /package/templates/src/{notification/api → app/api/notification}/manifest.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0001__create_notifications.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0002__notifications_user.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0003__notifications_broadcast.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.mysql.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/migrations/0005__tenant.sql +0 -0
- /package/templates/src/{notification/api → app/api/notification}/schema.yaml +0 -0
- /package/templates/src/{notification/api → app/api/notification}/seed.sql +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/manifest.yaml +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/profile/api.ts +0 -0
- /package/templates/src/{personal-center/api → app/api/personal-center}/upload/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/detach/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/members/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/departments/move/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/login-methods/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/manifest.yaml +0 -0
- /package/templates/src/{system/api → app/api/system}/permissions/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/roles/bindings/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/settings/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/forbidden/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/password/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/profile/api.ts +0 -0
- /package/templates/src/{system/api → app/api/system}/users/roles/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/get-async-routes/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/hello/api.ts +0 -0
- /package/templates/src/{web/api → app/api/web}/manifest.yaml +0 -0
- /package/templates/src/{web/api → app/api/web}/user-info/api.ts +0 -0
- /package/templates/src/{_platform/web → app/web/_platform}/__client/api.schemas.ts +0 -0
- /package/templates/src/{auth/web → app/web/auth}/__client/api.schemas.ts +0 -0
- /package/templates/src/app/web/home/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/notification/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/personal-center/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/app/web/system/__client/{api.ts → index.ts} +0 -0
- /package/templates/src/{web → app/web}/web/__client/api.schemas.ts +0 -0
|
@@ -1,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>;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// BDD:solution 角色 title 落库时同步翻译(R1–R6,计划 docs/plans/20261103-0948-role-title-translate)。
|
|
2
|
+
// title = 解析文本(站点默认语言)、title_key = 原文(UI 实时翻译锚);解析失败回退裸 key,
|
|
3
|
+
// 绝不失败安装(R1);升级元数据覆盖 = 重解析(R3);迁移 0018 对存量 solution 角色回填、
|
|
4
|
+
// builtin 不动(R2/AC4);sys_permission 不变(R5);name/code/绑定不变(R6)。
|
|
5
|
+
/* eslint-disable test/prefer-lowercase-title -- AC 编号是验收锚点,保留大写(register.spec 同约定) */
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
9
|
+
import { registerSolution, resolveDeclTitles, siteLanguage } from "../../src/app/api/_platform/_lifecycle/steps/register";
|
|
10
|
+
import { installDb } from "../fixture";
|
|
11
|
+
|
|
12
|
+
const req = createRequire(import.meta.url);
|
|
13
|
+
const { DatabaseSync } = req("node:sqlite");
|
|
14
|
+
const { readFileSync } = req("node:fs");
|
|
15
|
+
const { dirname, join } = req("node:path");
|
|
16
|
+
|
|
17
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const enc = new TextEncoder();
|
|
19
|
+
|
|
20
|
+
let dbo: ReturnType<typeof installDb>;
|
|
21
|
+
const g = globalThis as any;
|
|
22
|
+
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
dbo = installDb();
|
|
25
|
+
g.http = {};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
g.http = {};
|
|
30
|
+
dbo.exec("DELETE FROM sys_role_permission");
|
|
31
|
+
dbo.exec("DELETE FROM sys_user_role");
|
|
32
|
+
dbo.exec("DELETE FROM sys_permission");
|
|
33
|
+
dbo.exec("DELETE FROM sys_role");
|
|
34
|
+
dbo.exec("DELETE FROM sys_solution_route");
|
|
35
|
+
dbo.exec("DELETE FROM sys_setting");
|
|
36
|
+
dbo.exec("DELETE FROM sys_oplog");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function roleRows() {
|
|
40
|
+
return dbo.prepare("SELECT name, title, title_key FROM sys_role ORDER BY name").all() as Array<{ name: string, title: string | null, title_key: string | null }>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** readFile 假面:包内 locales 按路径精确映射,未命中即「文件不存在」 */
|
|
44
|
+
function fakeReadFile(staging: string, files: Record<string, string>) {
|
|
45
|
+
return async (p: string) => {
|
|
46
|
+
const hit = files[p];
|
|
47
|
+
if (hit === undefined)
|
|
48
|
+
throw new Error(`ENOENT: ${p}`);
|
|
49
|
+
return enc.encode(hit);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const STAGING = "/staging";
|
|
54
|
+
const PM_LOCALES = {
|
|
55
|
+
[`${STAGING}/web/modules/pm/locales/zh-CN.json`]: JSON.stringify({ role: { sales: "销售", admin: "方案管理员" } }),
|
|
56
|
+
[`${STAGING}/web/modules/pm/locales/en-US.json`]: JSON.stringify({ role: { sales: "Sales", admin: "Solution Admin" } }),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function pmDecl(title: string) {
|
|
60
|
+
return {
|
|
61
|
+
module: "pm",
|
|
62
|
+
version: "1.0.0",
|
|
63
|
+
roles: [{ name: "pm.sales", title, title_key: title, permissions: ["pm.doc.create"] as string[] }],
|
|
64
|
+
permissions: ["pm.doc.create"],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe("R4 语言取值", () => {
|
|
69
|
+
it("缺省 zh-CN(sys_setting 无 site.language 行)", async () => {
|
|
70
|
+
expect(await siteLanguage()).toBe("zh-CN");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("站点设置 site.language 生效(R4:站点默认语言)", async () => {
|
|
74
|
+
await g.db.table("sys_setting").insert({ key: "site.language", module: "framework", group: "site", type: "string", value: "en-US", update_time: Date.now(), deprecated: 0 }).run();
|
|
75
|
+
expect(await siteLanguage()).toBe("en-US");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("R1 注册时解析(resolveDeclTitles)", () => {
|
|
80
|
+
it("AC1 首装:title_key 解析为站点语言 locale 文本", async () => {
|
|
81
|
+
const resolved = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES));
|
|
82
|
+
expect(resolved.roles[0]!.title).toBe("销售");
|
|
83
|
+
expect(resolved.roles[0]!.title_key).toBe("pm:role.sales");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("R4:语言参数决定读取的 locale 文件", async () => {
|
|
87
|
+
const resolved = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "en-US", fakeReadFile(STAGING, PM_LOCALES));
|
|
88
|
+
expect(resolved.roles[0]!.title).toBe("Sales");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("AC3 缺 key:保留裸 key(title 原样),绝不抛错", async () => {
|
|
92
|
+
const files = { [`${STAGING}/web/modules/pm/locales/zh-CN.json`]: JSON.stringify({ role: { sales: "销售" } }) };
|
|
93
|
+
const resolved = await resolveDeclTitles(pmDecl("pm:role.admin"), STAGING, "zh-CN", fakeReadFile(STAGING, files));
|
|
94
|
+
expect(resolved.roles[0]!.title).toBe("pm:role.admin");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("R1 边界:locale 文件缺失 / 坏 JSON / 非 string 值 / 空 key 形状不符 → 原文保留", async () => {
|
|
98
|
+
const noFile = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, {}));
|
|
99
|
+
expect(noFile.roles[0]!.title).toBe("pm:role.sales");
|
|
100
|
+
|
|
101
|
+
const badJson = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, { [`${STAGING}/web/modules/pm/locales/zh-CN.json`]: "{not-json" }));
|
|
102
|
+
expect(badJson.roles[0]!.title).toBe("pm:role.sales");
|
|
103
|
+
|
|
104
|
+
const nonString = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, { [`${STAGING}/web/modules/pm/locales/zh-CN.json`]: JSON.stringify({ role: { sales: 42 } }) }));
|
|
105
|
+
expect(nonString.roles[0]!.title).toBe("pm:role.sales");
|
|
106
|
+
|
|
107
|
+
// 非 key 形状(中文文本)不做解析尝试——已解析文本二次注册不被误改
|
|
108
|
+
const plain = await resolveDeclTitles(pmDecl("销售"), STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES));
|
|
109
|
+
expect(plain.roles[0]!.title).toBe("销售");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("R1 边界:ns ≠ 模块名不越界解析(跨 ns 无本包 locale)", async () => {
|
|
113
|
+
const decl = { ...pmDecl("wiki:role.sales"), module: "pm" };
|
|
114
|
+
const resolved = await resolveDeclTitles(decl, STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES));
|
|
115
|
+
expect(resolved.roles[0]!.title).toBe("wiki:role.sales");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("R1–R3 落库(registerSolution 消费解析后的 decl)", () => {
|
|
120
|
+
it("AC1 首装:sys_role 落 (title=销售, title_key=pm:role.sales),权限点照常", async () => {
|
|
121
|
+
const resolved = await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES));
|
|
122
|
+
const r = await registerSolution(resolved);
|
|
123
|
+
expect(r.ok).toBe(true);
|
|
124
|
+
const rows = roleRows();
|
|
125
|
+
expect(rows).toEqual([{ name: "pm.sales", title: "销售", title_key: "pm:role.sales" }]);
|
|
126
|
+
const perms = dbo.prepare("SELECT code FROM sys_permission").all() as Array<{ code: string }>;
|
|
127
|
+
expect(perms.map(p => p.code)).toEqual(["pm.doc.create"]);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("AC2 升级:元数据覆盖写新解析文本 + title_key 刷新(R3 locale 改进随升级传播)", async () => {
|
|
131
|
+
await registerSolution(await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES)));
|
|
132
|
+
const improved = fakeReadFile(STAGING, { [`${STAGING}/web/modules/pm/locales/zh-CN.json`]: JSON.stringify({ role: { sales: "销售冠军" } }) });
|
|
133
|
+
const r = await registerSolution(await resolveDeclTitles(pmDecl("pm:role.sales"), STAGING, "zh-CN", improved));
|
|
134
|
+
expect(r.ok).toBe(true);
|
|
135
|
+
expect(roleRows()).toEqual([{ name: "pm.sales", title: "销售冠军", title_key: "pm:role.sales" }]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("AC3 缺 key:注册不失败,title = 裸 key(现行回退形态)", async () => {
|
|
139
|
+
const r = await registerSolution(await resolveDeclTitles(pmDecl("pm:role.viewer"), STAGING, "zh-CN", fakeReadFile(STAGING, PM_LOCALES)));
|
|
140
|
+
expect(r.ok).toBe(true);
|
|
141
|
+
expect(roleRows()).toEqual([{ name: "pm.sales", title: "pm:role.viewer", title_key: "pm:role.viewer" }]);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("R2 迁移 0018(sys_role.title_key 回填)", () => {
|
|
146
|
+
it("AC4 夹具真实迁移后 sys_role 带 title_key 列(列进库 ↔ schema.yaml 一致守卫的库侧半边)", () => {
|
|
147
|
+
const cols = (dbo.prepare("PRAGMA table_info(sys_role)").all() as Array<{ name: string }>).map(c => c.name);
|
|
148
|
+
expect(cols).toContain("title_key");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("AC4 存量 solution 角色按 key 形状回填,builtin 角色不动、title 原文不改", () => {
|
|
152
|
+
const raw = new DatabaseSync(":memory:");
|
|
153
|
+
raw.exec(`
|
|
154
|
+
CREATE TABLE sys_role (
|
|
155
|
+
name TEXT PRIMARY KEY, module TEXT NOT NULL, title TEXT, description TEXT,
|
|
156
|
+
builtin INTEGER NOT NULL DEFAULT 0, deprecated INTEGER NOT NULL DEFAULT 0
|
|
157
|
+
);
|
|
158
|
+
INSERT INTO sys_role (name, module, title, builtin) VALUES
|
|
159
|
+
('pm.sales', 'pm', 'pm:role.sales', 0),
|
|
160
|
+
('wiki.admin', 'wiki', 'wiki:role.admin', 0),
|
|
161
|
+
('admin', 'framework', '系统管理员', 1);
|
|
162
|
+
`);
|
|
163
|
+
raw.exec(readFileSync(join(HERE, "../../src/app/api/_platform/migrations/0018__sys_role_title_key.sql"), "utf8"));
|
|
164
|
+
const rows = raw.prepare("SELECT name, title, title_key FROM sys_role ORDER BY name").all() as Array<{ name: string, title: string, title_key: string | null }>;
|
|
165
|
+
expect(rows).toEqual([
|
|
166
|
+
{ name: "admin", title: "系统管理员", title_key: null },
|
|
167
|
+
{ name: "pm.sales", title: "pm:role.sales", title_key: "pm:role.sales" },
|
|
168
|
+
{ name: "wiki.admin", title: "wiki:role.admin", title_key: "wiki:role.admin" },
|
|
169
|
+
]);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -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";
|
|
@@ -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,21 @@ 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 带出 title_key(R2:solution 角色 UI 实时翻译锚;custom/builtin 为 null)", async () => {
|
|
161
|
+
// solution 角色带 title_key(0018 起);custom 角色管理员手填 title、无 key
|
|
162
|
+
dbo.prepare("INSERT INTO sys_role (name, module, title, title_key, builtin) VALUES ('pm.sales', 'pm', '销售', 'pm:role.sales', 0)").run();
|
|
163
|
+
await createRole({ name: "custom.tk", title: "手填" });
|
|
164
|
+
const roles = await listRoles();
|
|
165
|
+
expect(roles.find(x => x.name === "pm.sales")?.title_key).toBe("pm:role.sales");
|
|
166
|
+
expect(roles.find(x => x.name === "custom.tk")?.title_key).toBe(null);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("listRoles 原样返回 superadmin(只在 /system/roles 展示层隐去)", async () => {
|
|
170
|
+
// 成员资格页(users/roles.tsx)把 superadmin 当可授予项(仅 superadmin 可勾选),
|
|
171
|
+
// 页面数据源里少了它会让「授予超级管理员」直接不可用。过滤只做在展示层。
|
|
172
|
+
dbo.prepare("INSERT INTO sys_role (name, module, builtin) VALUES ('superadmin', 'framework', 1)").run();
|
|
173
|
+
const roles = await listRoles();
|
|
174
|
+
expect(roles.map(r => r.name)).toContain("superadmin");
|
|
175
|
+
});
|
|
159
176
|
});
|
|
@@ -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(() => {
|