@oj-module/cli 0.2.18 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/devkit/README.md +4 -4
- package/devkit/SKILL.md +41 -37
- package/devkit/framework-dev.md +6 -5
- package/devkit/manual.md +259 -161
- package/devkit/menu-rules.md +3 -3
- package/devkit/module-dev-and-cdn-playground.md +31 -22
- package/devkit/sql-builder-missing-capabilities-pr.md +11 -6
- package/package.json +2 -2
- package/shell-dist/assets/runtime.js +2 -2
- package/shell-dist/index.html +2 -2
- package/shell-dist/versions.json +3 -3
- package/src/__tests__/build-backend.test.ts +54 -0
- package/src/__tests__/layout.test.ts +176 -0
- package/src/__tests__/module-list.test.ts +66 -0
- package/src/__tests__/oj-caps.test.ts +114 -0
- package/src/alias-paths.ts +102 -0
- package/src/build.ts +41 -9
- package/src/bundle.ts +25 -13
- package/src/config.ts +82 -9
- package/src/contract/__tests__/market-client.integration.test.ts +2 -2
- package/src/contract/check.ts +56 -28
- package/src/contract/emit-stub.ts +21 -9
- package/src/contract/handler-scan.ts +19 -10
- package/src/contract/run.ts +14 -4
- package/src/dev.ts +22 -7
- package/src/index.ts +1 -1
- package/src/info.ts +20 -3
- package/src/init.ts +91 -21
- package/src/layout.ts +282 -24
- package/src/lifecycle/__tests__/bundle.test.ts +16 -1
- package/src/lifecycle/__tests__/manifest-contract.test.ts +2 -2
- package/src/market/__tests__/bootstrap.test.ts +17 -9
- package/src/market/bootstrap.ts +30 -17
- package/src/oj-caps.ts +133 -0
- package/src/oj.ts +27 -4
- package/src/preview-config.ts +1 -1
- package/src/preview.ts +2 -1
- package/src/site.ts +2 -2
- package/src/usage.ts +6 -6
- package/src/vendor.ts +5 -1
- package/templates/{api/config.yaml → config.yaml} +13 -8
- package/templates/global.d.ts +7 -6
- package/templates/init.include.yaml +41 -36
- package/templates/package.json +1 -1
- package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/installer.ts +4 -0
- package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/smoke.ts +21 -2
- package/templates/{api/src/_platform → src/_platform/api}/market/api.ts +25 -15
- package/templates/{api/src/_platform → src/_platform/api}/solutions/api.ts +7 -3
- package/templates/{api/src/auth → src/auth/api}/_shared/login-throttle.ts +2 -2
- package/templates/{api/src/auth → src/auth/api}/_shared/session.ts +2 -2
- package/templates/{api/src/auth → src/auth/api}/api.ts +1 -1
- package/templates/{api/src/auth → src/auth/api}/ldap-login/api.ts +1 -1
- package/templates/src/auth/api/manifest.yaml +6 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/InstallDialog.test.tsx +53 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/marketClient.fake.ts +6 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/api/client.ts +5 -0
- package/templates/{web/src/oj-market → src/oj-market/web}/api/defaultClient.ts +7 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/components/InstallDialog.tsx +80 -5
- package/templates/{web/src/oj-market → src/oj-market/web}/hooks/useMarket.ts +6 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/locales/en-US.json +10 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/locales/zh-CN.json +10 -1
- package/templates/{web/src/oj-market → src/oj-market/web}/types.ts +15 -2
- package/templates/{api/src/system → src/system/api}/login-methods/api.ts +2 -2
- package/templates/src/system/api/manifest.yaml +6 -0
- package/templates/{api/src/system → src/system/api}/oplog/api.ts +4 -4
- package/templates/{api/src/system → src/system/api}/permissions/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/roles/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/roles/bindings/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/settings/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/forbidden/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/password/api.ts +3 -3
- package/templates/{api/src/system → src/system/api}/users/roles/api.ts +3 -3
- package/templates/src/tsconfig.json +16 -0
- package/templates/{api/tests → tests}/auth-ldap.spec.ts +2 -2
- package/templates/{api/tests → tests}/auth-session.spec.ts +3 -3
- package/templates/{api/tests → tests}/auth-throttle.spec.ts +1 -1
- package/templates/tests/fixture.ts +434 -0
- package/templates/{api/tests → tests}/guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/atomic-state.spec.ts +3 -3
- package/templates/{api/tests → tests}/lifecycle/bootstrap.spec.ts +8 -4
- package/templates/{api/tests → tests}/lifecycle/deploy-smoke.spec.ts +31 -8
- package/templates/{api/tests → tests}/lifecycle/installer.spec.ts +15 -15
- package/templates/{api/tests → tests}/lifecycle/market-api.spec.ts +30 -29
- package/templates/{api/tests → tests}/lifecycle/migrate.spec.ts +6 -6
- package/templates/{api/tests → tests}/lifecycle/preflight.spec.ts +4 -4
- package/templates/{api/tests → tests}/lifecycle/register.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/semver.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/sha384.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/sig-fixtures.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/solutions-api.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/steps-fs.spec.ts +12 -12
- package/templates/{api/tests → tests}/lifecycle/text-edit.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/tgz-guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/lifecycle/trust.spec.ts +5 -5
- package/templates/{api/tests → tests}/lifecycle/uninstall.spec.ts +7 -7
- package/templates/{api/tests → tests}/lifecycle/verify-checks.spec.ts +9 -6
- package/templates/{api/tests → tests}/lifecycle/verify-report.spec.ts +7 -5
- package/templates/{api/tests → tests}/query-utils.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-audit.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-contacts.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-guard.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-roles.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-seed.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-settings.spec.ts +2 -2
- package/templates/{api/tests → tests}/rbac-solution-perms.spec.ts +1 -1
- package/templates/{api/tests → tests}/rbac-users.spec.ts +3 -3
- package/templates/tsconfig.json +5 -1
- package/templates/tsconfig.paths.json +19 -0
- package/templates/types/oj-modules.d.ts +17 -0
- package/templates/vitest.config.ts +22 -0
- package/templates/web.config.ts +23 -13
- package/vendor/host-versions.json +3 -3
- package/templates/api/src/auth/manifest.yaml +0 -5
- package/templates/api/src/system/manifest.yaml +0 -5
- package/templates/api/tests/fixture.ts +0 -58
- package/templates/api/tsconfig.json +0 -8
- package/templates/api/vitest.config.ts +0 -12
- package/templates/logs/task-events.jsonl +0 -0
- /package/templates/{api/.ojm-api-exempt.json → .ojm-api-exempt.json} +0 -0
- /package/templates/{api/seed.mysql.sql → seed.mysql.sql} +0 -0
- /package/templates/{api/seed.pg.sql → seed.pg.sql} +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/README.md +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/atomic.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/history.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/lock.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/semver.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/sha384.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/state.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/deploy-web.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/download.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/extract.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/migrate.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/preflight.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/register.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/reload.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/steps/verify.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tasks.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/text-edit.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/tgz-guard.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/trust.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/types.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/uninstall.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-checks.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_lifecycle/verify-report.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/respond.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/contacts.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/roles.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/settings.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/solution-perms.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/domain/users.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/access.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/audit.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/guard.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/oplog.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/query.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/service/infra/rate.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/_shared/site-facade.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/contacts/api.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/contacts/detail/api.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/fixtures/l1-test-user.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/manifest.yaml +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/market/bootstrap.ts +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0001__create_users.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0002__add_users_avatar_base64.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0003__users_source_display_name.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0004__sys_rbac.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0005__users_must_change.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0006__users_is_forbidden.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0007__users_email.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0008__sys_refresh_token.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0009__sys_throttle.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0010__sys_solution_route.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0011__sys_setting_group_label.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0012__market_history.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/migrations/0013__users_profile.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/schema.yaml +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.mysql.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.pg.sql +0 -0
- /package/templates/{api/src/_platform → src/_platform/api}/seed.sql +0 -0
- /package/templates/{web/src/_platform → src/_platform/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/_platform → src/_platform/web}/__client/api.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/entry.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/about → src/about/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/about → src/about/web}/pages/constants.ts +0 -0
- /package/templates/{web/src/about → src/about/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/entry.ts +0 -0
- /package/templates/{web/src/access → src/access/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/access → src/access/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/access-mode/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/admin-visible/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/button-control/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/common-visible/index.tsx +0 -0
- /package/templates/{web/src/access → src/access/web}/pages/page-control/index.tsx +0 -0
- /package/templates/{api/src/auth → src/auth/api}/_shared/ldap-login.ts +0 -0
- /package/templates/{api/src/auth → src/auth/api}/_shared/ldap.ts +0 -0
- /package/templates/{web/src/auth → src/auth/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/auth → src/auth/web}/__client/api.ts +0 -0
- /package/templates/{api/src/demo → src/demo/api}/manifest.yaml +0 -0
- /package/templates/{api/src/demo → src/demo/api}/migrations/0001__create_todos.sql +0 -0
- /package/templates/{api/src/demo → src/demo/api}/schema.yaml +0 -0
- /package/templates/{api/src/demo → src/demo/api}/seed.sql +0 -0
- /package/templates/{api/src/demo → src/demo/api}/todos/api.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/__client/api.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/entry.ts +0 -0
- /package/templates/{web/src/demo → src/demo/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/demo → src/demo/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/demo → src/demo/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/entry.ts +0 -0
- /package/templates/{web/src/exception → src/exception/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/exception → src/exception/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/403/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/404/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/500/index.tsx +0 -0
- /package/templates/{web/src/exception → src/exception/web}/pages/unknown-component/index.tsx +0 -0
- /package/templates/{api/src/home → src/home/api}/line/api.ts +0 -0
- /package/templates/{api/src/home → src/home/api}/manifest.yaml +0 -0
- /package/templates/{api/src/home → src/home/api}/migrations/0001__create_home_tables.sql +0 -0
- /package/templates/{api/src/home → src/home/api}/pie/api.ts +0 -0
- /package/templates/{api/src/home → src/home/api}/schema.yaml +0 -0
- /package/templates/{api/src/home → src/home/api}/seed.sql +0 -0
- /package/templates/{web/src/home → src/home/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/__client/api.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/entry.ts +0 -0
- /package/templates/{web/src/home → src/home/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/home → src/home/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/bar-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/card-list.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/line-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/components/pie-chart.tsx +0 -0
- /package/templates/{web/src/home → src/home/web}/pages/index.tsx +0 -0
- /package/templates/{web/src/login → src/login/web}/entry.ts +0 -0
- /package/templates/{web/src/login → src/login/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/login → src/login/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/login → src/login/web}/pages/change-password.tsx +0 -0
- /package/templates/{web/src/login → src/login/web}/pages/login.tsx +0 -0
- /package/templates/{api/src/notification → src/notification/api}/_shared/notify.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/api.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/del/api.ts +0 -0
- /package/templates/{api/src/notification → src/notification/api}/manifest.yaml +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0001__create_notifications.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0002__notifications_user.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0003__notifications_broadcast.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/migrations/0004__notifications_broadcast_hidden.sql +0 -0
- /package/templates/{api/src/notification → src/notification/api}/schema.yaml +0 -0
- /package/templates/{api/src/notification → src/notification/api}/seed.sql +0 -0
- /package/templates/{web/src/notification → src/notification/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/__client/api.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/entry.ts +0 -0
- /package/templates/{web/src/notification → src/notification/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/notification → src/notification/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/notification → src/notification/web}/pages/center/index.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/CardGrid.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/HistoryDrawer.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/RollbackDialog.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/UninstallConfirm.test.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/poll.test.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/render.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/runtime-stub.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/__tests__/semver.test.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/api/MarketClientProvider.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/api/context.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardGrid.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/CardItem.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/DetailDrawer.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/HistoryDrawer.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/RollbackDialog.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/components/UninstallConfirm.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/entry.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/pages/MarketApp.tsx +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/utils/poll.ts +0 -0
- /package/templates/{web/src/oj-market → src/oj-market/web}/utils/semver.ts +0 -0
- /package/templates/{web/src/outside → src/outside/web}/entry.ts +0 -0
- /package/templates/{web/src/outside → src/outside/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/outside → src/outside/web}/locales/zh-CN.json +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/manifest.yaml +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/profile/api.ts +0 -0
- /package/templates/{api/src/personal-center → src/personal-center/api}/upload/api.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/__client/api.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/entry.ts +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/personal-center → src/personal-center/web}/pages/my-profile/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/entry.ts +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-1/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu1/menu1-2/index.tsx +0 -0
- /package/templates/{web/src/route-nest → src/route-nest/web}/pages/menu2/index.tsx +0 -0
- /package/templates/{web/src → src}/styles.css +0 -0
- /package/templates/{web/src/system → src/system/web}/__client/api.schemas.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/__client/api.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/entry.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/locales/en-US.json +0 -0
- /package/templates/{web/src/system → src/system/web}/locales/zh-CN.json +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/errors.ts +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/forbidden.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/login-methods/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/oplog/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/roles/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/settings/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/users/index.tsx +0 -0
- /package/templates/{web/src/system → src/system/web}/pages/users/roles.tsx +0 -0
- /package/templates/{api/src/web → src/web/api}/get-async-routes/api.ts +0 -0
- /package/templates/{api/src/web → src/web/api}/hello/api.ts +0 -0
- /package/templates/{api/src/web → src/web/api}/manifest.yaml +0 -0
- /package/templates/{api/src/web → src/web/api}/user-info/api.ts +0 -0
- /package/templates/{web/src → src/web}/web/__client/api.schemas.ts +0 -0
- /package/templates/{web/src → src/web}/web/__client/api.ts +0 -0
- /package/templates/{api/tests → tests}/l1-builder.test.ts +0 -0
- /package/templates/{api/tests → tests}/rbac-tables.spec.ts +0 -0
|
@@ -28,8 +28,16 @@ function fakeStarter() {
|
|
|
28
28
|
function newSourceProject(): string {
|
|
29
29
|
const root = mkdtempSync(join(tmpdir(), "ojm-bootstrap-src-"));
|
|
30
30
|
mkdirSync(join(root, "bin", "plugins"), { recursive: true });
|
|
31
|
-
|
|
32
|
-
writeFileSync(
|
|
31
|
+
// 假 oj 必须过 §7 双探:`-V` 报版本、`build --help` 含 --module-root,否则 buildBackend 在闸门处 fail-fast
|
|
32
|
+
writeFileSync(
|
|
33
|
+
join(root, "bin", "oj"),
|
|
34
|
+
"#!/bin/sh\n"
|
|
35
|
+
+ "if [ \"$1\" = \"-V\" ]; then echo oj 0.1.85; exit 0; fi\n"
|
|
36
|
+
+ "if [ \"$1\" = \"build\" ]; then echo \" --module-root <MODULE_ROOT> 源码树根\"; exit 0; fi\n"
|
|
37
|
+
+ "echo fake-oj\n",
|
|
38
|
+
{ mode: 0o755 },
|
|
39
|
+
);
|
|
40
|
+
writeFileSync(join(root, "bin", ".oj-version"), "v0.1.85\n");
|
|
33
41
|
writeFileSync(join(root, "bin", "plugins", "auth.wasm"), "plugin", "utf-8");
|
|
34
42
|
mkdirSync(join(root, "api", "src", "_platform"), { recursive: true });
|
|
35
43
|
writeFileSync(join(root, "api", "src", "_platform", "seed.sql"), "-- seed\n", "utf-8");
|
|
@@ -60,7 +68,7 @@ describe("given 一个装了 oj 二进制的源工程 When 自举隔离站点",
|
|
|
60
68
|
|
|
61
69
|
const site = await bootstrapIsolatedSite({ projectRoot: src, starter });
|
|
62
70
|
|
|
63
|
-
expect(existsSync(join(site.root, "
|
|
71
|
+
expect(existsSync(join(site.root, "src", "_platform", "api", "seed.sql"))).toBe(true);
|
|
64
72
|
expect(existsSync(join(site.root, "bin", "oj"))).toBe(true);
|
|
65
73
|
expect(existsSync(join(site.root, "bin", "plugins", "auth.wasm"))).toBe(true);
|
|
66
74
|
expect(site.root).not.toBe(src);
|
|
@@ -75,8 +83,8 @@ describe("given 一个装了 oj 二进制的源工程 When 自举隔离站点",
|
|
|
75
83
|
|
|
76
84
|
expect(site.port).toBeGreaterThan(1024);
|
|
77
85
|
expect(site.port).not.toBe(9778);
|
|
78
|
-
expect(started[0]?.configPath).toBe(join(site.root, "
|
|
79
|
-
const cfg = readFileSync(join(site.root, "
|
|
86
|
+
expect(started[0]?.configPath).toBe(join(site.root, "config.yaml"));
|
|
87
|
+
const cfg = readFileSync(join(site.root, "config.yaml"), "utf-8");
|
|
80
88
|
expect(cfg).toContain(`port: ${site.port}`);
|
|
81
89
|
await site.cleanup();
|
|
82
90
|
});
|
|
@@ -87,7 +95,7 @@ describe("given 一个装了 oj 二进制的源工程 When 自举隔离站点",
|
|
|
87
95
|
|
|
88
96
|
const site = await bootstrapIsolatedSite({ projectRoot: src, starter });
|
|
89
97
|
|
|
90
|
-
const cfg = readFileSync(join(site.root, "
|
|
98
|
+
const cfg = readFileSync(join(site.root, "config.yaml"), "utf-8");
|
|
91
99
|
expect(cfg).not.toContain("__JWT_SECRET__");
|
|
92
100
|
await site.cleanup();
|
|
93
101
|
});
|
|
@@ -113,7 +121,8 @@ describe("given 一个装了 oj 二进制的源工程 When 自举隔离站点",
|
|
|
113
121
|
|
|
114
122
|
expect(site.publisher.privateKeyPem).toContain("PRIVATE KEY");
|
|
115
123
|
const pemFiles = listFiles(site.root).filter(f => f.endsWith(".pem"));
|
|
116
|
-
|
|
124
|
+
// listFiles 返回相对隔离根的路径;站点自身证书三件套在 config/ 下,其余任何 PEM 都是泄漏
|
|
125
|
+
const outside = pemFiles.filter(f => !f.startsWith("config/"));
|
|
117
126
|
expect(outside).toEqual([]);
|
|
118
127
|
await site.cleanup();
|
|
119
128
|
});
|
|
@@ -144,8 +153,7 @@ describe("given 一个装了 oj 二进制的源工程 When 自举隔离站点",
|
|
|
144
153
|
describe("given 源工程没装 oj 二进制 When 自举", () => {
|
|
145
154
|
it("then 人话报错指向 ojm vendor,且不留半成品临时根", async () => {
|
|
146
155
|
const root = mkdtempSync(join(tmpdir(), "ojm-bootstrap-nooj-"));
|
|
147
|
-
|
|
148
|
-
writeFileSync(join(root, "api", "config.yaml"), "server:\n port: 9778\n", "utf-8");
|
|
156
|
+
writeFileSync(join(root, "config.yaml"), "server:\n port: 9778\n", "utf-8");
|
|
149
157
|
const { starter } = fakeStarter();
|
|
150
158
|
|
|
151
159
|
await expect(bootstrapIsolatedSite({ projectRoot: root, starter }))
|
package/src/market/bootstrap.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import type { OjProcess } from "../oj";
|
|
19
19
|
import { Buffer } from "node:buffer";
|
|
20
20
|
import { createHash, createPrivateKey, randomBytes } from "node:crypto";
|
|
21
|
-
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
22
22
|
import net from "node:net";
|
|
23
23
|
import { tmpdir } from "node:os";
|
|
24
24
|
import path from "node:path";
|
|
@@ -26,6 +26,7 @@ import path from "node:path";
|
|
|
26
26
|
import process from "node:process";
|
|
27
27
|
import { fileURLToPath } from "node:url";
|
|
28
28
|
import { buildBackend } from "../build";
|
|
29
|
+
import { resolveLayout } from "../layout";
|
|
29
30
|
import { exportRawPublicKeyHex, fingerprintOfPublicKey } from "../lifecycle/sign";
|
|
30
31
|
import { startOj } from "../oj";
|
|
31
32
|
import { mintDevCert } from "../oj-cert";
|
|
@@ -49,7 +50,7 @@ export interface IsolatedPublisher {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export interface IsolatedSite {
|
|
52
|
-
/** 临时根(含 api/ bin/ cdn/) */
|
|
53
|
+
/** 临时根(含 config.yaml / src/ / api/dist/ / bin/ / cdn/) */
|
|
53
54
|
root: string
|
|
54
55
|
port: number
|
|
55
56
|
baseUrl: string
|
|
@@ -94,19 +95,26 @@ export async function bootstrapIsolatedSite(opts: BootstrapOptions = {}): Promis
|
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
const root = mkdtempSync(path.join(tmpdir(), "ojm-trial-"));
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
// 新布局(`src/<name>/{api,web}`):config.yaml 在隔离根,源码树根为 <root>/src,
|
|
99
|
+
// 构建产物仍是扁平根 <root>/api/dist(与真实工程同形)。
|
|
100
|
+
const srcDir = path.join(root, "src");
|
|
101
|
+
const configPath = path.join(root, "config.yaml");
|
|
99
102
|
const cdnDir = path.join(root, "cdn");
|
|
100
|
-
const dbPath = path.join(
|
|
103
|
+
const dbPath = path.join(root, "db.sqlite");
|
|
101
104
|
|
|
102
|
-
// 1)
|
|
105
|
+
// 1) 后端源码树 + config(模板由 cli 包内置,init 同源;与 cli→templates 依赖红线不冲突——那是运行期文件而非 import)
|
|
103
106
|
const cliRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
104
|
-
const
|
|
105
|
-
if (!existsSync(path.join(
|
|
106
|
-
throw new Error(`[ojm] cli 内置模板缺失:${
|
|
107
|
+
const templateDir = path.join(cliRoot, "templates");
|
|
108
|
+
if (!existsSync(path.join(templateDir, "config.yaml"))) {
|
|
109
|
+
throw new Error(`[ojm] cli 内置模板缺失:${templateDir}(@oj-module/cli 安装不完整?)`);
|
|
107
110
|
}
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
// 只拷后端侧(`src/<name>/api`):隔离站点不构建前端,web 源码拷过去只是噪音
|
|
112
|
+
for (const entry of readdirSync(path.join(templateDir, "src"), { withFileTypes: true })) {
|
|
113
|
+
const apiSide = path.join(templateDir, "src", entry.name, "api");
|
|
114
|
+
if (entry.isDirectory() && existsSync(apiSide))
|
|
115
|
+
cpSync(apiSide, path.join(srcDir, entry.name, "api"), { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
writeFileSync(configPath, readFileSync(path.join(templateDir, "config.yaml"), "utf-8"), "utf-8");
|
|
110
118
|
|
|
111
119
|
// 2) oj 二进制与插件(startOj 按 <root>/bin/oj 解析;plugins 让 auth 插件可用)
|
|
112
120
|
mkdirSync(path.join(root, "bin"), { recursive: true });
|
|
@@ -134,10 +142,13 @@ export async function bootstrapIsolatedSite(opts: BootstrapOptions = {}): Promis
|
|
|
134
142
|
const siteDir = path.join(root, "site");
|
|
135
143
|
mkdirSync(siteDir, { recursive: true });
|
|
136
144
|
writeFileSync(path.join(siteDir, "index.html"), "<!doctype html><html><body>ojm trial site</body></html>\n", "utf-8");
|
|
137
|
-
cfg = cfg.replace("web:
|
|
145
|
+
cfg = cfg.replace("web: ./cdn", `web: ${cdnDir}\n - prefix: /\n web: ${siteDir}\n spa: true`);
|
|
138
146
|
// 安装目标恒为 release 部署:装好的模块落在 api/dist,dev 形态(--api-path src)发现不了。
|
|
139
147
|
// 故隔离站点以 dist 起站,platform.root 同步改写(oj 校验 root 必须是生效的 api 挂载目录)。
|
|
140
|
-
|
|
148
|
+
// root 相对 **config 所在目录** 解析——config 在隔离根,产物在 <root>/api/dist,故不能写死
|
|
149
|
+
// `dist`(那是 config 还在 api/ 时的旧口径),按布局取值。
|
|
150
|
+
const apiDistRel = path.relative(root, resolveLayout(root).apiDist).split(path.sep).join("/");
|
|
151
|
+
cfg = cfg.replace(" root: src", ` root: ${apiDistRel}`);
|
|
141
152
|
// auth 守卫在装配期读 anonymous_paths,安装器注册的新匿名端点要重启才生效(首次安装 smoke 会 401)。
|
|
142
153
|
// 隔离站点直接预置被测方案的探活路径——与 scripts/verify-solution-smoke/bootstrap-host.mjs 同手法,
|
|
143
154
|
// 让 trial 验的是安装机制本身,而不是重启时序。
|
|
@@ -149,8 +160,8 @@ export async function bootstrapIsolatedSite(opts: BootstrapOptions = {}): Promis
|
|
|
149
160
|
cfg = `${cfg.trimEnd()}\nfs:\n root: .\n readonly: false\n`;
|
|
150
161
|
writeFileSync(configPath, cfg, "utf-8");
|
|
151
162
|
|
|
152
|
-
// 4) 站点开发证书(oj serve 无绕过开关;mintDevCert 落
|
|
153
|
-
await mintDevCert(path.join(
|
|
163
|
+
// 4) 站点开发证书(oj serve 无绕过开关;mintDevCert 落 config.yaml 同级的 config/ 三件套)
|
|
164
|
+
await mintDevCert(path.join(root, "config"));
|
|
154
165
|
|
|
155
166
|
// 5) 一次性发布方身份:seed 派生,私钥只在内存
|
|
156
167
|
const keyId = "trial.publisher";
|
|
@@ -168,7 +179,7 @@ export async function bootstrapIsolatedSite(opts: BootstrapOptions = {}): Promis
|
|
|
168
179
|
const starter = opts.starter ?? ((cfgPath: string, base: string, apiSrc: string) => startOj(cfgPath, base, apiSrc));
|
|
169
180
|
let oj: OjProcess;
|
|
170
181
|
try {
|
|
171
|
-
oj = starter(configPath, "/api", path.join(
|
|
182
|
+
oj = starter(configPath, "/api", path.join(root, "api", "dist"));
|
|
172
183
|
await oj.ready;
|
|
173
184
|
}
|
|
174
185
|
catch (error) {
|
|
@@ -245,7 +256,9 @@ function freePort(): Promise<number> {
|
|
|
245
256
|
function teardownReport(root: string, port: number): string[] {
|
|
246
257
|
const lines = [
|
|
247
258
|
`隔离根:${root}`,
|
|
248
|
-
"
|
|
259
|
+
" config.yaml + config/ 证书 + db.sqlite 站点配置面",
|
|
260
|
+
" src/ 后端模块源码树(src/<name>/api,拷自 cli 内置模板)",
|
|
261
|
+
" api/dist/ 构建产物(安装目标)",
|
|
249
262
|
" bin/ oj 二进制与插件(拷贝自源工程)",
|
|
250
263
|
" cdn/ 隔离 CDN(fixture 包 + 两份索引 + 签名)",
|
|
251
264
|
`监听端口:127.0.0.1:${port}(进程已停)`,
|
package/src/oj-caps.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* oj 二进制**能力**探针(设计 202610220010 §7「双探」)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么不能只看版本号:`bin/oj` 允许手改/手替(vendor.ts:143 的逃生门),
|
|
5
|
+
* `bin/.oj-version` 标记会漂移;且 vendor.ts:102-110 已实证「`oj -V` 正常但
|
|
6
|
+
* JsRuntime 能力缺失」真实存在。版本号是声明,能跑通才是事实。
|
|
7
|
+
*
|
|
8
|
+
* 为什么单独探 `--module-root`:module-root 布局(`src/<name>/{api,web}`)依赖
|
|
9
|
+
* oj 的模块根可配置。能力缺失时必须 fail-fast 并给处置命令——回落旧布局会让
|
|
10
|
+
* 「源码搬了、构建产物还是旧的」这种半坏状态长期存在,比直接失败难排查得多。
|
|
11
|
+
*
|
|
12
|
+
* 缓存:`bin/.oj-caps`,以二进制的 size+mtime 为指纹。指纹变了就重探,
|
|
13
|
+
* 所以手替 `bin/oj` 不会吃到旧缓存。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import fs from "node:fs";
|
|
18
|
+
import path from "node:path";
|
|
19
|
+
import { resolveOjBin } from "./vendor";
|
|
20
|
+
|
|
21
|
+
export interface OjCaps {
|
|
22
|
+
/** `oj build --help` 是否接受 `--module-root <DIR>`(源码树根,与 `-d` 互斥) */
|
|
23
|
+
moduleRoot: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 探针执行器(测试注入):执行 oj 子命令并返回合并输出 */
|
|
27
|
+
export type OjProbeRun = (ojBin: string, args: string[]) => string;
|
|
28
|
+
|
|
29
|
+
const defaultRun: OjProbeRun = (ojBin, args) =>
|
|
30
|
+
execFileSync(ojBin, args, { encoding: "utf-8", timeout: 10_000, stdio: ["ignore", "pipe", "pipe"] });
|
|
31
|
+
|
|
32
|
+
export const CAPS_FILE = ".oj-caps";
|
|
33
|
+
|
|
34
|
+
/** 二进制指纹:size + mtime 足以识别「换了文件」,比哈希便宜且无 IO 放大 */
|
|
35
|
+
function fingerprint(ojBin: string): string {
|
|
36
|
+
const st = fs.statSync(ojBin);
|
|
37
|
+
return `${st.size}:${Math.floor(st.mtimeMs)}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function capsPath(binDir: string): string {
|
|
41
|
+
return path.join(binDir, CAPS_FILE);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 缓存文件形状:指纹 + 能力位 */
|
|
45
|
+
interface CapsCache {
|
|
46
|
+
fingerprint?: string
|
|
47
|
+
caps?: Partial<OjCaps>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 读缓存;指纹不匹配或结构不对 → null(重探) */
|
|
51
|
+
export function readCapsCache(ojBin: string): OjCaps | null {
|
|
52
|
+
try {
|
|
53
|
+
const raw = JSON.parse(fs.readFileSync(capsPath(path.dirname(ojBin)), "utf-8")) as CapsCache | null;
|
|
54
|
+
if (!raw || raw.fingerprint !== fingerprint(ojBin) || typeof raw.caps?.moduleRoot !== "boolean")
|
|
55
|
+
return null;
|
|
56
|
+
return { moduleRoot: raw.caps.moduleRoot };
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** 写缓存(失败不影响主流程:缓存只是加速,不是正确性来源) */
|
|
64
|
+
export function writeCapsCache(ojBin: string, caps: OjCaps): void {
|
|
65
|
+
try {
|
|
66
|
+
fs.writeFileSync(
|
|
67
|
+
capsPath(path.dirname(ojBin)),
|
|
68
|
+
`${JSON.stringify({ fingerprint: fingerprint(ojBin), caps }, null, 2)}\n`,
|
|
69
|
+
"utf-8",
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// 只读目录 / 权限不足:忽略
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** 现场探测:解析 `oj build --help` 的旗标列表(不缓存) */
|
|
78
|
+
export function probeOjCaps(ojBin: string, run: OjProbeRun = defaultRun): OjCaps {
|
|
79
|
+
let help = "";
|
|
80
|
+
try {
|
|
81
|
+
help = run(ojBin, ["build", "--help"]);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`[ojm] 无法执行 ${ojBin} build --help:${(error as Error).message}\n`
|
|
86
|
+
+ "处置:`ojm vendor` 重装 oj 二进制。",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
// 只认长旗标整词:`--module-root <DIR>`;避免帮助文本里的说明文字误命中
|
|
90
|
+
return { moduleRoot: /--module-root\b/.test(help) };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* module-root 布局的能力闸门:缺失即抛,文案给处置命令。
|
|
95
|
+
* 有缓存走缓存(热路径每次 build/dev 都会经过这里)。
|
|
96
|
+
*/
|
|
97
|
+
export function requireModuleRootCapability(
|
|
98
|
+
projectRoot: string,
|
|
99
|
+
run: OjProbeRun = defaultRun,
|
|
100
|
+
): OjCaps {
|
|
101
|
+
const ojBin = resolveOjBin(projectRoot);
|
|
102
|
+
if (!fs.existsSync(ojBin)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`[ojm] 缺少 ${ojBin}:module-root 布局需要 oj 提供 --module-root。\n`
|
|
105
|
+
+ "处置:`ojm vendor` 安装 oj 二进制。",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const caps = readCapsCache(ojBin) ?? (() => {
|
|
110
|
+
const probed = probeOjCaps(ojBin, run);
|
|
111
|
+
writeCapsCache(ojBin, probed);
|
|
112
|
+
return probed;
|
|
113
|
+
})();
|
|
114
|
+
|
|
115
|
+
if (caps.moduleRoot)
|
|
116
|
+
return caps;
|
|
117
|
+
|
|
118
|
+
const version = (() => {
|
|
119
|
+
try {
|
|
120
|
+
return run(ojBin, ["-V"]).trim() || "(未知)";
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return "(不可探测)";
|
|
124
|
+
}
|
|
125
|
+
})();
|
|
126
|
+
throw new Error(
|
|
127
|
+
`[ojm] 当前 oj 不支持 --module-root(版本 ${version}),无法构建 src/<name>/{api,web} 布局。\n`
|
|
128
|
+
+ "原因:module-root 布局要求 oj build / serve 的模块根可配置;本版 oj 只认 `-d` 首层子目录为模块。\n"
|
|
129
|
+
+ "处置:升级 oj 后重试——`ojm vendor <tag>`(需 >= 支持 --module-root 的版本),"
|
|
130
|
+
+ "或把工程改回 web/src/<name> 布局。\n"
|
|
131
|
+
+ `缓存:${capsPath(path.dirname(ojBin))}(换二进制后指纹变化会自动重探)。`,
|
|
132
|
+
);
|
|
133
|
+
}
|
package/src/oj.ts
CHANGED
|
@@ -40,17 +40,40 @@ export interface StartOjPoll {
|
|
|
40
40
|
timeoutMs?: number
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* 工程根:从 config 所在目录向上找最近的含 `bin/` 的目录(ojm 的 vendor 布局)。
|
|
45
|
+
*
|
|
46
|
+
* 两种布局:
|
|
47
|
+
* <root>/api/config.yaml → <root>/bin/oj (历史布局,命中第二层)
|
|
48
|
+
* <root>/config.yaml → <root>/bin/oj (module-root,命中第一层)
|
|
49
|
+
* 找不到 `bin/` 时退回旧的「往上两级」,保持既有报错行为(缺 bin/oj 的文案不变)。
|
|
50
|
+
*/
|
|
51
|
+
function resolveProjectRoot(configPath: string): string {
|
|
52
|
+
const configDir = path.dirname(configPath);
|
|
53
|
+
for (const dir of [configDir, path.dirname(configDir)]) {
|
|
54
|
+
if (fs.existsSync(path.join(dir, "bin")))
|
|
55
|
+
return dir;
|
|
56
|
+
}
|
|
57
|
+
return path.dirname(configDir);
|
|
58
|
+
}
|
|
59
|
+
|
|
43
60
|
export function startOj(
|
|
44
61
|
configPath: string,
|
|
45
62
|
base: string,
|
|
46
|
-
|
|
63
|
+
apiSource: string | string[],
|
|
47
64
|
poll: StartOjPoll = {},
|
|
48
65
|
extraArgs: string[] = [],
|
|
49
66
|
): OjProcess {
|
|
50
67
|
const port = readOjPort(configPath);
|
|
51
|
-
// 约定:
|
|
52
|
-
|
|
68
|
+
// 约定:vendor 二进制在 <project>/bin/oj。工程根不能按「config 往上两级」算:
|
|
69
|
+
// module-root 布局的 config 在仓库根(<project>/config.yaml),往上两级会越过工程,
|
|
70
|
+
// 落到父目录找 bin/oj。改为「向上找最近的含 bin/ 的目录」,两种布局都成立。
|
|
71
|
+
const projectRoot = resolveProjectRoot(configPath);
|
|
53
72
|
const binPath = resolveOjBin(projectRoot);
|
|
73
|
+
// 后端源码参数二选一(oj v0.1.85:`--api-path` 与 `--module-root` 互斥,同时给会被
|
|
74
|
+
// clap 拒掉):历史布局传目录 → `--api-path <dir>`;module-root 布局传**已拼好的
|
|
75
|
+
// 旗标数组** → `["--module-root", "<project>/src"]`。
|
|
76
|
+
const apiArgs = Array.isArray(apiSource) ? apiSource : ["--api-path", apiSource];
|
|
54
77
|
const healthUrl = `http://127.0.0.1:${port}${base}/health`;
|
|
55
78
|
|
|
56
79
|
// 插件目录发现显式化:oj 的 resolve_plugins_dir 依赖 current_exe() 启发式,而
|
|
@@ -69,7 +92,7 @@ export function startOj(
|
|
|
69
92
|
let stderrTail = "";
|
|
70
93
|
// --console-log:oj 新版终端默认静默(console_log 缺省 false,只落 logs/),
|
|
71
94
|
// ojm dev/preview 的 [oj] 透传管道必须显式打开终端输出才能看到日志(手册 §10)。
|
|
72
|
-
const child = spawn(binPath, ["serve", "-c", configPath, "-b", base,
|
|
95
|
+
const child = spawn(binPath, ["serve", "-c", configPath, "-b", base, ...apiArgs, "--console-log", ...extraArgs], {
|
|
73
96
|
stdio: ["ignore", "pipe", "pipe"],
|
|
74
97
|
...(env ? { env } : {}),
|
|
75
98
|
});
|
package/src/preview-config.ts
CHANGED
|
@@ -44,7 +44,7 @@ export interface DerivePreviewConfigOptions {
|
|
|
44
44
|
apiRoot?: string
|
|
45
45
|
/** 显式端口时覆盖 server.port;缺省沿用原 config(oj 代码默认 9778) */
|
|
46
46
|
port?: number
|
|
47
|
-
/** 原 config 文本(测试注入);缺省读
|
|
47
|
+
/** 原 config 文本(测试注入);缺省读 config.yaml */
|
|
48
48
|
configText?: string
|
|
49
49
|
}
|
|
50
50
|
|
package/src/preview.ts
CHANGED
|
@@ -59,7 +59,8 @@ export async function runPreview(projectRoot: string, opts: PreviewOptions = {})
|
|
|
59
59
|
const siteDir = opts.siteDir ?? layout.distDir;
|
|
60
60
|
const ojBin = resolveOjBin(projectRoot);
|
|
61
61
|
const configPath = resolveConfigPath(projectRoot);
|
|
62
|
-
|
|
62
|
+
// release 根恒为扁平 api/dist(module-root 只改源码布局,不改产物形状——设计 C-3/C-7)
|
|
63
|
+
const apiDist = layout.apiDist;
|
|
63
64
|
|
|
64
65
|
// fail-fast 四查:缺一即提示对应补救(init 幂等补缺 / ojm build 产物)
|
|
65
66
|
if (!existsSync(ojBin))
|
package/src/site.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import process from "node:process";
|
|
8
8
|
|
|
9
|
-
/** 任务记录(线形状镜像;真源 templates/
|
|
9
|
+
/** 任务记录(线形状镜像;真源 templates/src/_platform/api/_lifecycle/types.ts:65,客户端不 import 模板内部) */
|
|
10
10
|
export interface TaskRecord {
|
|
11
11
|
/**
|
|
12
12
|
* 记录 schema 版本(P2-10 线形状镜像):缺省(undefined)=旧记录=v1 语义照常渲染;
|
|
@@ -30,7 +30,7 @@ export interface TaskRecord {
|
|
|
30
30
|
finishedAt?: number
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/** 模板 serve 缺省端口(templates/
|
|
33
|
+
/** 模板 serve 缺省端口(templates/config.yaml server.port: 9778;host 显式钉 127.0.0.1) */
|
|
34
34
|
export const DEFAULT_SITE_URL = "http://127.0.0.1:9778";
|
|
35
35
|
|
|
36
36
|
/** 本 CLI 已知的任务记录 schema 版本(P2-10;与服务端 tasks.ts TASK_SCHEMA_VERSION 手工同步,更高版本触发降级提示) */
|
package/src/usage.ts
CHANGED
|
@@ -27,7 +27,7 @@ export function usageText(): string {
|
|
|
27
27
|
ojm api [dir] [--check] [--docs] [--exempt <path>]
|
|
28
28
|
契约代码生成(client / routes / openapi / stub)
|
|
29
29
|
--check 四重对账(生成物同步 / route 双向 / routes.js / WS 路由鉴权)
|
|
30
|
-
--exempt <path> 指定豁免清单,覆盖默认
|
|
30
|
+
--exempt <path> 指定豁免清单,覆盖默认 .ojm-api-exempt.json(工程根;历史布局在 api/ 下)
|
|
31
31
|
--docs 出自包含文档站(单文件离线可看)
|
|
32
32
|
ojm info
|
|
33
33
|
输出版本矩阵与模块清单(报障用,US-7)
|
|
@@ -68,7 +68,7 @@ export function usageText(): string {
|
|
|
68
68
|
--check 离线自检两份索引签名
|
|
69
69
|
ojm market setup [--url <站点地址>] [--user <u> --pass <p>] [--new-pass <p>]
|
|
70
70
|
把系统设置 framework.market_cdn_url 指向本地模拟 CDN(工程根 cdn/,由
|
|
71
|
-
|
|
71
|
+
config.yaml 的 /cdn 挂载直出)。首跑若账号处于首次改密期(seed admin
|
|
72
72
|
must_change=1),会自动改密换全权 token 后再写入。
|
|
73
73
|
ojm market publish [--fixture <name>@<version>] [--real <方案工程>] [--id <key>] [--key <pem>] [--rebuild-index] [--check]
|
|
74
74
|
把方案包落进 cdn/:合成 fixture(或 --real 走 ojm build --bundle)→ 确定性 tgz
|
|
@@ -86,7 +86,7 @@ export function usageText(): string {
|
|
|
86
86
|
在一次性隔离站点(随机端口 + 一次性 DB/密钥/凭据/信任库/CDN)里跑完整安装,
|
|
87
87
|
跑完即毁;--keep 保留现场供排查。用于确认「这个包到底能不能装」,不污染你的工程。
|
|
88
88
|
ojm test|exec|openapi|migrate|schema [args...]
|
|
89
|
-
透传给 oj 同名子命令(自动补 -c <project>/
|
|
89
|
+
透传给 oj 同名子命令(自动补 -c <project>/config.yaml;其余参数原样转发)
|
|
90
90
|
例:ojm test --anonymous / ojm migrate --db report / ojm openapi --check
|
|
91
91
|
`;
|
|
92
92
|
}
|
|
@@ -104,7 +104,7 @@ const COMMAND_HELP: Record<string, string> = {
|
|
|
104
104
|
开发模式快捷键(仅 TTY 终端,类 Vite):
|
|
105
105
|
r 强制重建并热更新 h 显示帮助 c 清屏 o 浏览器打开
|
|
106
106
|
q 退出(后端 oj 一并终止)
|
|
107
|
-
port 缺省 5174(oj 后端端口以
|
|
107
|
+
port 缺省 5174(oj 后端端口以 config.yaml 的 server.port 为准)`,
|
|
108
108
|
"build": `ojm build [--bundle] [--out <dir>]
|
|
109
109
|
构建后端(oj build)与模块产物(含全站合并)
|
|
110
110
|
--bundle 方案包构建:manifest.yaml 契约校验(fail-fast)→ 确定性 tgz
|
|
@@ -117,7 +117,7 @@ const COMMAND_HELP: Record<string, string> = {
|
|
|
117
117
|
"api": `ojm api [dir] [--check] [--docs] [--exempt <path>]
|
|
118
118
|
契约代码生成(client / routes / openapi / stub)
|
|
119
119
|
--check 四重对账(生成物同步 / route 双向 / routes.js / WS 路由鉴权)
|
|
120
|
-
--exempt <path> 指定豁免清单,覆盖默认
|
|
120
|
+
--exempt <path> 指定豁免清单,覆盖默认 .ojm-api-exempt.json(工程根;历史布局在 api/ 下)
|
|
121
121
|
--docs 出自包含文档站(单文件离线可看)
|
|
122
122
|
dir 缺省当前目录;显式目录须先存在`,
|
|
123
123
|
"info": `ojm info
|
|
@@ -168,7 +168,7 @@ const COMMAND_HELP: Record<string, string> = {
|
|
|
168
168
|
本地模拟 CDN 与市场链路子命令:setup / publish / build-index / verify / trial
|
|
169
169
|
详见各子命令帮助:ojm market setup --help 等`,
|
|
170
170
|
"market setup": `ojm market setup [--url <站点地址>] [--user <u> --pass <p>] [--new-pass <p>]
|
|
171
|
-
把系统设置 framework.market_cdn_url 指向本地模拟 CDN(工程根 cdn/,由
|
|
171
|
+
把系统设置 framework.market_cdn_url 指向本地模拟 CDN(工程根 cdn/,由 config.yaml 的 /cdn 挂载直出)。首跑若账号处于首次改密期(seed admin must_change=1),会自动改密换全权 token 后再写入`,
|
|
172
172
|
"market publish": `ojm market publish [--fixture <name>@<version>] [--real <方案工程>] [--id <key>] [--key <pem>] [--rebuild-index] [--check]
|
|
173
173
|
把方案包落进 cdn/:合成 fixture(或 --real 走 ojm build --bundle)→ 确定性 tgz → 包级 detached 签名 <name>-<version>.tgz.sig
|
|
174
174
|
不碰索引(索引由 build-index 扫描重建,多人发布才不会互相覆盖)`,
|
package/src/vendor.ts
CHANGED
|
@@ -35,8 +35,12 @@ export const NPM_PKG = "@oj-bin/oj";
|
|
|
35
35
|
* (见 CHANGELOG 0.1.20 / docs/guides/api-codegen-openapi.md)。**0.2.13 抬到 0.1.81**:
|
|
36
36
|
* 模板侧 `solution-perms.ts` 权限级联清理用 `startswith` 操作键(v0.1.81 补齐,
|
|
37
37
|
* 构造器迁移收尾),oj < 0.1.81 时卸载方案报 `unknown variant startswith` fail-closed。
|
|
38
|
+
* **本版抬到 0.1.85**:`src/<name>/{web,api}` 布局依赖 `--module-root <DIR>`(源码树根,
|
|
39
|
+
* 与 `-d`/`--api-path` 互斥);旧版收到该旗标即报错。0.1.85 同时落地了
|
|
40
|
+
* `manifest.name` 与目录名脱钩、`#/m/x` 按 name 解析(见
|
|
41
|
+
* docs/prd/202610220010-layout-module-root-design.md §5)。
|
|
38
42
|
*/
|
|
39
|
-
export const MIN_OJ_VERSION = "0.1.
|
|
43
|
+
export const MIN_OJ_VERSION = "0.1.85";
|
|
40
44
|
|
|
41
45
|
/** 按段数值比较(字符串比较会把 0.1.9 判成大于 0.1.69);非数字段按 0 处理 */
|
|
42
46
|
export function isSupportedOjVersion(version: string): boolean {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# 本文件由 ojm init 生成;config 内相对路径相对本文件所在目录。
|
|
3
3
|
# 更多能力见手册 §10:vars / broker / tasks / oidc / ws / html_meta / secrets。
|
|
4
4
|
#
|
|
5
|
-
# ---- 证书与密钥的唯一落点:`./config/`(=
|
|
5
|
+
# ---- 证书与密钥的唯一落点:`./config/`(= 工程根/config/,本文件同级的子目录)----
|
|
6
6
|
# 三件套由 `ojm init` 现场签发(dev 缺证时 `ojm dev` 也会补签),逐把的作用与后果:
|
|
7
7
|
#
|
|
8
8
|
# ① private.pem —— 证书签发私钥(RSA 2048)。只用来给 ③ 签名,**oj 不读它**,
|
|
@@ -25,19 +25,24 @@
|
|
|
25
25
|
# 站点挂载(oj v0.1.58 起顶层扁平表:一行=一个 URL 前缀+一个目录,api/web 恰好其一)。
|
|
26
26
|
# 被删除的 server.api_prefix / app_spa_fallback 已由 mounts 取代;
|
|
27
27
|
# ojm dev 的 SPA 深链回落由 ojm 自建静态层负责;ojm preview 为单服务形态,
|
|
28
|
-
# 现场生成派生 config
|
|
28
|
+
# 现场生成派生 config(.ojm-preview.yaml,注入下面的 web 挂载 + spa: true),无需手改。
|
|
29
|
+
#
|
|
30
|
+
# **这里没有 api 挂载是有意的**:本工程是 `src/<name>/{api,web}` 布局,模块分散在
|
|
31
|
+
# `src/<name>/api` 下,而 mounts 的 api 项按 `<目录>/<模块>/manifest.yaml` 单层解析、
|
|
32
|
+
# 不会递归(实测报 `module 'x' missing manifest.yaml`)。源码形态由 `ojm dev` 用
|
|
33
|
+
# `--module-root src` 供给,产物形态由 `ojm preview` 用 `--api-path api/dist` 供给;
|
|
34
|
+
# 两者与 mounts 的 api 项同时出现还会报「module declared in multiple places」。
|
|
35
|
+
# 手写部署(不经 ojm)时才需要自己加回一条 `- prefix: /api` + `api: dist`。
|
|
29
36
|
mounts:
|
|
30
|
-
- prefix: /api # api 挂载:/api/<module>/...(目录相对 config 所在目录 → api/src)
|
|
31
|
-
api: src
|
|
32
37
|
# 本地模拟 CDN:直出工程根 cdn/(内容见 cdn/README.md)。
|
|
33
38
|
# 红线:生产请删掉这一条挂载,并把 system 设置 framework.market_cdn_url 指向真 CDN。
|
|
34
39
|
# 不得给此挂载设 spa——缺文件必须返回 404,回落 index.html 会让市场解析崩。
|
|
35
40
|
- prefix: /cdn
|
|
36
|
-
web:
|
|
41
|
+
web: ./cdn
|
|
37
42
|
# 生产若由 oj 直出前端(前后端同进程,即 ojm preview 的生产形态),
|
|
38
43
|
# 取消下一行注释并先 build 出 web/dist(preview 会自动注入等价挂载,无需手改):
|
|
39
44
|
# - prefix: "/"
|
|
40
|
-
# web: "
|
|
45
|
+
# web: "./web/dist" # 相对 config.yaml → 工程根/web/dist
|
|
41
46
|
# spa: true
|
|
42
47
|
# 嵌套 handler 组(oj v0.1.64)无需配置开关,组织方式见 api.ts 顶部注释。
|
|
43
48
|
|
|
@@ -84,8 +89,8 @@ platform:
|
|
|
84
89
|
# 平台特权模块名单:方案安装器的 reloading 段调 server.reloadConfig 触发热更。
|
|
85
90
|
# 缺这条 → 装在最后一步报 NotCapable: module '_platform' is not platform-privileged。
|
|
86
91
|
modules: [_platform]
|
|
87
|
-
#
|
|
88
|
-
#
|
|
92
|
+
# 受控根 = 后端模块源码根(`src/<name>/api` 的父目录,即 src)。ojm preview 派生 config
|
|
93
|
+
# 时会改写为 dist,保持与 `--api-path` 同源;手写部署请按实际模块根填写。
|
|
89
94
|
root: src
|
|
90
95
|
# ---- U6 信任库加固(P3-1;P2-2 红线 spike 结论)----
|
|
91
96
|
# 威胁:devkit 0.1.75 语义下 fs: 段对全部模块生效(jail = fs.root),且 trusted_paths 只增不减——
|
package/templates/global.d.ts
CHANGED
|
@@ -840,11 +840,12 @@ interface OjRabbitClient {
|
|
|
840
840
|
metadata: () => Promise<any>
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
-
// oj 的导入别名 `#x`(本模块根)/
|
|
844
|
-
// tsconfig 的 `paths`
|
|
845
|
-
//
|
|
846
|
-
//
|
|
847
|
-
//
|
|
848
|
-
//
|
|
843
|
+
// oj 的导入别名 `#x`(本模块根)/ `#/<模块名>/x`(目标模块根)是「引用方所在模块」
|
|
844
|
+
// 相对的,tsconfig 的 `paths` 表达不了模块相对解析,只能按模块枚举
|
|
845
|
+
// (`tsconfig.paths.json`,由 `ojm init` / `ojm build` / `ojm dev` 按 `src/*/api/manifest.yaml`
|
|
846
|
+
// 生成,被 `src/tsconfig.json` extends),因此仅能命中**已存在**的文件。无法静态定位
|
|
847
|
+
// 的别名(如尚未创建的 `#_shared/view`)由 `types/oj-modules.d.ts`(非模块,真 ambient
|
|
848
|
+
// `declare module "#*"`)兜底为 `any` 而非报 TS2307;已存在、能被 `paths` 命中的别名
|
|
849
|
+
// 仍走真实文件类型。运行时由 oj 的 loader 解析,本文件与该兜底只影响编辑器 / tsc。
|
|
849
850
|
|
|
850
851
|
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# 2. 模板自运行专属文件——templates 本身也是一个可 `pnpm dev` 的工程,
|
|
9
9
|
# 它的 package.json / node_modules / bin / lock 绝不能泄漏进用户工程;
|
|
10
10
|
# package.json 由 init 现场生成(钉死真实版本,不带 workspace:/catalog:)。
|
|
11
|
-
# 3. 构建与运行期产物——api/dist、web/dist、
|
|
11
|
+
# 3. 构建与运行期产物——api/dist、web/dist、logs、签发的私钥与 sqlite;
|
|
12
12
|
# 模板跑过 build/dev 后会留在本地,既不进用户工程,更不该让所有工程
|
|
13
13
|
# 共享同一把私钥。
|
|
14
14
|
# 4. 模板自用元数据——本清单自身。
|
|
@@ -32,43 +32,48 @@ include:
|
|
|
32
32
|
- tsconfig.json
|
|
33
33
|
- global.d.ts
|
|
34
34
|
- env.d.ts
|
|
35
|
+
# 别名类型兜底(`declare module "#*"`,非模块文件)。`tsconfig.paths.json` 不在此列:
|
|
36
|
+
# 它由 init 按目标工程的模块清单**现场生成**(模板兼作 demo 工程,多出的模块不该带过去)
|
|
37
|
+
- types
|
|
35
38
|
- web.config.ts
|
|
36
39
|
- openapi.json
|
|
37
|
-
-
|
|
38
|
-
#
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
- api
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
40
|
+
- src/styles.css
|
|
41
|
+
# 后端 typecheck 工程(package.json 的 typecheck:api 指向它);只收后端、排除 web
|
|
42
|
+
- src/tsconfig.json
|
|
43
|
+
# —— 后端:配置 / 种子 / 测试 / 默认模块(模块源码在 src/<name>/api)——
|
|
44
|
+
- config.yaml
|
|
45
|
+
- .ojm-api-exempt.json
|
|
46
|
+
- seed.mysql.sql
|
|
47
|
+
- seed.pg.sql
|
|
48
|
+
- vitest.config.ts
|
|
49
|
+
- tests
|
|
50
|
+
- src/_platform/api
|
|
51
|
+
- src/auth/api
|
|
52
|
+
- src/notification/api
|
|
53
|
+
- src/personal-center/api
|
|
54
|
+
- src/system/api
|
|
55
|
+
- src/web/api
|
|
51
56
|
# —— web 前端模块(demo/home 只列页面源码,__client 见顶部说明)——
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
57
|
+
- src/_platform/web
|
|
58
|
+
- src/auth/web
|
|
59
|
+
- src/demo/web/entry.ts
|
|
60
|
+
- src/demo/web/locales
|
|
61
|
+
- src/demo/web/pages
|
|
62
|
+
- src/home/web/entry.ts
|
|
63
|
+
- src/home/web/locales
|
|
64
|
+
- src/home/web/pages
|
|
65
|
+
- src/login/web
|
|
66
|
+
- src/notification/web
|
|
62
67
|
# 解决方案市场:默认第一方能力。逐子路径收录——__tests__ 不进脚手架
|
|
63
68
|
# (用户工程无 web 侧 vitest 基建,拷了是死文件)
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
69
|
+
- src/oj-market/web/entry.ts
|
|
70
|
+
- src/oj-market/web/types.ts
|
|
71
|
+
- src/oj-market/web/api
|
|
72
|
+
- src/oj-market/web/components
|
|
73
|
+
- src/oj-market/web/hooks
|
|
74
|
+
- src/oj-market/web/locales
|
|
75
|
+
- src/oj-market/web/pages
|
|
76
|
+
- src/oj-market/web/utils
|
|
77
|
+
- src/personal-center/web
|
|
78
|
+
- src/system/web
|
|
79
|
+
- src/web/web
|