@warlock.js/core 5.30.0 → 5.31.0
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/CHANGELOG.md +142 -36
- package/README.md +28 -23
- package/bin/source-load-hook.mjs +63 -0
- package/bin/warlock.js +102 -42
- package/esm/cli/commands/add.command.mjs +4 -2
- package/esm/cli/commands/add.command.mjs.map +1 -1
- package/esm/cli/commands/agents-md/agents-md-command.action.mjs +69 -0
- package/esm/cli/commands/agents-md/agents-md-command.action.mjs.map +1 -0
- package/esm/cli/commands/agents-md.command.mjs +38 -0
- package/esm/cli/commands/agents-md.command.mjs.map +1 -0
- package/esm/cli/commands/board/board-command.action.mjs +279 -0
- package/esm/cli/commands/board/board-command.action.mjs.map +1 -0
- package/esm/cli/commands/board.command.mjs +78 -0
- package/esm/cli/commands/board.command.mjs.map +1 -0
- package/esm/cli/commands/build.command.mjs +6 -1
- package/esm/cli/commands/build.command.mjs.map +1 -1
- package/esm/cli/commands/check/check-command.action.mjs +57 -0
- package/esm/cli/commands/check/check-command.action.mjs.map +1 -0
- package/esm/cli/commands/check/child-typecheck.mjs +66 -0
- package/esm/cli/commands/check/child-typecheck.mjs.map +1 -0
- package/esm/cli/commands/check/format-problems.mjs +43 -0
- package/esm/cli/commands/check/format-problems.mjs.map +1 -0
- package/esm/cli/commands/check/typecheck-command.action.mjs +61 -0
- package/esm/cli/commands/check/typecheck-command.action.mjs.map +1 -0
- package/esm/cli/commands/check.command.mjs +50 -0
- package/esm/cli/commands/check.command.mjs.map +1 -0
- package/esm/cli/commands/dev-server.command.mjs +9 -1
- package/esm/cli/commands/dev-server.command.mjs.map +1 -1
- package/esm/cli/commands/doctor/boot-for-diagnostics.mjs +8 -3
- package/esm/cli/commands/doctor/boot-for-diagnostics.mjs.map +1 -1
- package/esm/cli/commands/doctor/check.types.d.mts +76 -0
- package/esm/cli/commands/doctor/check.types.d.mts.map +1 -0
- package/esm/cli/commands/doctor/checks/config.check.mjs +1 -0
- package/esm/cli/commands/doctor/checks/config.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/connectors.check.mjs +2 -0
- package/esm/cli/commands/doctor/checks/connectors.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs +1 -0
- package/esm/cli/commands/doctor/checks/handler-signature.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/health.check.mjs +3 -0
- package/esm/cli/commands/doctor/checks/health.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs +1 -0
- package/esm/cli/commands/doctor/checks/jwt-secret.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs +1 -0
- package/esm/cli/commands/doctor/checks/locales-ts-deprecated.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +1 -0
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs +4 -0
- package/esm/cli/commands/doctor/checks/release-hygiene.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/routes.check.mjs +3 -0
- package/esm/cli/commands/doctor/checks/routes.check.mjs.map +1 -1
- package/esm/cli/commands/doctor/doctor-command.action.mjs +14 -6
- package/esm/cli/commands/doctor/doctor-command.action.mjs.map +1 -1
- package/esm/cli/commands/doctor/format-report.mjs +30 -2
- package/esm/cli/commands/doctor/format-report.mjs.map +1 -1
- package/esm/cli/commands/doctor.command.mjs +4 -0
- package/esm/cli/commands/doctor.command.mjs.map +1 -1
- package/esm/cli/commands/explain/explain-command.action.mjs +64 -0
- package/esm/cli/commands/explain/explain-command.action.mjs.map +1 -0
- package/esm/cli/commands/explain.command.mjs +23 -0
- package/esm/cli/commands/explain.command.mjs.map +1 -0
- package/esm/cli/commands/generate/generate.command.mjs +124 -124
- package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/endpoint.generator.mjs +311 -0
- package/esm/cli/commands/generate/generators/endpoint.generator.mjs.map +1 -0
- package/esm/cli/commands/generate/generators/migration.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/model.generator.mjs +1 -1
- package/esm/cli/commands/generate/templates/endpoint-stubs.mjs +341 -0
- package/esm/cli/commands/generate/templates/endpoint-stubs.mjs.map +1 -0
- package/esm/cli/commands/generate/templates/stubs.mjs +19 -6
- package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/endpoint-schema.mjs +137 -0
- package/esm/cli/commands/generate/utils/endpoint-schema.mjs.map +1 -0
- package/esm/cli/commands/generate/utils/name-parser.mjs +1 -1
- package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/writer.mjs +38 -13
- package/esm/cli/commands/generate/utils/writer.mjs.map +1 -1
- package/esm/cli/commands/inspect/inspect-command.action.mjs +72 -0
- package/esm/cli/commands/inspect/inspect-command.action.mjs.map +1 -0
- package/esm/cli/commands/inspect.command.mjs +39 -0
- package/esm/cli/commands/inspect.command.mjs.map +1 -0
- package/esm/cli/commands/mcp/mcp-command.action.mjs +103 -0
- package/esm/cli/commands/mcp/mcp-command.action.mjs.map +1 -0
- package/esm/cli/commands/mcp.command.mjs +76 -0
- package/esm/cli/commands/mcp.command.mjs.map +1 -0
- package/esm/cli/commands/openapi-generator.action.mjs.map +1 -1
- package/esm/cli/commands/openapi-generator.command.mjs.map +1 -1
- package/esm/cli/commands/postman-generator.action.mjs.map +1 -1
- package/esm/cli/commands/postman-generator.command.mjs.map +1 -1
- package/esm/cli/commands/routes/routes-diff.action.mjs +1 -1
- package/esm/cli/commands/test.command.mjs +131 -0
- package/esm/cli/commands/test.command.mjs.map +1 -0
- package/esm/cli/commands/trace/trace-command.action.mjs +145 -0
- package/esm/cli/commands/trace/trace-command.action.mjs.map +1 -0
- package/esm/cli/commands/trace.command.mjs +60 -0
- package/esm/cli/commands/trace.command.mjs.map +1 -0
- package/esm/cli/commands/typecheck.command.mjs +40 -0
- package/esm/cli/commands/typecheck.command.mjs.map +1 -0
- package/esm/cli/commands/upgrade.command.mjs +46 -0
- package/esm/cli/commands/upgrade.command.mjs.map +1 -0
- package/esm/cli/flush-and-exit.mjs +34 -0
- package/esm/cli/flush-and-exit.mjs.map +1 -0
- package/esm/cli/framework-cli-commands.mjs +23 -1
- package/esm/cli/framework-cli-commands.mjs.map +1 -1
- package/esm/cli/parse-cli-args.mjs +1 -0
- package/esm/cli/parse-cli-args.mjs.map +1 -1
- package/esm/config/config-loader.d.mts.map +1 -1
- package/esm/config/config-loader.mjs +34 -13
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/config/config-schema.d.mts +67 -0
- package/esm/config/config-schema.d.mts.map +1 -0
- package/esm/config/config-schema.mjs +77 -0
- package/esm/config/config-schema.mjs.map +1 -0
- package/esm/config/index.d.mts +6 -0
- package/esm/config/index.mjs +1 -0
- package/esm/connectors/assert-no-reserved-connector-names.d.mts.map +1 -1
- package/esm/connectors/assert-no-reserved-connector-names.mjs +2 -1
- package/esm/connectors/assert-no-reserved-connector-names.mjs.map +1 -1
- package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -1
- package/esm/connectors/assert-unique-connector-names.mjs +26 -2
- package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +3 -2
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/single-server-warnings.mjs.map +1 -1
- package/esm/connectors/socket-connector.d.mts.map +1 -1
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/container/index.d.mts.map +1 -1
- package/esm/container/index.mjs.map +1 -1
- package/esm/database/migrate-action.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.d.mts +0 -28
- package/esm/database/models/database-log/database-log.d.mts.map +1 -1
- package/esm/database/seeds/seeder.errors.d.mts +4 -0
- package/esm/database/seeds/seeder.errors.d.mts.map +1 -1
- package/esm/database/seeds/seeder.errors.mjs +2 -0
- package/esm/database/seeds/seeder.errors.mjs.map +1 -1
- package/esm/dev-server/boot-precondition-error.mjs +1 -0
- package/esm/dev-server/boot-precondition-error.mjs.map +1 -1
- package/esm/dev-server/create-worker.mjs +15 -9
- package/esm/dev-server/create-worker.mjs.map +1 -1
- package/esm/dev-server/dev-agent-tooling.mjs +135 -0
- package/esm/dev-server/dev-agent-tooling.mjs.map +1 -0
- package/esm/dev-server/dev-logger.mjs.map +1 -1
- package/esm/dev-server/development-server.mjs +8 -0
- package/esm/dev-server/development-server.mjs.map +1 -1
- package/esm/dev-server/files-orchestrator.mjs +4 -5
- package/esm/dev-server/files-orchestrator.mjs.map +1 -1
- package/esm/dev-server/files-watcher.mjs +1 -1
- package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs +2 -3
- package/esm/dev-server/health-checker/checkers/eslint-health-checker.mjs.map +1 -1
- package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs +33 -0
- package/esm/dev-server/health-checker/checkers/oxlint-health-checker.mjs.map +1 -0
- package/esm/dev-server/health-checker/default-health-checkers.mjs +31 -0
- package/esm/dev-server/health-checker/default-health-checkers.mjs.map +1 -0
- package/esm/dev-server/health-checker/file-health-checker.contract.d.mts +9 -3
- package/esm/dev-server/health-checker/file-health-checker.contract.d.mts.map +1 -1
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs +15 -4
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
- package/esm/dev-server/health-checker/oxlint-runner.mjs +302 -0
- package/esm/dev-server/health-checker/oxlint-runner.mjs.map +1 -0
- package/esm/dev-server/health-checker/workers/oxlint-health.worker.d.mts +1 -0
- package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs +42 -0
- package/esm/dev-server/health-checker/workers/oxlint-health.worker.mjs.map +1 -0
- package/esm/dev-server/loader/loader-port-acks.mjs +1 -1
- package/esm/dev-server/loader/loader-port-acks.mjs.map +1 -1
- package/esm/dev-server/loader/register-loader.mjs +1 -1
- package/esm/dev-server/loader/register-loader.mjs.map +1 -1
- package/esm/dev-server/loader/resolve-hook.mjs +1 -1
- package/esm/dev-server/loader/transpile-cache.mjs +1 -1
- package/esm/dev-server/model-resource-typings.mjs.map +1 -1
- package/esm/dev-server/module-loader.mjs +1 -0
- package/esm/dev-server/module-loader.mjs.map +1 -1
- package/esm/dev-server/parse-imports.mjs +1 -1
- package/esm/dev-server/parse-imports.mjs.map +1 -1
- package/esm/dev-server/route-types-publisher.mjs +1 -1
- package/esm/dev-server/start-development-server.mjs.map +1 -1
- package/esm/dev-server/translation-keys-sources.mjs +1 -1
- package/esm/dev-server/translation-keys-sources.mjs.map +1 -1
- package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
- package/esm/dev-server/type-generator.mjs +3 -3
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/dev-server/types.d.mts.map +1 -1
- package/esm/errors/container-key-missing-error.mjs +1 -0
- package/esm/errors/container-key-missing-error.mjs.map +1 -1
- package/esm/errors/error-codes.d.mts +653 -0
- package/esm/errors/error-codes.d.mts.map +1 -0
- package/esm/errors/error-codes.mjs +634 -0
- package/esm/errors/error-codes.mjs.map +1 -0
- package/esm/errors/esbuild-binary-missing-error.mjs +1 -0
- package/esm/errors/esbuild-binary-missing-error.mjs.map +1 -1
- package/esm/errors/index.d.mts +3 -1
- package/esm/errors/index.mjs +3 -1
- package/esm/errors/unknown-locale-error.mjs +1 -0
- package/esm/errors/unknown-locale-error.mjs.map +1 -1
- package/esm/errors/warlock-error.d.mts +23 -0
- package/esm/errors/warlock-error.d.mts.map +1 -0
- package/esm/errors/warlock-error.mjs +22 -0
- package/esm/errors/warlock-error.mjs.map +1 -0
- package/esm/generations/add-command.action.mjs +19 -3
- package/esm/generations/add-command.action.mjs.map +1 -1
- package/esm/generations/features/access.feature.mjs +1 -1
- package/esm/generations/features/access.feature.mjs.map +1 -1
- package/esm/generations/features/bull-board.feature.mjs +1 -1
- package/esm/generations/features/bull-board.feature.mjs.map +1 -1
- package/esm/generations/features/mysql.feature.mjs.map +1 -1
- package/esm/generations/features/notifications.feature.mjs +5 -2
- package/esm/generations/features/notifications.feature.mjs.map +1 -1
- package/esm/generations/features/queue.feature.mjs +1 -1
- package/esm/generations/features/queue.feature.mjs.map +1 -1
- package/esm/generations/features/react-email.feature.mjs +1 -1
- package/esm/generations/features/react-email.feature.mjs.map +1 -1
- package/esm/generations/features/shadcn.feature.mjs +1 -1
- package/esm/generations/features/shadcn.feature.mjs.map +1 -1
- package/esm/generations/features/shared/link-ai-package-import.mjs +1 -1
- package/esm/generations/features/shared/link-ai-package-import.mjs.map +1 -1
- package/esm/generations/features/shared/merge-web-sitemap-config.mjs.map +1 -1
- package/esm/generations/features/shared/patch-tsconfig-include.mjs +1 -1
- package/esm/generations/features/shared/patch-tsconfig-include.mjs.map +1 -1
- package/esm/generations/features/shared/relocate-conflicting-home-route.mjs +1 -1
- package/esm/generations/features/shared/relocate-conflicting-home-route.mjs.map +1 -1
- package/esm/generations/features/sitemap.feature.mjs +1 -1
- package/esm/generations/features/sitemap.feature.mjs.map +1 -1
- package/esm/generations/features/tailwind.feature.mjs +1 -1
- package/esm/generations/features/tailwind.feature.mjs.map +1 -1
- package/esm/generations/features/test.feature.mjs +11 -6
- package/esm/generations/features/test.feature.mjs.map +1 -1
- package/esm/generations/features/web.feature.mjs +1 -1
- package/esm/generations/features/web.feature.mjs.map +1 -1
- package/esm/generations/generation-fs.mjs +73 -0
- package/esm/generations/generation-fs.mjs.map +1 -0
- package/esm/generations/generation-run.mjs +185 -0
- package/esm/generations/generation-run.mjs.map +1 -0
- package/esm/generations/stubs.mjs +155 -13
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/bounded-stream-queue.d.mts +10 -0
- package/esm/http/bounded-stream-queue.d.mts.map +1 -0
- package/esm/http/bounded-stream-queue.mjs +97 -0
- package/esm/http/bounded-stream-queue.mjs.map +1 -0
- package/esm/http/build-rate-limit-options.d.mts +13 -0
- package/esm/http/build-rate-limit-options.d.mts.map +1 -1
- package/esm/http/build-rate-limit-options.mjs.map +1 -1
- package/esm/http/conditional-request.d.mts +86 -0
- package/esm/http/conditional-request.d.mts.map +1 -0
- package/esm/http/conditional-request.mjs +121 -0
- package/esm/http/conditional-request.mjs.map +1 -0
- package/esm/http/csp.d.mts +2 -0
- package/esm/http/csp.d.mts.map +1 -1
- package/esm/http/csp.mjs +1 -0
- package/esm/http/csp.mjs.map +1 -1
- package/esm/http/csrf-origin-policy.mjs.map +1 -1
- package/esm/http/database/RequestLog.d.mts +24 -84
- package/esm/http/database/RequestLog.d.mts.map +1 -1
- package/esm/http/errors/errors.d.mts +2 -0
- package/esm/http/errors/errors.d.mts.map +1 -1
- package/esm/http/errors/errors.mjs +1 -0
- package/esm/http/errors/errors.mjs.map +1 -1
- package/esm/http/escape-header-value.d.mts +18 -0
- package/esm/http/escape-header-value.d.mts.map +1 -0
- package/esm/http/escape-header-value.mjs +27 -0
- package/esm/http/escape-header-value.mjs.map +1 -0
- package/esm/http/flush-pending-cookies.mjs.map +1 -1
- package/esm/http/index.d.mts +5 -2
- package/esm/http/index.mjs +4 -1
- package/esm/http/lazy-static.mjs +194 -0
- package/esm/http/lazy-static.mjs.map +1 -0
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/plugins.d.mts.map +1 -1
- package/esm/http/plugins.mjs +7 -4
- package/esm/http/plugins.mjs.map +1 -1
- package/esm/http/rate-limit-cache-store.mjs +2 -1
- package/esm/http/rate-limit-cache-store.mjs.map +1 -1
- package/esm/http/request-log-snapshot.d.mts +12 -5
- package/esm/http/request-log-snapshot.d.mts.map +1 -1
- package/esm/http/request-log-snapshot.mjs +83 -4
- package/esm/http/request-log-snapshot.mjs.map +1 -1
- package/esm/http/request.d.mts +2 -2
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +5 -4
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.d.mts +11 -1
- package/esm/http/response.d.mts.map +1 -1
- package/esm/http/response.mjs +164 -76
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/safe-redirect.d.mts +51 -0
- package/esm/http/safe-redirect.d.mts.map +1 -0
- package/esm/http/safe-redirect.mjs +80 -0
- package/esm/http/safe-redirect.mjs.map +1 -0
- package/esm/http/serialized.d.mts.map +1 -1
- package/esm/http/server.d.mts +3 -1
- package/esm/http/server.d.mts.map +1 -1
- package/esm/http/server.mjs +14 -4
- package/esm/http/server.mjs.map +1 -1
- package/esm/http/stream-transport.mjs +4 -2
- package/esm/http/stream-transport.mjs.map +1 -1
- package/esm/http/types.d.mts +44 -11
- package/esm/http/types.d.mts.map +1 -1
- package/esm/http/uploads/generate-image-variant.mjs +1 -1
- package/esm/http/uploads/generate-image-variants.d.mts +10 -7
- package/esm/http/uploads/generate-image-variants.d.mts.map +1 -1
- package/esm/http/uploads/generate-image-variants.mjs +61 -24
- package/esm/http/uploads/generate-image-variants.mjs.map +1 -1
- package/esm/http/uploads/image-variant-cache-entries.mjs +78 -0
- package/esm/http/uploads/image-variant-cache-entries.mjs.map +1 -0
- package/esm/http/uploads/image-variant-cache.mjs +72 -30
- package/esm/http/uploads/image-variant-cache.mjs.map +1 -1
- package/esm/http/uploads/image-variant-types.d.mts +2 -0
- package/esm/http/uploads/image-variant-types.d.mts.map +1 -1
- package/esm/http/uploads/image-variants-config-error.d.mts +3 -1
- package/esm/http/uploads/image-variants-config-error.d.mts.map +1 -1
- package/esm/http/uploads/image-variants-config-error.mjs +3 -2
- package/esm/http/uploads/image-variants-config-error.mjs.map +1 -1
- package/esm/http/uploads/load-variant-source.mjs +1 -1
- package/esm/http/uploads/load-variant-source.mjs.map +1 -1
- package/esm/http/uploads/purge-image-variants.d.mts +7 -2
- package/esm/http/uploads/purge-image-variants.d.mts.map +1 -1
- package/esm/http/uploads/purge-image-variants.mjs +16 -16
- package/esm/http/uploads/purge-image-variants.mjs.map +1 -1
- package/esm/http/uploads/remote-variant-source.mjs +115 -0
- package/esm/http/uploads/remote-variant-source.mjs.map +1 -0
- package/esm/http/uploads/resolve-image-variant.d.mts +3 -4
- package/esm/http/uploads/resolve-image-variant.d.mts.map +1 -1
- package/esm/http/uploads/resolve-image-variant.mjs +10 -18
- package/esm/http/uploads/resolve-image-variant.mjs.map +1 -1
- package/esm/http/uploads/resolve-image-variants-config.mjs +5 -3
- package/esm/http/uploads/resolve-image-variants-config.mjs.map +1 -1
- package/esm/http/uploads/resolve-remote-image-variant.mjs +89 -0
- package/esm/http/uploads/resolve-remote-image-variant.mjs.map +1 -0
- package/esm/http/uploads/trim-image-variant-cache.mjs +193 -0
- package/esm/http/uploads/trim-image-variant-cache.mjs.map +1 -0
- package/esm/http/uploads/uploaded-file.controller.d.mts +5 -3
- package/esm/http/uploads/uploaded-file.controller.d.mts.map +1 -1
- package/esm/http/uploads/uploaded-file.controller.mjs +16 -8
- package/esm/http/uploads/uploaded-file.controller.mjs.map +1 -1
- package/esm/http/uploads/variant-cache-key.mjs +1 -1
- package/esm/http/uploads-types.d.mts +6 -2
- package/esm/http/uploads-types.d.mts.map +1 -1
- package/esm/index.d.mts +17 -6
- package/esm/index.mjs +14 -3
- package/esm/localization/parse-locale-dictionary.d.mts +2 -0
- package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
- package/esm/localization/parse-locale-dictionary.mjs +1 -0
- package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
- package/esm/mail/config.d.mts +12 -1
- package/esm/mail/config.d.mts.map +1 -1
- package/esm/mail/config.mjs +16 -1
- package/esm/mail/config.mjs.map +1 -1
- package/esm/mail/index.d.mts +1 -1
- package/esm/mail/index.mjs +1 -1
- package/esm/net/index.d.mts +2 -0
- package/esm/net/index.mjs +3 -0
- package/esm/openapi/build-openapi-document.d.mts.map +1 -1
- package/esm/openapi/build-openapi-document.mjs +8 -5
- package/esm/openapi/build-openapi-document.mjs.map +1 -1
- package/esm/openapi/error-responses.mjs +28 -2
- package/esm/openapi/error-responses.mjs.map +1 -1
- package/esm/openapi/postman/build-request-body.mjs.map +1 -1
- package/esm/openapi/postman/build-request-url.mjs.map +1 -1
- package/esm/openapi/postman/build-saved-responses.mjs.map +1 -1
- package/esm/openapi/postman/example-from-schema.d.mts.map +1 -1
- package/esm/openapi/postman/example-from-schema.mjs.map +1 -1
- package/esm/openapi/postman/openapi-to-postman-collection.d.mts.map +1 -1
- package/esm/openapi/postman/openapi-to-postman-collection.mjs.map +1 -1
- package/esm/openapi/postman/schema-refs.mjs.map +1 -1
- package/esm/openapi/postman/uuid-v5.mjs.map +1 -1
- package/esm/openapi/request-schemas.mjs.map +1 -1
- package/esm/openapi/response-schemas.mjs.map +1 -1
- package/esm/openapi/schema-registry.d.mts +1 -0
- package/esm/openapi/schema-registry.mjs.map +1 -1
- package/esm/openapi/security.mjs.map +1 -1
- package/esm/openapi/types.d.mts +3 -2
- package/esm/openapi/types.d.mts.map +1 -1
- package/esm/production/assert-generated-imports.mjs +1 -0
- package/esm/production/assert-generated-imports.mjs.map +1 -1
- package/esm/production/production-builder.mjs +12 -4
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/resolve-build-config.mjs +1 -0
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/production/route-registration-child.mjs.map +1 -1
- package/esm/production/route-registration-snapshot.mjs.map +1 -1
- package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
- package/esm/repositories/contracts/types.d.mts.map +1 -1
- package/esm/repositories/repository.manager.mjs.map +1 -1
- package/esm/resource/resource.d.mts.map +1 -1
- package/esm/resource/resource.mjs.map +1 -1
- package/esm/resource/types.d.mts.map +1 -1
- package/esm/restful/restful.d.mts +5 -5
- package/esm/restful/restful.d.mts.map +1 -1
- package/esm/restful/restful.mjs.map +1 -1
- package/esm/router/build-route-rate-limit.mjs.map +1 -1
- package/esm/router/dev-dispatch.mjs +31 -12
- package/esm/router/dev-dispatch.mjs.map +1 -1
- package/esm/router/index.d.mts +4 -2
- package/esm/router/index.mjs +2 -0
- package/esm/router/log-request-lifecycle.mjs.map +1 -1
- package/esm/router/positional-handler-diagnostics.d.mts.map +1 -1
- package/esm/router/positional-handler-diagnostics.mjs.map +1 -1
- package/esm/router/resolve-route-rate-limit.mjs +47 -0
- package/esm/router/resolve-route-rate-limit.mjs.map +1 -0
- package/esm/router/resolve-route-validation.mjs +19 -0
- package/esm/router/resolve-route-validation.mjs.map +1 -0
- package/esm/router/route-guard-names.mjs +30 -0
- package/esm/router/route-guard-names.mjs.map +1 -0
- package/esm/router/route-name-taken-error.d.mts +14 -0
- package/esm/router/route-name-taken-error.d.mts.map +1 -0
- package/esm/router/route-name-taken-error.mjs +18 -0
- package/esm/router/route-name-taken-error.mjs.map +1 -0
- package/esm/router/router.d.mts +32 -13
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +71 -38
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +137 -17
- package/esm/router/types.d.mts.map +1 -1
- package/esm/router/unguarded-route-diagnostics.d.mts +40 -0
- package/esm/router/unguarded-route-diagnostics.d.mts.map +1 -0
- package/esm/router/unguarded-route-diagnostics.mjs +95 -0
- package/esm/router/unguarded-route-diagnostics.mjs.map +1 -0
- package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
- package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
- package/esm/storage/drivers/local-driver.d.mts.map +1 -1
- package/esm/storage/drivers/local-driver.mjs.map +1 -1
- package/esm/storage/local-disk-roots.mjs +24 -0
- package/esm/storage/local-disk-roots.mjs.map +1 -0
- package/esm/storage/storage.d.mts +14 -0
- package/esm/storage/storage.d.mts.map +1 -1
- package/esm/storage/storage.mjs +22 -0
- package/esm/storage/storage.mjs.map +1 -1
- package/esm/storage/types.d.mts.map +1 -1
- package/esm/storage/utils/storage-not-initialized-error.d.mts +2 -0
- package/esm/storage/utils/storage-not-initialized-error.d.mts.map +1 -1
- package/esm/storage/utils/storage-not-initialized-error.mjs +1 -0
- package/esm/storage/utils/storage-not-initialized-error.mjs.map +1 -1
- package/esm/tests/authenticated-test-client.d.mts +32 -0
- package/esm/tests/authenticated-test-client.d.mts.map +1 -0
- package/esm/tests/authenticated-test-client.mjs +40 -0
- package/esm/tests/authenticated-test-client.mjs.map +1 -0
- package/esm/tests/factories.d.mts +59 -0
- package/esm/tests/factories.d.mts.map +1 -0
- package/esm/tests/factories.mjs +105 -0
- package/esm/tests/factories.mjs.map +1 -0
- package/esm/tests/fakes/cache-fake.d.mts +29 -0
- package/esm/tests/fakes/cache-fake.d.mts.map +1 -0
- package/esm/tests/fakes/cache-fake.mjs +79 -0
- package/esm/tests/fakes/cache-fake.mjs.map +1 -0
- package/esm/tests/fakes/clock-fake.d.mts +32 -0
- package/esm/tests/fakes/clock-fake.d.mts.map +1 -0
- package/esm/tests/fakes/clock-fake.mjs +69 -0
- package/esm/tests/fakes/clock-fake.mjs.map +1 -0
- package/esm/tests/fakes/fake-assertion-error.d.mts +13 -0
- package/esm/tests/fakes/fake-assertion-error.d.mts.map +1 -0
- package/esm/tests/fakes/fake-assertion-error.mjs +20 -0
- package/esm/tests/fakes/fake-assertion-error.mjs.map +1 -0
- package/esm/tests/fakes/ids-fake.d.mts +22 -0
- package/esm/tests/fakes/ids-fake.d.mts.map +1 -0
- package/esm/tests/fakes/ids-fake.mjs +57 -0
- package/esm/tests/fakes/ids-fake.mjs.map +1 -0
- package/esm/tests/fakes/index.d.mts +8 -0
- package/esm/tests/fakes/index.mjs +10 -0
- package/esm/tests/fakes/mail-fake.d.mts +41 -0
- package/esm/tests/fakes/mail-fake.d.mts.map +1 -0
- package/esm/tests/fakes/mail-fake.mjs +111 -0
- package/esm/tests/fakes/mail-fake.mjs.map +1 -0
- package/esm/tests/fakes/queue-fake.d.mts +48 -0
- package/esm/tests/fakes/queue-fake.d.mts.map +1 -0
- package/esm/tests/fakes/queue-fake.mjs +134 -0
- package/esm/tests/fakes/queue-fake.mjs.map +1 -0
- package/esm/tests/fakes/storage-fake.d.mts +31 -0
- package/esm/tests/fakes/storage-fake.d.mts.map +1 -0
- package/esm/tests/fakes/storage-fake.mjs +122 -0
- package/esm/tests/fakes/storage-fake.mjs.map +1 -0
- package/esm/tests/fakes/test-fakes.d.mts +39 -0
- package/esm/tests/fakes/test-fakes.d.mts.map +1 -0
- package/esm/tests/fakes/test-fakes.mjs +90 -0
- package/esm/tests/fakes/test-fakes.mjs.map +1 -0
- package/esm/tests/index.d.mts +14 -2
- package/esm/tests/index.mjs +15 -2
- package/esm/tests/snapshot-response.d.mts +34 -0
- package/esm/tests/snapshot-response.d.mts.map +1 -0
- package/esm/tests/snapshot-response.mjs +42 -0
- package/esm/tests/snapshot-response.mjs.map +1 -0
- package/esm/tests/start-http-development-server.d.mts +22 -0
- package/esm/tests/start-http-development-server.d.mts.map +1 -1
- package/esm/tests/start-http-development-server.mjs +36 -3
- package/esm/tests/start-http-development-server.mjs.map +1 -1
- package/esm/tests/test-helpers.d.mts +20 -1
- package/esm/tests/test-helpers.d.mts.map +1 -1
- package/esm/tests/test-helpers.mjs +40 -27
- package/esm/tests/test-helpers.mjs.map +1 -1
- package/esm/tests/test-http-server.d.mts +62 -0
- package/esm/tests/test-http-server.d.mts.map +1 -0
- package/esm/tests/test-http-server.mjs +119 -0
- package/esm/tests/test-http-server.mjs.map +1 -0
- package/esm/tests/vitest-setup.d.mts +11 -0
- package/esm/tests/vitest-setup.d.mts.map +1 -1
- package/esm/tests/vitest-setup.mjs +12 -4
- package/esm/tests/vitest-setup.mjs.map +1 -1
- package/esm/tooling/agents-md/agents-md-markers.d.mts +27 -0
- package/esm/tooling/agents-md/agents-md-markers.d.mts.map +1 -0
- package/esm/tooling/agents-md/agents-md-markers.mjs +59 -0
- package/esm/tooling/agents-md/agents-md-markers.mjs.map +1 -0
- package/esm/tooling/agents-md/agents-md-refresher.d.mts +36 -0
- package/esm/tooling/agents-md/agents-md-refresher.d.mts.map +1 -0
- package/esm/tooling/agents-md/agents-md-refresher.mjs +72 -0
- package/esm/tooling/agents-md/agents-md-refresher.mjs.map +1 -0
- package/esm/tooling/agents-md/index.mjs +7 -0
- package/esm/tooling/agents-md/installed-skills.d.mts +30 -0
- package/esm/tooling/agents-md/installed-skills.d.mts.map +1 -0
- package/esm/tooling/agents-md/installed-skills.mjs +74 -0
- package/esm/tooling/agents-md/installed-skills.mjs.map +1 -0
- package/esm/tooling/agents-md/render-agents-md.d.mts +33 -0
- package/esm/tooling/agents-md/render-agents-md.d.mts.map +1 -0
- package/esm/tooling/agents-md/render-agents-md.mjs +195 -0
- package/esm/tooling/agents-md/render-agents-md.mjs.map +1 -0
- package/esm/tooling/agents-md/write-agents-md.d.mts +33 -0
- package/esm/tooling/agents-md/write-agents-md.d.mts.map +1 -0
- package/esm/tooling/agents-md/write-agents-md.mjs +49 -0
- package/esm/tooling/agents-md/write-agents-md.mjs.map +1 -0
- package/esm/tooling/board/board-message.d.mts +31 -0
- package/esm/tooling/board/board-message.d.mts.map +1 -0
- package/esm/tooling/board/board-message.mjs +86 -0
- package/esm/tooling/board/board-message.mjs.map +1 -0
- package/esm/tooling/board/board.d.mts +109 -0
- package/esm/tooling/board/board.d.mts.map +1 -0
- package/esm/tooling/board/board.mjs +406 -0
- package/esm/tooling/board/board.mjs.map +1 -0
- package/esm/tooling/board/board.types.d.mts +72 -0
- package/esm/tooling/board/board.types.d.mts.map +1 -0
- package/esm/tooling/board/board.types.mjs +54 -0
- package/esm/tooling/board/board.types.mjs.map +1 -0
- package/esm/tooling/check/changed-files.d.mts +33 -0
- package/esm/tooling/check/changed-files.d.mts.map +1 -0
- package/esm/tooling/check/changed-files.mjs +73 -0
- package/esm/tooling/check/changed-files.mjs.map +1 -0
- package/esm/tooling/check/check-report.types.d.mts +62 -0
- package/esm/tooling/check/check-report.types.d.mts.map +1 -0
- package/esm/tooling/check/check-report.types.mjs +37 -0
- package/esm/tooling/check/check-report.types.mjs.map +1 -0
- package/esm/tooling/check/code-style-conventions.mjs +106 -0
- package/esm/tooling/check/code-style-conventions.mjs.map +1 -0
- package/esm/tooling/check/conventions-step.d.mts +34 -0
- package/esm/tooling/check/conventions-step.d.mts.map +1 -0
- package/esm/tooling/check/conventions-step.mjs +184 -0
- package/esm/tooling/check/conventions-step.mjs.map +1 -0
- package/esm/tooling/check/environment-step.d.mts +18 -0
- package/esm/tooling/check/environment-step.d.mts.map +1 -0
- package/esm/tooling/check/environment-step.mjs +78 -0
- package/esm/tooling/check/environment-step.mjs.map +1 -0
- package/esm/tooling/check/index.d.mts +8 -0
- package/esm/tooling/check/index.mjs +10 -0
- package/esm/tooling/check/lint-step.d.mts +19 -0
- package/esm/tooling/check/lint-step.d.mts.map +1 -0
- package/esm/tooling/check/lint-step.mjs +111 -0
- package/esm/tooling/check/lint-step.mjs.map +1 -0
- package/esm/tooling/check/request-input.mjs +132 -0
- package/esm/tooling/check/request-input.mjs.map +1 -0
- package/esm/tooling/check/run-check.d.mts +35 -0
- package/esm/tooling/check/run-check.d.mts.map +1 -0
- package/esm/tooling/check/run-check.mjs +192 -0
- package/esm/tooling/check/run-check.mjs.map +1 -0
- package/esm/tooling/check/run-tests.d.mts +48 -0
- package/esm/tooling/check/run-tests.d.mts.map +1 -0
- package/esm/tooling/check/run-tests.mjs +93 -0
- package/esm/tooling/check/run-tests.mjs.map +1 -0
- package/esm/tooling/check/security-conventions.mjs +648 -0
- package/esm/tooling/check/security-conventions.mjs.map +1 -0
- package/esm/tooling/check/source-ast.mjs +195 -0
- package/esm/tooling/check/source-ast.mjs.map +1 -0
- package/esm/tooling/check/source-files.mjs +27 -0
- package/esm/tooling/check/source-files.mjs.map +1 -0
- package/esm/tooling/check/tests-step.d.mts +34 -0
- package/esm/tooling/check/tests-step.d.mts.map +1 -0
- package/esm/tooling/check/tests-step.mjs +177 -0
- package/esm/tooling/check/tests-step.mjs.map +1 -0
- package/esm/tooling/dev-state/dev-server-state.d.mts +39 -0
- package/esm/tooling/dev-state/dev-server-state.d.mts.map +1 -0
- package/esm/tooling/dev-state/dev-server-state.mjs +67 -0
- package/esm/tooling/dev-state/dev-server-state.mjs.map +1 -0
- package/esm/tooling/devtools/devtools-client.d.mts +91 -0
- package/esm/tooling/devtools/devtools-client.d.mts.map +1 -0
- package/esm/tooling/devtools/devtools-client.mjs +155 -0
- package/esm/tooling/devtools/devtools-client.mjs.map +1 -0
- package/esm/tooling/generate/generation.d.mts +78 -0
- package/esm/tooling/generate/generation.d.mts.map +1 -0
- package/esm/tooling/generate/generation.mjs +123 -0
- package/esm/tooling/generate/generation.mjs.map +1 -0
- package/esm/tooling/generate/generator-spec.d.mts +57 -0
- package/esm/tooling/generate/generator-spec.d.mts.map +1 -0
- package/esm/tooling/generate/generator-spec.mjs +102 -0
- package/esm/tooling/generate/generator-spec.mjs.map +1 -0
- package/esm/tooling/generate/index.mjs +6 -0
- package/esm/tooling/generate/project-files.mjs +121 -0
- package/esm/tooling/generate/project-files.mjs.map +1 -0
- package/esm/tooling/generate/run-cli.d.mts +40 -0
- package/esm/tooling/generate/run-cli.d.mts.map +1 -0
- package/esm/tooling/generate/run-cli.mjs +93 -0
- package/esm/tooling/generate/run-cli.mjs.map +1 -0
- package/esm/tooling/generate/unified-diff.d.mts +37 -0
- package/esm/tooling/generate/unified-diff.d.mts.map +1 -0
- package/esm/tooling/generate/unified-diff.mjs +161 -0
- package/esm/tooling/generate/unified-diff.mjs.map +1 -0
- package/esm/tooling/index.d.mts +41 -0
- package/esm/tooling/index.mjs +45 -0
- package/esm/tooling/inspect/boot-for-inspect.d.mts +23 -0
- package/esm/tooling/inspect/boot-for-inspect.d.mts.map +1 -0
- package/esm/tooling/inspect/boot-for-inspect.mjs +63 -0
- package/esm/tooling/inspect/boot-for-inspect.mjs.map +1 -0
- package/esm/tooling/inspect/collect-config.mjs +77 -0
- package/esm/tooling/inspect/collect-config.mjs.map +1 -0
- package/esm/tooling/inspect/collect-models.d.mts +9 -0
- package/esm/tooling/inspect/collect-models.d.mts.map +1 -0
- package/esm/tooling/inspect/collect-models.mjs +154 -0
- package/esm/tooling/inspect/collect-models.mjs.map +1 -0
- package/esm/tooling/inspect/collect-packages.d.mts +10 -0
- package/esm/tooling/inspect/collect-packages.d.mts.map +1 -0
- package/esm/tooling/inspect/collect-packages.mjs +157 -0
- package/esm/tooling/inspect/collect-packages.mjs.map +1 -0
- package/esm/tooling/inspect/collect-pages.mjs +108 -0
- package/esm/tooling/inspect/collect-pages.mjs.map +1 -0
- package/esm/tooling/inspect/collect-routes.mjs +168 -0
- package/esm/tooling/inspect/collect-routes.mjs.map +1 -0
- package/esm/tooling/inspect/event-recorder.d.mts +37 -0
- package/esm/tooling/inspect/event-recorder.d.mts.map +1 -0
- package/esm/tooling/inspect/event-recorder.mjs +91 -0
- package/esm/tooling/inspect/event-recorder.mjs.map +1 -0
- package/esm/tooling/inspect/index.d.mts +7 -0
- package/esm/tooling/inspect/index.mjs +7 -0
- package/esm/tooling/inspect/inspect-app.d.mts +53 -0
- package/esm/tooling/inspect/inspect-app.d.mts.map +1 -0
- package/esm/tooling/inspect/inspect-app.mjs +92 -0
- package/esm/tooling/inspect/inspect-app.mjs.map +1 -0
- package/esm/tooling/inspect/inspect-report.schema.d.mts +15 -0
- package/esm/tooling/inspect/inspect-report.schema.d.mts.map +1 -0
- package/esm/tooling/inspect/inspect-report.schema.mjs +463 -0
- package/esm/tooling/inspect/inspect-report.schema.mjs.map +1 -0
- package/esm/tooling/inspect/inspect-report.types.d.mts +196 -0
- package/esm/tooling/inspect/inspect-report.types.d.mts.map +1 -0
- package/esm/tooling/inspect/inspect-report.types.mjs +33 -0
- package/esm/tooling/inspect/inspect-report.types.mjs.map +1 -0
- package/esm/tooling/mcp/create-mcp-context.d.mts +26 -0
- package/esm/tooling/mcp/create-mcp-context.d.mts.map +1 -0
- package/esm/tooling/mcp/create-mcp-context.mjs +75 -0
- package/esm/tooling/mcp/create-mcp-context.mjs.map +1 -0
- package/esm/tooling/mcp/db-schema.d.mts +49 -0
- package/esm/tooling/mcp/db-schema.d.mts.map +1 -0
- package/esm/tooling/mcp/db-schema.mjs +56 -0
- package/esm/tooling/mcp/db-schema.mjs.map +1 -0
- package/esm/tooling/mcp/docs-search.d.mts +72 -0
- package/esm/tooling/mcp/docs-search.d.mts.map +1 -0
- package/esm/tooling/mcp/docs-search.mjs +178 -0
- package/esm/tooling/mcp/docs-search.mjs.map +1 -0
- package/esm/tooling/mcp/index.mjs +9 -0
- package/esm/tooling/mcp/load-ai-tools.d.mts +62 -0
- package/esm/tooling/mcp/load-ai-tools.d.mts.map +1 -0
- package/esm/tooling/mcp/load-ai-tools.mjs +44 -0
- package/esm/tooling/mcp/load-ai-tools.mjs.map +1 -0
- package/esm/tooling/mcp/mcp-tools.d.mts +60 -0
- package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -0
- package/esm/tooling/mcp/mcp-tools.mjs +513 -0
- package/esm/tooling/mcp/mcp-tools.mjs.map +1 -0
- package/esm/tooling/mcp/start-mcp-server.d.mts +56 -0
- package/esm/tooling/mcp/start-mcp-server.d.mts.map +1 -0
- package/esm/tooling/mcp/start-mcp-server.mjs +126 -0
- package/esm/tooling/mcp/start-mcp-server.mjs.map +1 -0
- package/esm/tooling/mcp/tool-input.d.mts +75 -0
- package/esm/tooling/mcp/tool-input.d.mts.map +1 -0
- package/esm/tooling/mcp/tool-input.mjs +72 -0
- package/esm/tooling/mcp/tool-input.mjs.map +1 -0
- package/esm/tooling/problem.d.mts +45 -0
- package/esm/tooling/problem.d.mts.map +1 -0
- package/esm/tooling/problem.mjs +28 -0
- package/esm/tooling/problem.mjs.map +1 -0
- package/esm/tooling/trace/trace-report.types.d.mts +71 -0
- package/esm/tooling/trace/trace-report.types.d.mts.map +1 -0
- package/esm/tooling/trace/trace-report.types.mjs +7 -0
- package/esm/tooling/trace/trace-report.types.mjs.map +1 -0
- package/esm/tooling/trace/trace-request.d.mts +83 -0
- package/esm/tooling/trace/trace-request.d.mts.map +1 -0
- package/esm/tooling/trace/trace-request.mjs +241 -0
- package/esm/tooling/trace/trace-request.mjs.map +1 -0
- package/esm/tooling/typecheck/index.d.mts +1 -0
- package/esm/tooling/typecheck/index.mjs +3 -0
- package/esm/tooling/typecheck/run-typecheck.d.mts +59 -0
- package/esm/tooling/typecheck/run-typecheck.d.mts.map +1 -0
- package/esm/tooling/typecheck/run-typecheck.mjs +153 -0
- package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -0
- package/esm/upgrade/codemods/head-viewport.mjs +46 -0
- package/esm/upgrade/codemods/head-viewport.mjs.map +1 -0
- package/esm/upgrade/codemods/helpers.mjs +81 -0
- package/esm/upgrade/codemods/helpers.mjs.map +1 -0
- package/esm/upgrade/codemods/index.mjs +34 -0
- package/esm/upgrade/codemods/index.mjs.map +1 -0
- package/esm/upgrade/codemods/logger-sync-calls.mjs +57 -0
- package/esm/upgrade/codemods/logger-sync-calls.mjs.map +1 -0
- package/esm/upgrade/codemods/package-json.mjs +122 -0
- package/esm/upgrade/codemods/package-json.mjs.map +1 -0
- package/esm/upgrade/codemods/request-log-snapshot.mjs +82 -0
- package/esm/upgrade/codemods/request-log-snapshot.mjs.map +1 -0
- package/esm/upgrade/codemods/review-sites.mjs +262 -0
- package/esm/upgrade/codemods/review-sites.mjs.map +1 -0
- package/esm/upgrade/diff.mjs +119 -0
- package/esm/upgrade/diff.mjs.map +1 -0
- package/esm/upgrade/format-upgrade-report.mjs +32 -0
- package/esm/upgrade/format-upgrade-report.mjs.map +1 -0
- package/esm/upgrade/load-ts-morph.mjs +48 -0
- package/esm/upgrade/load-ts-morph.mjs.map +1 -0
- package/esm/upgrade/notes.mjs +16 -0
- package/esm/upgrade/notes.mjs.map +1 -0
- package/esm/upgrade/run-upgrade.mjs +246 -0
- package/esm/upgrade/run-upgrade.mjs.map +1 -0
- package/esm/upgrade/upgrade-command.action.mjs +37 -0
- package/esm/upgrade/upgrade-command.action.mjs.map +1 -0
- package/esm/upgrade/version.mjs +39 -0
- package/esm/upgrade/version.mjs.map +1 -0
- package/esm/use-cases/use-cases-registry.mjs.map +1 -1
- package/esm/utils/clock.d.mts +33 -0
- package/esm/utils/clock.d.mts.map +1 -0
- package/esm/utils/clock.mjs +27 -0
- package/esm/utils/clock.mjs.map +1 -0
- package/esm/utils/framework-vesion.mjs +1 -1
- package/esm/utils/framework-vesion.mjs.map +1 -1
- package/esm/utils/ids.d.mts +32 -0
- package/esm/utils/ids.d.mts.map +1 -0
- package/esm/utils/ids.mjs +33 -0
- package/esm/utils/ids.mjs.map +1 -0
- package/esm/utils/index.d.mts +3 -0
- package/esm/utils/index.mjs +3 -0
- package/esm/utils/runtime.d.mts +59 -0
- package/esm/utils/runtime.d.mts.map +1 -0
- package/esm/utils/runtime.mjs +85 -0
- package/esm/utils/runtime.mjs.map +1 -0
- package/esm/validation/index.d.mts +1 -1
- package/esm/validation/types.d.mts +57 -2
- package/esm/validation/types.d.mts.map +1 -1
- package/esm/validation/validateAll.mjs +19 -2
- package/esm/validation/validateAll.mjs.map +1 -1
- package/esm/validation/validation-failure-status.mjs +15 -0
- package/esm/validation/validation-failure-status.mjs.map +1 -0
- package/esm/validation/validators/file-validator.d.mts +0 -16
- package/esm/validation/validators/file-validator.d.mts.map +1 -1
- package/esm/warlock-config/bundle-config.mjs +1 -1
- package/esm/warlock-config/types.d.mts +27 -3
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/llms-full.txt +3166 -736
- package/llms.txt +16 -6
- package/package.json +43 -13
- package/schemas/inspect-report.schema.json +554 -0
- package/skills/README.md +9 -0
- package/skills/add-connector/SKILL.md +26 -38
- package/skills/benchmark-code/SKILL.md +30 -24
- package/skills/build-restful/SKILL.md +14 -14
- package/skills/build-url/SKILL.md +18 -18
- package/skills/configure-app/SKILL.md +107 -14
- package/skills/create-controller/SKILL.md +25 -12
- package/skills/create-module/SKILL.md +3 -3
- package/skills/define-resource/SKILL.md +32 -29
- package/skills/encrypt-data/SKILL.md +21 -19
- package/skills/generate-openapi/SKILL.md +50 -24
- package/skills/hash-password/SKILL.md +2 -2
- package/skills/health-checks/SKILL.md +24 -7
- package/skills/index.md +9 -4
- package/skills/lower-stage3-decorators/SKILL.md +4 -4
- package/skills/make-endpoint/SKILL.md +110 -0
- package/skills/model-factories/SKILL.md +92 -0
- package/skills/process-image/SKILL.md +32 -30
- package/skills/register-route/SKILL.md +109 -10
- package/skills/request-memo/SKILL.md +1 -1
- package/skills/request-tracing/SKILL.md +4 -1
- package/skills/resolve-path/SKILL.md +45 -44
- package/skills/retry-operation/SKILL.md +20 -11
- package/skills/run-app/SKILL.md +106 -22
- package/skills/send-response/SKILL.md +179 -14
- package/skills/store-file/SKILL.md +93 -53
- package/skills/test-fakes/SKILL.md +123 -0
- package/skills/test-http/SKILL.md +125 -21
- package/skills/test-service/SKILL.md +41 -1
- package/skills/update-packages/SKILL.md +29 -18
- package/skills/upgrade-from-5-29/SKILL.md +413 -0
- package/skills/upload-file/SKILL.md +31 -33
- package/skills/use-app-context/SKILL.md +38 -31
- package/skills/use-middleware/SKILL.md +45 -25
- package/skills/use-model-transformers/SKILL.md +37 -28
- package/skills/use-repository/SKILL.md +2 -2
- package/skills/validate-input/SKILL.md +72 -28
- package/skills/warlock-agents-md/SKILL.md +96 -0
- package/skills/warlock-board/SKILL.md +123 -0
- package/skills/warlock-check/SKILL.md +132 -0
- package/skills/warlock-conventions/SKILL.md +115 -0
- package/skills/warlock-doctor/SKILL.md +55 -22
- package/skills/warlock-inspect/SKILL.md +134 -0
- package/skills/warlock-mcp/SKILL.md +120 -0
- package/skills/warlock-routes/SKILL.md +18 -11
- package/skills/warlock-trace/SKILL.md +81 -0
- package/skills/wire-socket/SKILL.md +8 -8
- package/skills/write-seeder/SKILL.md +46 -32
- package/skills/write-use-case/SKILL.md +40 -27
- package/esm/http/uploads/matches-if-none-match.mjs +0 -13
- package/esm/http/uploads/matches-if-none-match.mjs.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getHttpReadyReport } from "../http/ready-report.mjs";
|
|
2
|
+
import { connectorsManager } from "../connectors/connectors-manager.mjs";
|
|
3
|
+
import { devLogInfo, devLogWarn } from "./dev-logger.mjs";
|
|
4
|
+
import { removeDevServerState, writeDevServerState } from "../tooling/dev-state/dev-server-state.mjs";
|
|
5
|
+
import { DEFAULT_DEVTOOLS_PATH } from "../tooling/devtools/devtools-client.mjs";
|
|
6
|
+
|
|
7
|
+
//#region ../../packages/core/src/dev-server/dev-agent-tooling.ts
|
|
8
|
+
/** Resolve `devServer.mcp` and the `--mcp` flag (the flag turns it on with the config's options). */
|
|
9
|
+
function resolveDevMcpOptions(flag, config) {
|
|
10
|
+
if (!flag && !config) return false;
|
|
11
|
+
const settings = typeof config === "object" ? config : {};
|
|
12
|
+
return {
|
|
13
|
+
port: settings.port ?? 0,
|
|
14
|
+
...settings.token ? { token: settings.token } : {},
|
|
15
|
+
allowWrites: settings.allowWrites === true
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function errorMessage(error) {
|
|
19
|
+
return error instanceof Error ? error.message : String(error);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The agent-facing side of `warlock dev`, all best-effort — none of it may
|
|
23
|
+
* stop the app from serving:
|
|
24
|
+
*
|
|
25
|
+
* - records the server's address in `.warlock/dev-server.json` (read by
|
|
26
|
+
* `warlock trace` and `warlock mcp`), removed on shutdown;
|
|
27
|
+
* - keeps the generated section of `AGENTS.md` fresh (unless
|
|
28
|
+
* `devServer.agentsMd: false`), on boot and after each reload, debounced;
|
|
29
|
+
* - with `--mcp` / `devServer.mcp`, serves `warlock mcp` over HTTP on
|
|
30
|
+
* loopback from this process, so `inspect_*` reads the live registries.
|
|
31
|
+
*
|
|
32
|
+
* The tooling modules are imported lazily: they pull in the TypeScript
|
|
33
|
+
* compiler and the generators, which a dev boot without them never needs.
|
|
34
|
+
*/
|
|
35
|
+
var DevAgentTooling = class {
|
|
36
|
+
/** @param cwd Project root. Default: `process.cwd()`. */
|
|
37
|
+
constructor(cwd = process.cwd()) {
|
|
38
|
+
this.cwd = cwd;
|
|
39
|
+
this.stateWritten = false;
|
|
40
|
+
}
|
|
41
|
+
async start(options) {
|
|
42
|
+
const http = getHttpReadyReport();
|
|
43
|
+
const devtoolsActive = connectorsManager.list().some((connector) => connector.name === "devtools" && connector.isActive());
|
|
44
|
+
if (options.mcp) await this.startMcp(options.mcp, http?.url);
|
|
45
|
+
if (http) try {
|
|
46
|
+
writeDevServerState({
|
|
47
|
+
schemaVersion: 1,
|
|
48
|
+
pid: process.pid,
|
|
49
|
+
url: http.url,
|
|
50
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
51
|
+
devtools: devtoolsActive ? { path: DEFAULT_DEVTOOLS_PATH } : null,
|
|
52
|
+
mcp: this.mcp?.url ? { url: this.mcp.url } : null
|
|
53
|
+
}, this.cwd);
|
|
54
|
+
this.stateWritten = true;
|
|
55
|
+
} catch (error) {
|
|
56
|
+
devLogWarn(`Could not record the dev server address: ${errorMessage(error)}`);
|
|
57
|
+
}
|
|
58
|
+
if (options.agentsMd) await this.startAgentsMd();
|
|
59
|
+
}
|
|
60
|
+
/** Called after every hot reload: routes or modules may have changed. */
|
|
61
|
+
afterReload() {
|
|
62
|
+
this.refresher?.schedule();
|
|
63
|
+
}
|
|
64
|
+
async shutdown() {
|
|
65
|
+
this.refresher?.dispose();
|
|
66
|
+
this.refresher = void 0;
|
|
67
|
+
if (this.mcp) {
|
|
68
|
+
const server = this.mcp;
|
|
69
|
+
this.mcp = void 0;
|
|
70
|
+
try {
|
|
71
|
+
await server.close();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
devLogWarn(`MCP server did not close cleanly: ${errorMessage(error)}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (this.stateWritten) {
|
|
77
|
+
this.stateWritten = false;
|
|
78
|
+
removeDevServerState(process.pid, this.cwd);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async startAgentsMd() {
|
|
82
|
+
try {
|
|
83
|
+
const [{ createAgentsMdRefresher }, { inspectApp }] = await Promise.all([import("../tooling/agents-md/index.mjs"), import("../tooling/inspect/inspect-app.mjs")]);
|
|
84
|
+
this.refresher = createAgentsMdRefresher({
|
|
85
|
+
cwd: this.cwd,
|
|
86
|
+
collect: () => inspectApp({ sections: [
|
|
87
|
+
"routes",
|
|
88
|
+
"models",
|
|
89
|
+
"packages"
|
|
90
|
+
] }),
|
|
91
|
+
onWrite: (result) => {
|
|
92
|
+
if (result.status === "created" || result.status === "updated") devLogInfo(`AGENTS.md generated section ${result.status}`);
|
|
93
|
+
},
|
|
94
|
+
onError: (error) => devLogWarn(`AGENTS.md not refreshed: ${errorMessage(error)}`)
|
|
95
|
+
});
|
|
96
|
+
this.refresher.schedule();
|
|
97
|
+
} catch (error) {
|
|
98
|
+
devLogWarn(`AGENTS.md refresh is off: ${errorMessage(error)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async startMcp(options, serverUrl) {
|
|
102
|
+
try {
|
|
103
|
+
const [{ createMcpContext }, { startWarlockMcpServer }, { inspectApp }, { featuresMap }] = await Promise.all([
|
|
104
|
+
import("../tooling/mcp/create-mcp-context.mjs"),
|
|
105
|
+
import("../tooling/mcp/start-mcp-server.mjs"),
|
|
106
|
+
import("../tooling/inspect/inspect-app.mjs"),
|
|
107
|
+
import("../generations/features/index.mjs")
|
|
108
|
+
]);
|
|
109
|
+
const context = createMcpContext({
|
|
110
|
+
cwd: this.cwd,
|
|
111
|
+
allowWrites: options.allowWrites,
|
|
112
|
+
inspect: (sections) => inspectApp({ sections }),
|
|
113
|
+
...process.argv[1] ? { cliEntry: process.argv[1] } : {},
|
|
114
|
+
devtools: serverUrl ? { url: serverUrl } : {},
|
|
115
|
+
features: Object.keys(featuresMap)
|
|
116
|
+
});
|
|
117
|
+
this.mcp = await startWarlockMcpServer({
|
|
118
|
+
context,
|
|
119
|
+
transport: {
|
|
120
|
+
type: "http",
|
|
121
|
+
host: "127.0.0.1",
|
|
122
|
+
port: options.port,
|
|
123
|
+
...options.token ? { token: options.token } : {}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
devLogInfo(`MCP server at ${this.mcp.url ?? "?"} (${options.allowWrites ? "writes allowed" : "read-only"}${options.token ? ", token required" : ""})`);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
devLogWarn(`MCP server not started: ${errorMessage(error)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { DevAgentTooling, resolveDevMcpOptions };
|
|
135
|
+
//# sourceMappingURL=dev-agent-tooling.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-agent-tooling.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/dev-agent-tooling.ts"],"sourcesContent":["import { connectorsManager } from \"../connectors/connectors-manager\";\nimport { getHttpReadyReport } from \"../http/ready-report\";\nimport { removeDevServerState, writeDevServerState } from \"../tooling/dev-state/dev-server-state\";\nimport { DEFAULT_DEVTOOLS_PATH } from \"../tooling/devtools/devtools-client\";\nimport { devLogInfo, devLogWarn } from \"./dev-logger\";\n\n/** `devServer.mcp` (or `--mcp`) resolved: off, or the HTTP options. */\nexport type DevMcpOptions = false | { port: number; token?: string; allowWrites: boolean };\n\n/** Resolve `devServer.mcp` and the `--mcp` flag (the flag turns it on with the config's options). */\nexport function resolveDevMcpOptions(\n flag: boolean | undefined,\n config: boolean | { port?: number; token?: string; allowWrites?: boolean } | undefined,\n): DevMcpOptions {\n if (!flag && !config) return false;\n\n const settings = typeof config === \"object\" ? config : {};\n\n return {\n port: settings.port ?? 0,\n ...(settings.token ? { token: settings.token } : {}),\n allowWrites: settings.allowWrites === true,\n };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * The agent-facing side of `warlock dev`, all best-effort — none of it may\n * stop the app from serving:\n *\n * - records the server's address in `.warlock/dev-server.json` (read by\n * `warlock trace` and `warlock mcp`), removed on shutdown;\n * - keeps the generated section of `AGENTS.md` fresh (unless\n * `devServer.agentsMd: false`), on boot and after each reload, debounced;\n * - with `--mcp` / `devServer.mcp`, serves `warlock mcp` over HTTP on\n * loopback from this process, so `inspect_*` reads the live registries.\n *\n * The tooling modules are imported lazily: they pull in the TypeScript\n * compiler and the generators, which a dev boot without them never needs.\n */\nexport class DevAgentTooling {\n private refresher?: { schedule(): void; dispose(): void };\n private mcp?: { url?: string; close(): Promise<void> };\n private stateWritten = false;\n\n /** @param cwd Project root. Default: `process.cwd()`. */\n public constructor(private readonly cwd: string = process.cwd()) {}\n\n public async start(options: { agentsMd: boolean; mcp: DevMcpOptions }): Promise<void> {\n const http = getHttpReadyReport();\n const devtoolsActive = connectorsManager\n .list()\n .some((connector) => connector.name === \"devtools\" && connector.isActive());\n\n if (options.mcp) {\n await this.startMcp(options.mcp, http?.url);\n }\n\n if (http) {\n try {\n writeDevServerState(\n {\n schemaVersion: 1,\n pid: process.pid,\n url: http.url,\n startedAt: new Date().toISOString(),\n devtools: devtoolsActive ? { path: DEFAULT_DEVTOOLS_PATH } : null,\n mcp: this.mcp?.url ? { url: this.mcp.url } : null,\n },\n this.cwd,\n );\n this.stateWritten = true;\n } catch (error) {\n devLogWarn(`Could not record the dev server address: ${errorMessage(error)}`);\n }\n }\n\n if (options.agentsMd) {\n await this.startAgentsMd();\n }\n }\n\n /** Called after every hot reload: routes or modules may have changed. */\n public afterReload(): void {\n this.refresher?.schedule();\n }\n\n public async shutdown(): Promise<void> {\n this.refresher?.dispose();\n this.refresher = undefined;\n\n if (this.mcp) {\n const server = this.mcp;\n this.mcp = undefined;\n\n try {\n await server.close();\n } catch (error) {\n devLogWarn(`MCP server did not close cleanly: ${errorMessage(error)}`);\n }\n }\n\n if (this.stateWritten) {\n this.stateWritten = false;\n removeDevServerState(process.pid, this.cwd);\n }\n }\n\n private async startAgentsMd(): Promise<void> {\n try {\n const [{ createAgentsMdRefresher }, { inspectApp }] = await Promise.all([\n import(\"../tooling/agents-md\"),\n import(\"../tooling/inspect/inspect-app\"),\n ]);\n\n this.refresher = createAgentsMdRefresher({\n cwd: this.cwd,\n collect: () => inspectApp({ sections: [\"routes\", \"models\", \"packages\"] }),\n onWrite: (result) => {\n if (result.status === \"created\" || result.status === \"updated\") {\n devLogInfo(`AGENTS.md generated section ${result.status}`);\n }\n },\n onError: (error) => devLogWarn(`AGENTS.md not refreshed: ${errorMessage(error)}`),\n });\n this.refresher.schedule();\n } catch (error) {\n devLogWarn(`AGENTS.md refresh is off: ${errorMessage(error)}`);\n }\n }\n\n private async startMcp(\n options: Exclude<DevMcpOptions, false>,\n serverUrl?: string,\n ): Promise<void> {\n try {\n const [{ createMcpContext }, { startWarlockMcpServer }, { inspectApp }, { featuresMap }] =\n await Promise.all([\n import(\"../tooling/mcp/create-mcp-context\"),\n import(\"../tooling/mcp/start-mcp-server\"),\n import(\"../tooling/inspect/inspect-app\"),\n import(\"../generations/features\"),\n ]);\n const context = createMcpContext({\n cwd: this.cwd,\n allowWrites: options.allowWrites,\n inspect: (sections) => inspectApp({ sections }),\n ...(process.argv[1] ? { cliEntry: process.argv[1] } : {}),\n devtools: serverUrl ? { url: serverUrl } : {},\n features: Object.keys(featuresMap),\n });\n\n this.mcp = await startWarlockMcpServer({\n context,\n transport: {\n type: \"http\",\n host: \"127.0.0.1\",\n port: options.port,\n ...(options.token ? { token: options.token } : {}),\n },\n });\n\n devLogInfo(\n `MCP server at ${this.mcp.url ?? \"?\"} (${options.allowWrites ? \"writes allowed\" : \"read-only\"}${options.token ? \", token required\" : \"\"})`,\n );\n } catch (error) {\n devLogWarn(`MCP server not started: ${errorMessage(error)}`);\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-logger.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/dev-logger.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport dayjs from \"dayjs\";\nimport { Path } from \"../utils/normalized-path\";\n\n/**\n * Dev server logger — Vite-style formatting helpers.\n */\n\nfunction timestamp(): string {\n return colors.dim(`${dayjs().format(\"HH:mm:ss A\")}`);\n}\n\nexport function devLog(message: string) {\n console.log(`${timestamp()} ${message}`);\n}\n\nexport function devLogSuccess(message: string) {\n console.log(`${timestamp()} ${colors.green(\"✓\")} ${colors.green(message)}`);\n}\n\n/**\n * Colourise a stack trace so the eye lands on *your* code.\n *\n * - Error header (`ReferenceError: x is not defined`) → bold red.\n * - Frames in project `src/` → highlighted: a green `›` pointer, yellow\n * function name, cyan relative path, dim `:line:col`. These are almost\n * always where the bug is.\n * - Framework (`@warlock.js`), `node_modules`, and `node:` internal frames\n * → dimmed and relativised. Still there for context, just out of the way.\n *\n * Source maps are enabled in dev, so the paths/lines here are already the\n * original `.ts` locations — this only changes how they're painted.\n */\nexport function formatErrorStack(stack: string): string {\n const frame = /^(\\s*)at (.+?) \\((.+):(\\d+):(\\d+)\\)$/;\n const bareFrame = /^(\\s*)at (.+):(\\d+):(\\d+)$/;\n let headerDone = false;\n\n return stack\n .split(\"\\n\")\n .map((line) => {\n const withFn = line.match(frame);\n const bare = line.match(bareFrame);\n\n if (!withFn && !bare) {\n // Header line(s) before the first frame.\n const painted = headerDone ? colors.dim(line) : colors.bold(colors.red(line));\n return painted;\n }\n\n headerDone = true;\n\n // Every read here is defaulted rather than asserted, and the reason is\n // what this function IS: a stack-trace formatter. If it throws while\n // formatting, it throws INSIDE error reporting — and what the developer\n // then sees is this function's failure instead of the error they were\n // actually chasing. An unreadable frame should degrade to a blank field,\n // never take the report down with it — every fatal needs an\n // unconditional floor.\n const fn = (withFn ? withFn[2] : \"\") ?? \"\";\n const file = (withFn ? withFn[3] : bare?.[2]) ?? \"\";\n const lineNo = (withFn ? withFn[4] : bare?.[3]) ?? \"\";\n const col = (withFn ? withFn[5] : bare?.[4]) ?? \"\";\n\n const isNodeInternal = file.startsWith(\"node:\");\n const isDep = file.includes(\"node_modules\");\n const isFramework = /[\\\\/]@warlock\\.js[\\\\/]/.test(file);\n const isUserCode = !isNodeInternal && !isDep && !isFramework;\n\n const rel = isNodeInternal ? file : Path.toRelative(file);\n const loc = `:${lineNo}:${col}`;\n\n if (isUserCode) {\n return (\n ` ${colors.green(\"›\")} ${colors.dim(\"at\")} ` +\n `${colors.yellow(fn || \"<anonymous>\")} ` +\n `${colors.cyan(rel)}${colors.dim(loc)}`\n );\n }\n\n const label = fn ? `at ${fn} ${rel}${loc}` : `at ${rel}${loc}`;\n return ` ${colors.dim(label)}`;\n })\n .join(\"\\n\");\n}\n\nexport function devLogError(message: string, error?: any) {\n console.log(`${timestamp()} ${colors.red(\"✗\")} ${colors.red(message)}`);\n if (error?.stack) console.log(formatErrorStack(error.stack));\n}\n\nexport function devLogWarn(message: string) {\n console.log(`${timestamp()} ${colors.yellow(\"⚠\")} ${colors.yellow(message)}`);\n}\n\nexport function devLogInfo(message: string) {\n console.log(`${timestamp()} ${colors.cyan(message)}`);\n}\n\nexport function devLogDim(message: string) {\n console.log(`${timestamp()} ${colors.dim(message)}`);\n}\n\nexport function devLogHMR(file: string, dependents?: number, durationMs?: number) {\n const relativePath = Path.toRelative(file);\n const depInfo = dependents\n ? colors.dim(` +${dependents} module${dependents > 1 ? \"s\" : \"\"}`)\n : \"\";\n const durationInfo = durationMs !== undefined ? colors.dim(` (${durationMs}ms)`) : \"\";\n console.log(\n `${timestamp()} 🔥 ${colors.green(\"hmr update\")} ${colors.dim(relativePath)}${depInfo}${durationInfo}`,\n );\n}\n\n/**\n * Per-phase breakdown for one hot reload, printed only when\n * `devServer.timings` is on. Phases run in this order: the watcher's\n * `awaitWriteFinish` settle wait, this handler's own debounce wait,\n * module-graph invalidation (version bumps), re-import of the changed\n * modules, and connector restart/rebind.\n */\nexport type ReloadPhaseTimings = {\n watcherSettleMs: number;\n debounceWaitMs: number;\n moduleGraphInvalidationMs: number;\n reimportMs: number;\n connectorRestartMs: number;\n};\n\nexport function devLogTimings(timings: ReloadPhaseTimings) {\n const phase = (label: string, ms: number) => `${colors.dim(label)} ${colors.dim(`${Math.round(ms)}ms`)}`;\n const line = [\n phase(\"watcher\", timings.watcherSettleMs),\n phase(\"debounce\", timings.debounceWaitMs),\n phase(\"graph\", timings.moduleGraphInvalidationMs),\n phase(\"reimport\", timings.reimportMs),\n phase(\"connectors\", timings.connectorRestartMs),\n ].join(colors.dim(\" · \"));\n console.log(`${timestamp()} ${colors.dim(\"⏱\")} ${line}`);\n}\n\nexport function devLogConfig(file: string, connectors?: string[]) {\n const relativePath = Path.toRelative(file);\n const connectorInfo =\n connectors && connectors.length > 0 ? colors.dim(` → restarting ${connectors.join(\", \")}`) : \"\";\n console.log(\n `${timestamp()} ${colors.cyan(\"config reload\")} ${colors.dim(relativePath)}${connectorInfo}`,\n );\n}\n\nexport function devLogReady(message: string) {\n console.log(`\\n${timestamp()} ${colors.green(\"➜\")} ${colors.bold(message)}`);\n}\n\nexport function devLogSection(title: string) {\n console.log(`\\n${timestamp()} ${colors.bold(colors.cyan(title))}`);\n}\n\n/**\n * Format ERR_MODULE_NOT_FOUND so the displayed paths are relative to the\n * project root. The loader hook keeps source paths in the URL so we only\n * need to strip the absolute prefix — no cache-path translation any more.\n */\nexport function formatModuleNotFoundError(error: Error, suggestions?: string[]): string {\n const match = error.message.match(/Cannot find module '([^']+)' imported from '([^']+)'/);\n if (!match) return error.message;\n\n // Same rule as the frame formatter above: this renders a MODULE NOT FOUND\n // report, so a missing capture must degrade the message, not replace the\n // user's error with a crash inside the reporter.\n const [, rawModulePath, rawImporterPath] = match;\n const modulePath = rawModulePath ?? \"\";\n const importerPath = rawImporterPath ?? \"\";\n const lines: string[] = [\n \"\",\n `${colors.red(\"❌ MODULE NOT FOUND\")}`,\n \"\",\n `${colors.dim(\"Cannot find:\")} ${colors.cyan(Path.toRelative(modulePath))}`,\n \"\",\n `${colors.dim(\"Imported by:\")}`,\n ` ${colors.yellow(\"→\")} ${colors.white(Path.toRelative(importerPath))}`,\n ];\n\n if (suggestions && suggestions.length > 0) {\n lines.push(\"\");\n lines.push(`${colors.dim(\"Did you mean?\")}`);\n suggestions.forEach((s) => lines.push(` ${colors.cyan(\"→\")} ${colors.green(s)}`));\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\n/** @deprecated alias retained for older callers. Use `devLog` directly. */\nexport const devServeLog = devLog;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dev-logger.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/dev-logger.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport dayjs from \"dayjs\";\nimport { Path } from \"../utils/normalized-path\";\n\n/**\n * Dev server logger — Vite-style formatting helpers.\n */\n\nfunction timestamp(): string {\n return colors.dim(`${dayjs().format(\"HH:mm:ss A\")}`);\n}\n\nexport function devLog(message: string) {\n console.log(`${timestamp()} ${message}`);\n}\n\nexport function devLogSuccess(message: string) {\n console.log(`${timestamp()} ${colors.green(\"✓\")} ${colors.green(message)}`);\n}\n\n/**\n * Colourise a stack trace so the eye lands on *your* code.\n *\n * - Error header (`ReferenceError: x is not defined`) → bold red.\n * - Frames in project `src/` → highlighted: a green `›` pointer, yellow\n * function name, cyan relative path, dim `:line:col`. These are almost\n * always where the bug is.\n * - Framework (`@warlock.js`), `node_modules`, and `node:` internal frames\n * → dimmed and relativised. Still there for context, just out of the way.\n *\n * Source maps are enabled in dev, so the paths/lines here are already the\n * original `.ts` locations — this only changes how they're painted.\n */\nexport function formatErrorStack(stack: string): string {\n const frame = /^(\\s*)at (.+?) \\((.+):(\\d+):(\\d+)\\)$/;\n const bareFrame = /^(\\s*)at (.+):(\\d+):(\\d+)$/;\n let headerDone = false;\n\n return stack\n .split(\"\\n\")\n .map((line) => {\n const withFn = line.match(frame);\n const bare = line.match(bareFrame);\n\n if (!withFn && !bare) {\n // Header line(s) before the first frame.\n const painted = headerDone ? colors.dim(line) : colors.bold(colors.red(line));\n return painted;\n }\n\n headerDone = true;\n\n // Every read here is defaulted rather than asserted, and the reason is\n // what this function IS: a stack-trace formatter. If it throws while\n // formatting, it throws INSIDE error reporting — and what the developer\n // then sees is this function's failure instead of the error they were\n // actually chasing. An unreadable frame should degrade to a blank field,\n // never take the report down with it — every fatal needs an\n // unconditional floor.\n const fn = (withFn ? withFn[2] : \"\") ?? \"\";\n const file = (withFn ? withFn[3] : bare?.[2]) ?? \"\";\n const lineNo = (withFn ? withFn[4] : bare?.[3]) ?? \"\";\n const col = (withFn ? withFn[5] : bare?.[4]) ?? \"\";\n\n const isNodeInternal = file.startsWith(\"node:\");\n const isDep = file.includes(\"node_modules\");\n const isFramework = /[\\\\/]@warlock\\.js[\\\\/]/.test(file);\n const isUserCode = !isNodeInternal && !isDep && !isFramework;\n\n const rel = isNodeInternal ? file : Path.toRelative(file);\n const loc = `:${lineNo}:${col}`;\n\n if (isUserCode) {\n return (\n ` ${colors.green(\"›\")} ${colors.dim(\"at\")} ` +\n `${colors.yellow(fn || \"<anonymous>\")} ` +\n `${colors.cyan(rel)}${colors.dim(loc)}`\n );\n }\n\n const label = fn ? `at ${fn} ${rel}${loc}` : `at ${rel}${loc}`;\n return ` ${colors.dim(label)}`;\n })\n .join(\"\\n\");\n}\n\nexport function devLogError(message: string, error?: any) {\n console.log(`${timestamp()} ${colors.red(\"✗\")} ${colors.red(message)}`);\n if (error?.stack) console.log(formatErrorStack(error.stack));\n}\n\nexport function devLogWarn(message: string) {\n console.log(`${timestamp()} ${colors.yellow(\"⚠\")} ${colors.yellow(message)}`);\n}\n\nexport function devLogInfo(message: string) {\n console.log(`${timestamp()} ${colors.cyan(message)}`);\n}\n\nexport function devLogDim(message: string) {\n console.log(`${timestamp()} ${colors.dim(message)}`);\n}\n\nexport function devLogHMR(file: string, dependents?: number, durationMs?: number) {\n const relativePath = Path.toRelative(file);\n const depInfo = dependents\n ? colors.dim(` +${dependents} module${dependents > 1 ? \"s\" : \"\"}`)\n : \"\";\n const durationInfo = durationMs !== undefined ? colors.dim(` (${durationMs}ms)`) : \"\";\n console.log(\n `${timestamp()} 🔥 ${colors.green(\"hmr update\")} ${colors.dim(relativePath)}${depInfo}${durationInfo}`,\n );\n}\n\n/**\n * Per-phase breakdown for one hot reload, printed only when\n * `devServer.timings` is on. Phases run in this order: the watcher's\n * `awaitWriteFinish` settle wait, this handler's own debounce wait,\n * module-graph invalidation (version bumps), re-import of the changed\n * modules, and connector restart/rebind.\n */\nexport type ReloadPhaseTimings = {\n watcherSettleMs: number;\n debounceWaitMs: number;\n moduleGraphInvalidationMs: number;\n reimportMs: number;\n connectorRestartMs: number;\n};\n\nexport function devLogTimings(timings: ReloadPhaseTimings) {\n const phase = (label: string, ms: number) =>\n `${colors.dim(label)} ${colors.dim(`${Math.round(ms)}ms`)}`;\n const line = [\n phase(\"watcher\", timings.watcherSettleMs),\n phase(\"debounce\", timings.debounceWaitMs),\n phase(\"graph\", timings.moduleGraphInvalidationMs),\n phase(\"reimport\", timings.reimportMs),\n phase(\"connectors\", timings.connectorRestartMs),\n ].join(colors.dim(\" · \"));\n console.log(`${timestamp()} ${colors.dim(\"⏱\")} ${line}`);\n}\n\nexport function devLogConfig(file: string, connectors?: string[]) {\n const relativePath = Path.toRelative(file);\n const connectorInfo =\n connectors && connectors.length > 0 ? colors.dim(` → restarting ${connectors.join(\", \")}`) : \"\";\n console.log(\n `${timestamp()} ${colors.cyan(\"config reload\")} ${colors.dim(relativePath)}${connectorInfo}`,\n );\n}\n\nexport function devLogReady(message: string) {\n console.log(`\\n${timestamp()} ${colors.green(\"➜\")} ${colors.bold(message)}`);\n}\n\nexport function devLogSection(title: string) {\n console.log(`\\n${timestamp()} ${colors.bold(colors.cyan(title))}`);\n}\n\n/**\n * Format ERR_MODULE_NOT_FOUND so the displayed paths are relative to the\n * project root. The loader hook keeps source paths in the URL so we only\n * need to strip the absolute prefix — no cache-path translation any more.\n */\nexport function formatModuleNotFoundError(error: Error, suggestions?: string[]): string {\n const match = error.message.match(/Cannot find module '([^']+)' imported from '([^']+)'/);\n if (!match) return error.message;\n\n // Same rule as the frame formatter above: this renders a MODULE NOT FOUND\n // report, so a missing capture must degrade the message, not replace the\n // user's error with a crash inside the reporter.\n const [, rawModulePath, rawImporterPath] = match;\n const modulePath = rawModulePath ?? \"\";\n const importerPath = rawImporterPath ?? \"\";\n const lines: string[] = [\n \"\",\n `${colors.red(\"❌ MODULE NOT FOUND\")}`,\n \"\",\n `${colors.dim(\"Cannot find:\")} ${colors.cyan(Path.toRelative(modulePath))}`,\n \"\",\n `${colors.dim(\"Imported by:\")}`,\n ` ${colors.yellow(\"→\")} ${colors.white(Path.toRelative(importerPath))}`,\n ];\n\n if (suggestions && suggestions.length > 0) {\n lines.push(\"\");\n lines.push(`${colors.dim(\"Did you mean?\")}`);\n suggestions.forEach((s) => lines.push(` ${colors.cyan(\"→\")} ${colors.green(s)}`));\n }\n\n lines.push(\"\");\n return lines.join(\"\\n\");\n}\n\n/** @deprecated alias retained for older callers. Use `devLog` directly. */\nexport const devServeLog = devLog;\n"],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ import { restartDevServer } from "./restart-dev-server.mjs";
|
|
|
13
13
|
import { devServerShortcuts } from "./shortcuts.mjs";
|
|
14
14
|
import { BootPreconditionError } from "./boot-precondition-error.mjs";
|
|
15
15
|
import { buildDevelopmentOpenApiDocument } from "./build-development-openapi-document.mjs";
|
|
16
|
+
import { DevAgentTooling, resolveDevMcpOptions } from "./dev-agent-tooling.mjs";
|
|
16
17
|
import { LayerExecutor } from "./layer-executor.mjs";
|
|
17
18
|
import { printReadyBlock } from "./ready-block.mjs";
|
|
18
19
|
import { registerInstalledDevtools } from "./register-installed-devtools.mjs";
|
|
@@ -32,6 +33,7 @@ var DevelopmentServer = class {
|
|
|
32
33
|
constructor(options = {}) {
|
|
33
34
|
this.running = false;
|
|
34
35
|
this.connectorsStarted = false;
|
|
36
|
+
this.agentTooling = new DevAgentTooling();
|
|
35
37
|
this.reloadQueue = Promise.resolve();
|
|
36
38
|
this.options = options;
|
|
37
39
|
devLogSection("Starting Development Server...");
|
|
@@ -73,6 +75,10 @@ var DevelopmentServer = class {
|
|
|
73
75
|
const devServerConfig = await warlockConfigManager.get("devServer");
|
|
74
76
|
const generateTypings = this.options.generateTypings ?? devServerConfig?.generateTypings ?? true;
|
|
75
77
|
const healthCheckers = this.options.healthCheckers ?? devServerConfig?.healthCheckers ?? true;
|
|
78
|
+
await this.agentTooling.start({
|
|
79
|
+
agentsMd: devServerConfig?.agentsMd !== false,
|
|
80
|
+
mcp: resolveDevMcpOptions(this.options.mcp, devServerConfig?.mcp)
|
|
81
|
+
});
|
|
76
82
|
if (generateTypings) await typeGenerator.executeGenerateAllCommand();
|
|
77
83
|
if (healthCheckers) filesOrchestrator.startCheckingHealth(healthCheckers === true ? void 0 : healthCheckers);
|
|
78
84
|
} catch (error) {
|
|
@@ -108,6 +114,7 @@ var DevelopmentServer = class {
|
|
|
108
114
|
...batch.changed,
|
|
109
115
|
...batch.deleted
|
|
110
116
|
]);
|
|
117
|
+
this.agentTooling.afterReload();
|
|
111
118
|
filesOrchestrator.checkHealth(batch);
|
|
112
119
|
} catch (error) {
|
|
113
120
|
devServeLog(colors.redBright(`Failed to execute batch reload: ${error}`));
|
|
@@ -144,6 +151,7 @@ var DevelopmentServer = class {
|
|
|
144
151
|
devServeLog(colors.redBright("Shutting down Development Server..."));
|
|
145
152
|
this.running = false;
|
|
146
153
|
this.connectorsStarted = false;
|
|
154
|
+
await this.agentTooling.shutdown();
|
|
147
155
|
await connectorsManager.shutdown();
|
|
148
156
|
devServeLog(colors.greenBright("Development Server stopped"));
|
|
149
157
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"development-server.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/development-server.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport events from \"@mongez/events\";\nimport { fileExistsAsync, unlinkAsync } from \"@warlock.js/fs\";\nimport { Application } from \"../application\";\nimport { connectorsManager } from \"../connectors/connectors-manager\";\nimport { ConnectorLifecyclePhase } from \"../connectors/types\";\nimport { warlockConfigManager } from \"../warlock-config\";\nimport { registerDevelopmentOpenApiProvider } from \"../openapi/development-openapi-provider\";\nimport { BootPreconditionError } from \"./boot-precondition-error\";\nimport { buildDevelopmentOpenApiDocument } from \"./build-development-openapi-document\";\nimport { devLogInfo, devLogSection, devLogWarn, devServeLog } from \"./dev-logger\";\nimport { filesOrchestrator } from \"./files-orchestrator\";\nimport { MANIFEST_PATH } from \"./flags\";\nimport type { IncomingReloadTimings } from \"./layer-executor\";\nimport { LayerExecutor } from \"./layer-executor\";\nimport { printReadyBlock } from \"./ready-block\";\nimport { registerInstalledDevtools } from \"./register-installed-devtools\";\nimport { restartDevServer } from \"./restart-dev-server\";\nimport { collectDevelopmentApiRoutes } from \"./collect-development-api-routes\";\nimport { publishCurrentRouteTypes } from \"./route-types-publisher\";\nimport { devServerShortcuts } from \"./shortcuts\";\nimport type { StartDevServerOptions } from \"./start-development-server\";\nimport { typeGenerator } from \"./type-generator\";\n\ntype Batch = {\n added: string[];\n changed: string[];\n deleted: string[];\n /** Non-code `watch.include` files that changed; only a restart applies them. */\n restartTriggers?: string[];\n timings?: IncomingReloadTimings;\n};\n\n/**\n * Top-level coordinator for `warlock dev`. Wires the file orchestrator, the\n * connectors, and the layer executor together, and listens for the watcher's\n * batched events to drive HMR.\n */\nexport class DevelopmentServer {\n private layerExecutor?: LayerExecutor;\n private running = false;\n\n /** Set once boot begins, so a failed boot still closes connectors that already started. */\n private connectorsStarted = false;\n private readonly options: StartDevServerOptions;\n\n public constructor(options: StartDevServerOptions = {}) {\n this.options = options;\n devLogSection(\"Starting Development Server...\");\n }\n\n public async start(): Promise<void> {\n try {\n this.connectorsStarted = true;\n const startedAt = performance.now();\n\n // Devtools reads this through the root barrel, which must not reach dev-server code.\n registerDevelopmentOpenApiProvider(buildDevelopmentOpenApiDocument);\n\n // --fresh deletes the manifest so reconciliation re-parses every file\n // from disk. Transpile caching is owned by the loader hook (in-memory).\n if (this.options.fresh && (await fileExistsAsync(MANIFEST_PATH))) {\n await unlinkAsync(MANIFEST_PATH);\n devServeLog(colors.cyanBright(\"Cleared manifest (--fresh)\"));\n }\n\n await filesOrchestrator.init();\n await filesOrchestrator.initializeAll();\n await filesOrchestrator.watchFiles();\n\n filesOrchestrator.specialFilesCollector.collect(filesOrchestrator.getFiles());\n\n this.setupEventListeners();\n\n // Decorator-driven registries (models, etc.) must be populated before\n // routes/services can resolve symbols by name.\n await this.autoDiscoverFiles();\n\n await filesOrchestrator.moduleLoader.loadAll();\n\n // A rejecting validator (Application.onValidateBoot) must abort boot\n // before late-phase connectors bind a port — this is what makes the\n // hook actually prevent serving instead of merely being defined.\n //\n // Wrapped and re-thrown as a BootPreconditionError: a rejected\n // validator is, by definition, a precondition whose cause cannot\n // change because the worker tried again — the supervisor must not\n // restart into the same rejection. See boot-precondition-error.ts.\n try {\n await Application.runStartupValidators();\n } catch (error) {\n throw new BootPreconditionError((error as Error).message, { cause: error });\n }\n\n // `@warlock.js/devtools` is a dev dependency the config never names;\n // when installed it joins the late phase here, and only here.\n await registerInstalledDevtools();\n\n // Late-phase connectors (http, socket) bind after app code has\n // registered routes/listeners.\n await connectorsManager.startPhase(ConnectorLifecyclePhase.Late);\n\n // Web installs its page table from its late connector. Generate only\n // after that installation so `href()` and the declaration table agree.\n await publishCurrentRouteTypes(process.cwd(), await collectDevelopmentApiRoutes());\n\n this.layerExecutor = new LayerExecutor(\n filesOrchestrator.getDependencyGraph(),\n filesOrchestrator.specialFilesCollector,\n filesOrchestrator.moduleLoader,\n (absolutePath) => filesOrchestrator.bumpVersion(absolutePath),\n () => filesOrchestrator.flushVersionBumps(),\n );\n\n this.running = true;\n\n const duration = performance.now() - startedAt;\n\n // App modules are loaded and both connector phases are active — signal a\n // complete boot so `Application.onceBooted(...)` listeners fire.\n Application.markBooted({\n environment: Application.environment,\n runtimeStrategy: Application.runtimeStrategy,\n bootDurationMs: duration,\n });\n\n // ONE block, AFTER the boot it summarises, replacing the scattered\n // \"N route(s) registered\" / \"Server ready at …\" / \"ready in …\" lines that\n // used to arrive in completion order. Warnings logged during boot sit\n // above it and stay there — see `ready-block.ts`.\n printReadyBlock(duration);\n\n // Tell the supervisor (when there is one) that boot completed, so its\n // healthy-uptime window counts from here rather than from spawn.\n process.send?.(\"warlock:booted\");\n\n // Precedence: explicit CLI option > devServer.* config > default.\n const devServerConfig = await warlockConfigManager.get(\"devServer\");\n const generateTypings =\n this.options.generateTypings ?? devServerConfig?.generateTypings ?? true;\n const healthCheckers = this.options.healthCheckers ?? devServerConfig?.healthCheckers ?? true;\n\n if (generateTypings) await typeGenerator.executeGenerateAllCommand();\n\n if (healthCheckers) {\n filesOrchestrator.startCheckingHealth(healthCheckers === true ? undefined : healthCheckers);\n }\n } catch (error) {\n devServeLog(colors.redBright(`Failed to start Development Server: ${error}`));\n await this.shutdown();\n throw error;\n }\n }\n\n /**\n * Eagerly import files whose decorators populate global registries so any\n * symbol-by-name resolution later in boot finds them.\n */\n private async autoDiscoverFiles(): Promise<void> {\n const discoveryTypes = [\"model\"] as const;\n for (const file of filesOrchestrator.files.values()) {\n if (file.type && (discoveryTypes as readonly string[]).includes(file.type)) {\n await filesOrchestrator.moduleLoader.loadModule(file, file.type);\n }\n }\n }\n\n /** Tail of the batch-reload chain (see `setupEventListeners`). */\n private reloadQueue: Promise<void> = Promise.resolve();\n\n private setupEventListeners(): void {\n // Reloads run one at a time: a second batch waits for the first to finish\n // so route re-registration and connector restarts never interleave.\n events.on(\"dev-server:batch-complete\", (batch: Batch) => {\n this.reloadQueue = this.reloadQueue\n .then(() => this.handleBatchComplete(batch))\n .catch((error) => devServeLog(colors.redBright(`Batch reload failed: ${error}`)));\n });\n }\n\n private async handleBatchComplete(batch: Batch): Promise<void> {\n if (!this.running || !this.layerExecutor) return;\n\n // warlock.config.ts holds settings read at boot (CLI commands, build\n // options, watch patterns, scheduled jobs) and .env feeds every config\n // that reads it. Neither can be hot-reloaded without leaving running\n // services configured with stale values, so the only honest response is\n // a full restart.\n const restartTrigger = this.findRestartTrigger(batch);\n\n if (restartTrigger) {\n // On success this never comes back — the process exits and the\n // supervisor replaces it. Reaching the next line means the restart was\n // declined by config or wasn't possible, so we fall through and still\n // hot-reload whatever ordinary code shared the batch.\n await this.restartForConfigChange(restartTrigger);\n }\n\n // No-op saves (an editor that fsyncs without a content write) are already\n // filtered upstream by the file hash in FileEventHandler, so batch.changed\n // only contains genuinely-changed paths by the time it reaches here.\n\n const total = batch.added.length + batch.changed.length + batch.deleted.length;\n if (total === 0) return;\n\n // Boot-time files still ride along in `changed` when a restart was\n // declined (`restartOnConfigChange: false`) or wasn't possible — they are\n // never hot-reloaded, so keep them out of the reload set either way.\n const codeFiles = [...batch.added, ...batch.changed].filter(\n (p) => !isEnvPath(p) && p !== \"warlock.config.ts\" && !batch.restartTriggers?.includes(p),\n );\n\n try {\n await this.layerExecutor.executeBatchReload(\n codeFiles,\n filesOrchestrator.getFiles(),\n batch.deleted,\n batch.changed,\n batch.timings,\n );\n\n // `executeBatchReload` includes route re-imports and affected connector\n // restarts. Publishing earlier could freeze a partial page/API view.\n // This also refreshes deletion-only batches after their cleanup/restart.\n await publishCurrentRouteTypes(process.cwd(), await collectDevelopmentApiRoutes());\n\n typeGenerator.executeTypingsGenerator([...batch.added, ...batch.changed, ...batch.deleted]);\n\n filesOrchestrator.checkHealth(batch);\n } catch (error) {\n devServeLog(colors.redBright(`Failed to execute batch reload: ${error}`));\n }\n }\n\n /**\n * The boot-time file in this batch that can only be applied by restarting,\n * or `undefined` when the batch is ordinary application code.\n */\n private findRestartTrigger(batch: Batch): string | undefined {\n if (batch.changed.includes(\"warlock.config.ts\")) {\n return \"warlock.config.ts\";\n }\n\n return [...batch.added, ...batch.changed].find(isEnvPath) ?? batch.restartTriggers?.[0];\n }\n\n /**\n * Restart so a changed boot-time file actually takes effect.\n *\n * Opt out with `devServer.restartOnConfigChange: false` and the old\n * behaviour returns: a warning telling you to restart yourself. If the\n * restart can't be performed at all (no supervisor, a shutdown that threw),\n * `restartDevServer` reports it and we fall back to the same warning rather\n * than leaving the server running against config it isn't using.\n */\n private async restartForConfigChange(file: string): Promise<void> {\n const devServerConfig = await warlockConfigManager.get(\"devServer\");\n\n if (devServerConfig?.restartOnConfigChange === false) {\n devLogWarn(`${file} changed — restart the dev server to apply.`);\n return;\n }\n\n devLogInfo(`${file} changed — restarting to apply.`);\n\n const restarted = await restartDevServer(this);\n\n if (!restarted) {\n devLogWarn(`${file} changed — restart the dev server to apply.`);\n }\n }\n\n public async shutdown(): Promise<void> {\n // Always hand the terminal back, even on a repeat/no-op shutdown — a\n // process that exits while stdin is still in raw mode leaves the user's\n // shell without line editing or Ctrl+C.\n devServerShortcuts.release();\n\n if (!this.running && !this.connectorsStarted) return;\n devServeLog(colors.redBright(\"Shutting down Development Server...\"));\n this.running = false;\n this.connectorsStarted = false;\n await connectorsManager.shutdown();\n devServeLog(colors.greenBright(\"Development Server stopped\"));\n }\n\n public isRunning(): boolean {\n return this.running;\n }\n}\n\nfunction isEnvPath(path: string): boolean {\n const basename = path.split(\"/\").pop() ?? path;\n return basename === \".env\" || basename.startsWith(\".env.\");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,IAAa,oBAAb,MAA+B;CAQ7B,AAAO,YAAY,UAAiC,CAAC,GAAG;iBANtC;2BAGU;qBA6HS,QAAQ,QAAQ;EAzHnD,KAAK,UAAU;EACf,cAAc,gCAAgC;CAChD;CAEA,MAAa,QAAuB;EAClC,IAAI;GACF,KAAK,oBAAoB;GACzB,MAAM,YAAY,YAAY,IAAI;GAGlC,mCAAmC,+BAA+B;GAIlE,IAAI,KAAK,QAAQ,SAAU,MAAM,gBAAgB,aAAa,GAAI;IAChE,MAAM,YAAY,aAAa;IAC/B,YAAY,OAAO,WAAW,4BAA4B,CAAC;GAC7D;GAEA,MAAM,kBAAkB,KAAK;GAC7B,MAAM,kBAAkB,cAAc;GACtC,MAAM,kBAAkB,WAAW;GAEnC,kBAAkB,sBAAsB,QAAQ,kBAAkB,SAAS,CAAC;GAE5E,KAAK,oBAAoB;GAIzB,MAAM,KAAK,kBAAkB;GAE7B,MAAM,kBAAkB,aAAa,QAAQ;GAU7C,IAAI;IACF,MAAM,YAAY,qBAAqB;GACzC,SAAS,OAAO;IACd,MAAM,IAAI,sBAAuB,MAAgB,SAAS,EAAE,OAAO,MAAM,CAAC;GAC5E;GAIA,MAAM,0BAA0B;GAIhC,MAAM,kBAAkB,iBAAuC;GAI/D,MAAM,yBAAyB,QAAQ,IAAI,GAAG,MAAM,4BAA4B,CAAC;GAEjF,KAAK,gBAAgB,IAAI,cACvB,kBAAkB,mBAAmB,GACrC,kBAAkB,uBAClB,kBAAkB,eACjB,iBAAiB,kBAAkB,YAAY,YAAY,SACtD,kBAAkB,kBAAkB,CAC5C;GAEA,KAAK,UAAU;GAEf,MAAM,WAAW,YAAY,IAAI,IAAI;GAIrC,YAAY,WAAW;IACrB,aAAa,YAAY;IACzB,iBAAiB,YAAY;IAC7B,gBAAgB;GAClB,CAAC;GAMD,gBAAgB,QAAQ;GAIxB,QAAQ,OAAO,gBAAgB;GAG/B,MAAM,kBAAkB,MAAM,qBAAqB,IAAI,WAAW;GAClE,MAAM,kBACJ,KAAK,QAAQ,mBAAmB,iBAAiB,mBAAmB;GACtE,MAAM,iBAAiB,KAAK,QAAQ,kBAAkB,iBAAiB,kBAAkB;GAEzF,IAAI,iBAAiB,MAAM,cAAc,0BAA0B;GAEnE,IAAI,gBACF,kBAAkB,oBAAoB,mBAAmB,OAAO,SAAY,cAAc;EAE9F,SAAS,OAAO;GACd,YAAY,OAAO,UAAU,uCAAuC,OAAO,CAAC;GAC5E,MAAM,KAAK,SAAS;GACpB,MAAM;EACR;CACF;;;;;CAMA,MAAc,oBAAmC;EAC/C,MAAM,iBAAiB,CAAC,OAAO;EAC/B,KAAK,MAAM,QAAQ,kBAAkB,MAAM,OAAO,GAChD,IAAI,KAAK,QAAS,eAAqC,SAAS,KAAK,IAAI,GACvE,MAAM,kBAAkB,aAAa,WAAW,MAAM,KAAK,IAAI;CAGrE;CAKA,AAAQ,sBAA4B;EAGlC,OAAO,GAAG,8BAA8B,UAAiB;GACvD,KAAK,cAAc,KAAK,YACrB,WAAW,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAC3C,OAAO,UAAU,YAAY,OAAO,UAAU,wBAAwB,OAAO,CAAC,CAAC;EACpF,CAAC;CACH;CAEA,MAAc,oBAAoB,OAA6B;EAC7D,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,eAAe;EAO1C,MAAM,iBAAiB,KAAK,mBAAmB,KAAK;EAEpD,IAAI,gBAKF,MAAM,KAAK,uBAAuB,cAAc;EAQlD,IADc,MAAM,MAAM,SAAS,MAAM,QAAQ,SAAS,MAAM,QAAQ,WAC1D,GAAG;EAKjB,MAAM,YAAY,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,CAAC,QAClD,MAAM,CAAC,UAAU,CAAC,KAAK,MAAM,uBAAuB,CAAC,MAAM,iBAAiB,SAAS,CAAC,CACzF;EAEA,IAAI;GACF,MAAM,KAAK,cAAc,mBACvB,WACA,kBAAkB,SAAS,GAC3B,MAAM,SACN,MAAM,SACN,MAAM,OACR;GAKA,MAAM,yBAAyB,QAAQ,IAAI,GAAG,MAAM,4BAA4B,CAAC;GAEjF,cAAc,wBAAwB;IAAC,GAAG,MAAM;IAAO,GAAG,MAAM;IAAS,GAAG,MAAM;GAAO,CAAC;GAE1F,kBAAkB,YAAY,KAAK;EACrC,SAAS,OAAO;GACd,YAAY,OAAO,UAAU,mCAAmC,OAAO,CAAC;EAC1E;CACF;;;;;CAMA,AAAQ,mBAAmB,OAAkC;EAC3D,IAAI,MAAM,QAAQ,SAAS,mBAAmB,GAC5C,OAAO;EAGT,OAAO,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,CAAC,KAAK,SAAS,KAAK,MAAM,kBAAkB;CACvF;;;;;;;;;;CAWA,MAAc,uBAAuB,MAA6B;EAGhE,KAAI,MAF0B,qBAAqB,IAAI,WAAW,EAE/C,EAAE,0BAA0B,OAAO;GACpD,WAAW,GAAG,KAAK,4CAA4C;GAC/D;EACF;EAEA,WAAW,GAAG,KAAK,gCAAgC;EAInD,IAAI,CAAC,MAFmB,iBAAiB,IAAI,GAG3C,WAAW,GAAG,KAAK,4CAA4C;CAEnE;CAEA,MAAa,WAA0B;EAIrC,mBAAmB,QAAQ;EAE3B,IAAI,CAAC,KAAK,WAAW,CAAC,KAAK,mBAAmB;EAC9C,YAAY,OAAO,UAAU,qCAAqC,CAAC;EACnE,KAAK,UAAU;EACf,KAAK,oBAAoB;EACzB,MAAM,kBAAkB,SAAS;EACjC,YAAY,OAAO,YAAY,4BAA4B,CAAC;CAC9D;CAEA,AAAO,YAAqB;EAC1B,OAAO,KAAK;CACd;AACF;AAEA,SAAS,UAAU,MAAuB;CACxC,MAAM,WAAW,KAAK,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK;CAC1C,OAAO,aAAa,UAAU,SAAS,WAAW,OAAO;AAC3D"}
|
|
1
|
+
{"version":3,"file":"development-server.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/development-server.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport events from \"@mongez/events\";\nimport { fileExistsAsync, unlinkAsync } from \"@warlock.js/fs\";\nimport { Application } from \"../application\";\nimport { connectorsManager } from \"../connectors/connectors-manager\";\nimport { ConnectorLifecyclePhase } from \"../connectors/types\";\nimport { warlockConfigManager } from \"../warlock-config\";\nimport { registerDevelopmentOpenApiProvider } from \"../openapi/development-openapi-provider\";\nimport { BootPreconditionError } from \"./boot-precondition-error\";\nimport { buildDevelopmentOpenApiDocument } from \"./build-development-openapi-document\";\nimport { DevAgentTooling, resolveDevMcpOptions } from \"./dev-agent-tooling\";\nimport { devLogInfo, devLogSection, devLogWarn, devServeLog } from \"./dev-logger\";\nimport { filesOrchestrator } from \"./files-orchestrator\";\nimport { MANIFEST_PATH } from \"./flags\";\nimport type { IncomingReloadTimings } from \"./layer-executor\";\nimport { LayerExecutor } from \"./layer-executor\";\nimport { printReadyBlock } from \"./ready-block\";\nimport { registerInstalledDevtools } from \"./register-installed-devtools\";\nimport { restartDevServer } from \"./restart-dev-server\";\nimport { collectDevelopmentApiRoutes } from \"./collect-development-api-routes\";\nimport { publishCurrentRouteTypes } from \"./route-types-publisher\";\nimport { devServerShortcuts } from \"./shortcuts\";\nimport type { StartDevServerOptions } from \"./start-development-server\";\nimport { typeGenerator } from \"./type-generator\";\n\ntype Batch = {\n added: string[];\n changed: string[];\n deleted: string[];\n /** Non-code `watch.include` files that changed; only a restart applies them. */\n restartTriggers?: string[];\n timings?: IncomingReloadTimings;\n};\n\n/**\n * Top-level coordinator for `warlock dev`. Wires the file orchestrator, the\n * connectors, and the layer executor together, and listens for the watcher's\n * batched events to drive HMR.\n */\nexport class DevelopmentServer {\n private layerExecutor?: LayerExecutor;\n private running = false;\n\n /** Set once boot begins, so a failed boot still closes connectors that already started. */\n private connectorsStarted = false;\n private readonly options: StartDevServerOptions;\n\n /** `.warlock/dev-server.json`, the AGENTS.md refresher and `--mcp`. */\n private readonly agentTooling = new DevAgentTooling();\n\n public constructor(options: StartDevServerOptions = {}) {\n this.options = options;\n devLogSection(\"Starting Development Server...\");\n }\n\n public async start(): Promise<void> {\n try {\n this.connectorsStarted = true;\n const startedAt = performance.now();\n\n // Devtools reads this through the root barrel, which must not reach dev-server code.\n registerDevelopmentOpenApiProvider(buildDevelopmentOpenApiDocument);\n\n // --fresh deletes the manifest so reconciliation re-parses every file\n // from disk. Transpile caching is owned by the loader hook (in-memory).\n if (this.options.fresh && (await fileExistsAsync(MANIFEST_PATH))) {\n await unlinkAsync(MANIFEST_PATH);\n devServeLog(colors.cyanBright(\"Cleared manifest (--fresh)\"));\n }\n\n await filesOrchestrator.init();\n await filesOrchestrator.initializeAll();\n await filesOrchestrator.watchFiles();\n\n filesOrchestrator.specialFilesCollector.collect(filesOrchestrator.getFiles());\n\n this.setupEventListeners();\n\n // Decorator-driven registries (models, etc.) must be populated before\n // routes/services can resolve symbols by name.\n await this.autoDiscoverFiles();\n\n await filesOrchestrator.moduleLoader.loadAll();\n\n // A rejecting validator (Application.onValidateBoot) must abort boot\n // before late-phase connectors bind a port — this is what makes the\n // hook actually prevent serving instead of merely being defined.\n //\n // Wrapped and re-thrown as a BootPreconditionError: a rejected\n // validator is, by definition, a precondition whose cause cannot\n // change because the worker tried again — the supervisor must not\n // restart into the same rejection. See boot-precondition-error.ts.\n try {\n await Application.runStartupValidators();\n } catch (error) {\n throw new BootPreconditionError((error as Error).message, { cause: error });\n }\n\n // `@warlock.js/devtools` is a dev dependency the config never names;\n // when installed it joins the late phase here, and only here.\n await registerInstalledDevtools();\n\n // Late-phase connectors (http, socket) bind after app code has\n // registered routes/listeners.\n await connectorsManager.startPhase(ConnectorLifecyclePhase.Late);\n\n // Web installs its page table from its late connector. Generate only\n // after that installation so `href()` and the declaration table agree.\n await publishCurrentRouteTypes(process.cwd(), await collectDevelopmentApiRoutes());\n\n this.layerExecutor = new LayerExecutor(\n filesOrchestrator.getDependencyGraph(),\n filesOrchestrator.specialFilesCollector,\n filesOrchestrator.moduleLoader,\n (absolutePath) => filesOrchestrator.bumpVersion(absolutePath),\n () => filesOrchestrator.flushVersionBumps(),\n );\n\n this.running = true;\n\n const duration = performance.now() - startedAt;\n\n // App modules are loaded and both connector phases are active — signal a\n // complete boot so `Application.onceBooted(...)` listeners fire.\n Application.markBooted({\n environment: Application.environment,\n runtimeStrategy: Application.runtimeStrategy,\n bootDurationMs: duration,\n });\n\n // ONE block, AFTER the boot it summarises, replacing the scattered\n // \"N route(s) registered\" / \"Server ready at …\" / \"ready in …\" lines that\n // used to arrive in completion order. Warnings logged during boot sit\n // above it and stay there — see `ready-block.ts`.\n printReadyBlock(duration);\n\n // Tell the supervisor (when there is one) that boot completed, so its\n // healthy-uptime window counts from here rather than from spawn.\n process.send?.(\"warlock:booted\");\n\n // Precedence: explicit CLI option > devServer.* config > default.\n const devServerConfig = await warlockConfigManager.get(\"devServer\");\n const generateTypings =\n this.options.generateTypings ?? devServerConfig?.generateTypings ?? true;\n const healthCheckers = this.options.healthCheckers ?? devServerConfig?.healthCheckers ?? true;\n\n await this.agentTooling.start({\n agentsMd: devServerConfig?.agentsMd !== false,\n mcp: resolveDevMcpOptions(this.options.mcp, devServerConfig?.mcp),\n });\n\n if (generateTypings) await typeGenerator.executeGenerateAllCommand();\n\n if (healthCheckers) {\n filesOrchestrator.startCheckingHealth(healthCheckers === true ? undefined : healthCheckers);\n }\n } catch (error) {\n devServeLog(colors.redBright(`Failed to start Development Server: ${error}`));\n await this.shutdown();\n throw error;\n }\n }\n\n /**\n * Eagerly import files whose decorators populate global registries so any\n * symbol-by-name resolution later in boot finds them.\n */\n private async autoDiscoverFiles(): Promise<void> {\n const discoveryTypes = [\"model\"] as const;\n for (const file of filesOrchestrator.files.values()) {\n if (file.type && (discoveryTypes as readonly string[]).includes(file.type)) {\n await filesOrchestrator.moduleLoader.loadModule(file, file.type);\n }\n }\n }\n\n /** Tail of the batch-reload chain (see `setupEventListeners`). */\n private reloadQueue: Promise<void> = Promise.resolve();\n\n private setupEventListeners(): void {\n // Reloads run one at a time: a second batch waits for the first to finish\n // so route re-registration and connector restarts never interleave.\n events.on(\"dev-server:batch-complete\", (batch: Batch) => {\n this.reloadQueue = this.reloadQueue\n .then(() => this.handleBatchComplete(batch))\n .catch((error) => devServeLog(colors.redBright(`Batch reload failed: ${error}`)));\n });\n }\n\n private async handleBatchComplete(batch: Batch): Promise<void> {\n if (!this.running || !this.layerExecutor) return;\n\n // warlock.config.ts holds settings read at boot (CLI commands, build\n // options, watch patterns, scheduled jobs) and .env feeds every config\n // that reads it. Neither can be hot-reloaded without leaving running\n // services configured with stale values, so the only honest response is\n // a full restart.\n const restartTrigger = this.findRestartTrigger(batch);\n\n if (restartTrigger) {\n // On success this never comes back — the process exits and the\n // supervisor replaces it. Reaching the next line means the restart was\n // declined by config or wasn't possible, so we fall through and still\n // hot-reload whatever ordinary code shared the batch.\n await this.restartForConfigChange(restartTrigger);\n }\n\n // No-op saves (an editor that fsyncs without a content write) are already\n // filtered upstream by the file hash in FileEventHandler, so batch.changed\n // only contains genuinely-changed paths by the time it reaches here.\n\n const total = batch.added.length + batch.changed.length + batch.deleted.length;\n if (total === 0) return;\n\n // Boot-time files still ride along in `changed` when a restart was\n // declined (`restartOnConfigChange: false`) or wasn't possible — they are\n // never hot-reloaded, so keep them out of the reload set either way.\n const codeFiles = [...batch.added, ...batch.changed].filter(\n (p) => !isEnvPath(p) && p !== \"warlock.config.ts\" && !batch.restartTriggers?.includes(p),\n );\n\n try {\n await this.layerExecutor.executeBatchReload(\n codeFiles,\n filesOrchestrator.getFiles(),\n batch.deleted,\n batch.changed,\n batch.timings,\n );\n\n // `executeBatchReload` includes route re-imports and affected connector\n // restarts. Publishing earlier could freeze a partial page/API view.\n // This also refreshes deletion-only batches after their cleanup/restart.\n await publishCurrentRouteTypes(process.cwd(), await collectDevelopmentApiRoutes());\n\n typeGenerator.executeTypingsGenerator([...batch.added, ...batch.changed, ...batch.deleted]);\n\n this.agentTooling.afterReload();\n\n filesOrchestrator.checkHealth(batch);\n } catch (error) {\n devServeLog(colors.redBright(`Failed to execute batch reload: ${error}`));\n }\n }\n\n /**\n * The boot-time file in this batch that can only be applied by restarting,\n * or `undefined` when the batch is ordinary application code.\n */\n private findRestartTrigger(batch: Batch): string | undefined {\n if (batch.changed.includes(\"warlock.config.ts\")) {\n return \"warlock.config.ts\";\n }\n\n return [...batch.added, ...batch.changed].find(isEnvPath) ?? batch.restartTriggers?.[0];\n }\n\n /**\n * Restart so a changed boot-time file actually takes effect.\n *\n * Opt out with `devServer.restartOnConfigChange: false` and the old\n * behaviour returns: a warning telling you to restart yourself. If the\n * restart can't be performed at all (no supervisor, a shutdown that threw),\n * `restartDevServer` reports it and we fall back to the same warning rather\n * than leaving the server running against config it isn't using.\n */\n private async restartForConfigChange(file: string): Promise<void> {\n const devServerConfig = await warlockConfigManager.get(\"devServer\");\n\n if (devServerConfig?.restartOnConfigChange === false) {\n devLogWarn(`${file} changed — restart the dev server to apply.`);\n return;\n }\n\n devLogInfo(`${file} changed — restarting to apply.`);\n\n const restarted = await restartDevServer(this);\n\n if (!restarted) {\n devLogWarn(`${file} changed — restart the dev server to apply.`);\n }\n }\n\n public async shutdown(): Promise<void> {\n // Always hand the terminal back, even on a repeat/no-op shutdown — a\n // process that exits while stdin is still in raw mode leaves the user's\n // shell without line editing or Ctrl+C.\n devServerShortcuts.release();\n\n if (!this.running && !this.connectorsStarted) return;\n devServeLog(colors.redBright(\"Shutting down Development Server...\"));\n this.running = false;\n this.connectorsStarted = false;\n await this.agentTooling.shutdown();\n await connectorsManager.shutdown();\n devServeLog(colors.greenBright(\"Development Server stopped\"));\n }\n\n public isRunning(): boolean {\n return this.running;\n }\n}\n\nfunction isEnvPath(path: string): boolean {\n const basename = path.split(\"/\").pop() ?? path;\n return basename === \".env\" || basename.startsWith(\".env.\");\n}\n"],"mappings":"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"}
|
|
@@ -10,8 +10,7 @@ import { FileManager } from "./file-manager.mjs";
|
|
|
10
10
|
import { ensureWarlockDirectory, getFilesFromDirectory } from "./utils.mjs";
|
|
11
11
|
import { FileOperations } from "./file-operations.mjs";
|
|
12
12
|
import { FilesWatcher, createIgnoredMatcher } from "./files-watcher.mjs";
|
|
13
|
-
import {
|
|
14
|
-
import { TypescriptHealthChecker } from "./health-checker/checkers/typescript-health-checker.mjs";
|
|
13
|
+
import { defaultHealthCheckers } from "./health-checker/default-health-checkers.mjs";
|
|
15
14
|
import { FilesHealthcareManager } from "./health-checker/files-healthcare.manager.mjs";
|
|
16
15
|
import { buildTranspileInit } from "./loader/build-transpile-init.mjs";
|
|
17
16
|
import { trackLoaderPortAcks } from "./loader/loader-port-acks.mjs";
|
|
@@ -20,8 +19,8 @@ import { ManifestManager } from "./manifest-manager.mjs";
|
|
|
20
19
|
import { ModuleLoader } from "./module-loader.mjs";
|
|
21
20
|
import { packageJsonManager } from "./package-json-manager.mjs";
|
|
22
21
|
import { SpecialFilesCollector } from "./special-files-collector.mjs";
|
|
23
|
-
import { colors } from "@mongez/copper";
|
|
24
22
|
import { fileURLToPath } from "node:url";
|
|
23
|
+
import { colors } from "@mongez/copper";
|
|
25
24
|
import { init } from "es-module-lexer";
|
|
26
25
|
|
|
27
26
|
//#region ../../packages/core/src/dev-server/files-orchestrator.ts
|
|
@@ -152,7 +151,7 @@ var FilesOrchestrator = class {
|
|
|
152
151
|
}
|
|
153
152
|
async startCheckingHealth(healthCheckers) {
|
|
154
153
|
devLogDim("Started File Health Checks in the background.");
|
|
155
|
-
const checkers = healthCheckers
|
|
154
|
+
const checkers = Array.isArray(healthCheckers) ? healthCheckers : defaultHealthCheckers(healthCheckers);
|
|
156
155
|
await this.healthCheckerManager.setHealthCheckers(checkers).initialize();
|
|
157
156
|
await this.healthCheckerManager.validateAllFiles();
|
|
158
157
|
}
|
|
@@ -162,7 +161,7 @@ var FilesOrchestrator = class {
|
|
|
162
161
|
*
|
|
163
162
|
* The JSON dictionaries must be in the boot set: the module loader
|
|
164
163
|
* registers them like any other locale file, but a code-only glob left them
|
|
165
|
-
* out, so `t()` printed raw keys until the watcher reported an edit
|
|
164
|
+
* out, so `t()` printed raw keys until the watcher reported an edit.
|
|
166
165
|
*/
|
|
167
166
|
async getAllFilesFromFilesystem() {
|
|
168
167
|
const [codePaths, localePaths] = await Promise.all([getFilesFromDirectory(), getFilesFromDirectory(void 0, MODULE_LOCALES_JSON_GLOB)]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files-orchestrator.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/files-orchestrator.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { init } from \"es-module-lexer\";\nimport { fileURLToPath } from \"node:url\";\nimport type { MessagePort } from \"node:worker_threads\";\nimport { warlockConfigManager } from \"../warlock-config/warlock-config.manager\";\nimport { getDevelopmentAppModuleRegistry } from \"./app-module-registry\";\nimport { DependencyGraph } from \"./dependency-graph\";\nimport { devLogDim, devLogSuccess } from \"./dev-logger\";\nimport { FileEventHandler } from \"./file-event-handler\";\nimport { FileManager } from \"./file-manager\";\nimport { FileOperations } from \"./file-operations\";\nimport { FilesWatcher, createIgnoredMatcher } from \"./files-watcher\";\nimport { FILE_PROCESSING_BATCH_SIZE } from \"./flags\";\nimport { EslintHealthChecker } from \"./health-checker/checkers/eslint-health-checker\";\nimport { TypescriptHealthChecker } from \"./health-checker/checkers/typescript-health-checker\";\nimport type { FileHealthCheckerContract } from \"./health-checker/file-health-checker.contract\";\nimport { FilesHealthcareManager } from \"./health-checker/files-healthcare.manager\";\nimport { buildTranspileInit } from \"./loader/build-transpile-init.js\";\nimport { trackLoaderPortAcks, type LoaderPortAcks } from \"./loader/loader-port-acks\";\nimport { registerLoader } from \"./loader/register-loader.js\";\nimport { ManifestManager } from \"./manifest-manager\";\nimport { ModuleLoader } from \"./module-loader\";\nimport { packageJsonManager } from \"./package-json-manager\";\nimport { Path } from \"../utils/normalized-path\";\nimport { SpecialFilesCollector } from \"./special-files-collector\";\nimport { tsconfigManager } from \"./tsconfig-manager\";\nimport { ensureWarlockDirectory, getFilesFromDirectory } from \"./utils\";\n\n/** Module dictionaries, relative to `src/`; matches what `isLocaleFile` accepts as JSON. */\nexport const MODULE_LOCALES_JSON_GLOB = \"app/*/utils/locales.json\";\n\n/**\n * Register a cleanup callback that fires before the current module is\n * unloaded by HMR. Stack-inspects the caller so user code doesn't need to\n * thread the FileManager through.\n */\nexport function onCleanup(callback: () => any) {\n if (globalThis.__currentModuleFile) {\n globalThis.__currentModuleFile.addCleanup(callback);\n return;\n }\n\n const stack = new Error().stack;\n const callerLine = stack?.split(\"\\n\")[2];\n const match = callerLine?.match(/\\((.+?):\\d+:\\d+\\)/) || callerLine?.match(/at (.+?):\\d+:\\d+/);\n const rawCaller = match?.[1];\n\n // Loaded modules report `file:///…?v=N`; turn that back into a plain path.\n const callerFile = rawCaller?.startsWith(\"file://\")\n ? fileURLToPath(rawCaller.replace(/\\?.*$/, \"\"))\n : rawCaller;\n\n if (!callerFile) return;\n const fileManager = filesOrchestrator.files.get(Path.toRelative(callerFile));\n fileManager?.addCleanup(callback);\n}\n\n/**\n * Top-level coordinator for the dev server's file system.\n *\n * Owns: file discovery, the dependency graph, the manifest, the special-files\n * index, the file watcher, and the lifecycle of the ESM loader hook (which\n * provides cache-busting via `?v=N` version tokens).\n */\nexport class FilesOrchestrator {\n public readonly filesWatcher = new FilesWatcher();\n public readonly files = new Map<string, FileManager>();\n private readonly manifest = new ManifestManager(this.files);\n private readonly dependencyGraph = new DependencyGraph();\n private readonly healthCheckerManager = new FilesHealthcareManager(this.files);\n public readonly specialFilesCollector = new SpecialFilesCollector();\n public readonly moduleLoader = new ModuleLoader(this.specialFilesCollector);\n public readonly fileOperations: FileOperations;\n private readonly eventHandler: FileEventHandler;\n\n /** Main-thread end of the MessageChannel to the loader hook worker. */\n private loaderPort: MessagePort | null = null;\n\n /** `sync`/`sync-ack` round trips on {@link loaderPort}; never holds the process open. */\n private loaderAcks: LoaderPortAcks | null = null;\n\n /**\n * Files bumped since the last `flushVersionBumps()`. They are published to\n * the development app-module carrier only once the hook thread acknowledged\n * the bump, so a subscriber that imports the published URL cannot get the\n * previous instance.\n */\n private pendingBumpedPaths: string[] = [];\n\n public isInitialized = false;\n\n public constructor() {\n // Web creates its Vite bridge after this orchestrator exists; create the\n // carrier now so it can subscribe before the first bump happens.\n getDevelopmentAppModuleRegistry();\n\n this.fileOperations = new FileOperations(\n this.files,\n this.dependencyGraph,\n this.manifest,\n this.specialFilesCollector,\n );\n\n this.eventHandler = new FileEventHandler(\n this.fileOperations,\n this.manifest,\n this.dependencyGraph,\n this.files,\n );\n }\n\n public async add(relativePath: string): Promise<FileManager> {\n return this.fileOperations.addFile(relativePath);\n }\n\n public async load<T>(relativePath: string, type = \"other\") {\n // Guarantee the ESM loader hook is registered before we import anything.\n // `load()` is the dynamic-import entrypoint, so it is the one place that\n // must satisfy `init()`'s documented precondition (\"Must be called before\n // any user src/ module is dynamically imported\") on its own — it cannot\n // assume a caller ran `init()` first.\n //\n // The CLI command-resolution path proves why: `cliCommandsLoader.load()`\n // imports a project command module during command *lookup* (before the\n // command's own `execute()` runs), whereas `loadPreloaders()` only calls\n // `init()` from *inside* `execute()`. So a `warlock <command>` whose\n // command file imports an `app/*` alias or a `.ts` sibling was imported\n // with no hook registered and died on `ERR_MODULE_NOT_FOUND` (f9d8f99f).\n //\n // `init()` is idempotent (guarded by `isInitialized`), so this is a no-op\n // on the dev-server path, which already calls it explicitly at startup.\n await this.init();\n\n const fileManager = await this.add(relativePath);\n return this.moduleLoader.loadModule<T>(fileManager, fileManager.type || type);\n }\n\n public getDependencyGraph(): DependencyGraph {\n return this.dependencyGraph;\n }\n\n public getInvalidationChain(file: string): string[] {\n return this.dependencyGraph.getInvalidationChain(file);\n }\n\n public getFiles(): Map<string, FileManager> {\n return this.files;\n }\n\n public getHealthCheckerManager(): FilesHealthcareManager {\n return this.healthCheckerManager;\n }\n\n /**\n * Initialise managers and register the ESM loader hook. Must be called\n * before any user `src/` module is dynamically imported.\n */\n public async init() {\n if (this.isInitialized) return;\n this.isInitialized = true;\n\n await init;\n await Promise.all([tsconfigManager.init(), packageJsonManager.init()]);\n\n // The loader hook writes itself into .warlock/, so ensure the dir exists.\n await ensureWarlockDirectory();\n\n const devServerConfig = await warlockConfigManager.lazyGet(\"devServer\");\n const transpileInit = buildTranspileInit(\n tsconfigManager.tsconfig?.compilerOptions,\n devServerConfig?.transpileCacheDebug === true,\n );\n\n this.loaderPort = await registerLoader(transpileInit);\n this.loaderAcks = trackLoaderPortAcks(this.loaderPort);\n }\n\n /**\n * Tell the hook worker a file changed. The next `import()` of it will get\n * a fresh `?v=N` URL → Node cache miss → fresh content.\n */\n public bumpVersion(absolutePath: string): void {\n if (!this.loaderPort) return;\n\n this.loaderPort.postMessage({ type: \"bump\", absolutePath });\n this.pendingBumpedPaths.push(absolutePath);\n }\n\n /**\n * Wait until the hook worker has processed every pending bump.\n *\n * `postMessage` is async — without this, a follow-up `import()` may\n * resolve before the worker increments the counter and Node will return\n * the cached old module.\n */\n public flushVersionBumps(): Promise<void> {\n if (!this.loaderAcks) return Promise.resolve();\n\n // Everything posted before this `sync` message is processed by the hook\n // thread before it answers, so exactly this batch is safe to publish on ack.\n const bumpedPaths = this.pendingBumpedPaths;\n this.pendingBumpedPaths = [];\n\n return this.loaderAcks.sync().then(() => {\n const appModules = getDevelopmentAppModuleRegistry();\n\n for (const absolutePath of bumpedPaths) appModules.bump(absolutePath);\n });\n }\n\n\n /**\n * Discover files on disk, reconcile against the manifest, build the dep\n * graph, and persist the new manifest. Idempotent.\n */\n public async initializeAll() {\n const [filesInFilesystem, manifestExists] = await Promise.all([\n this.getAllFilesFromFilesystem(),\n this.manifest.init(),\n ]);\n\n if (!manifestExists) {\n await this.processFiles(filesInFilesystem);\n } else {\n await this.reconcileFiles(filesInFilesystem);\n }\n\n this.dependencyGraph.build(this.files);\n this.fileOperations.updateFileDependents();\n this.fileOperations.syncFilesToManifest();\n await this.manifest.save();\n }\n\n public async checkHealth(files: { added: string[]; changed: string[]; deleted: string[] }) {\n const filesToCheck = [...files.added, ...files.changed]\n .map((file) => this.files.get(Path.toRelative(file)))\n .filter((file): file is FileManager => !!file);\n\n const filesToDelete = files.deleted\n .map((file) => this.files.get(Path.toRelative(file)))\n .filter((file): file is FileManager => !!file);\n\n await this.healthCheckerManager.onFileChanges(filesToCheck);\n this.healthCheckerManager.removeFiles(filesToDelete);\n this.healthCheckerManager.checkFiles(filesToCheck);\n }\n\n public async startCheckingHealth(healthCheckers?: FileHealthCheckerContract[]): Promise<void> {\n devLogDim(\"Started File Health Checks in the background.\");\n\n const checkers = healthCheckers ?? [new TypescriptHealthChecker(), new EslintHealthChecker()];\n await this.healthCheckerManager.setHealthCheckers(checkers).initialize();\n await this.healthCheckerManager.validateAllFiles();\n }\n\n /**\n * Glob the src directory, returning relative paths: every `.ts`/`.tsx`\n * file plus each module's `utils/locales.json`.\n *\n * The JSON dictionaries must be in the boot set: the module loader\n * registers them like any other locale file, but a code-only glob left them\n * out, so `t()` printed raw keys until the watcher reported an edit (FW-02).\n */\n public async getAllFilesFromFilesystem(): Promise<string[]> {\n const [codePaths, localePaths] = await Promise.all([\n getFilesFromDirectory(),\n getFilesFromDirectory(undefined, MODULE_LOCALES_JSON_GLOB),\n ]);\n\n return Array.from(\n new Set([...codePaths, ...localePaths].map((absPath) => Path.toRelative(absPath))),\n );\n }\n\n /**\n * Process every file from scratch — used when no manifest exists.\n */\n private async processFiles(filePaths: string[]) {\n devLogDim(`processing ${filePaths.length} files...`);\n await runInBatches(filePaths, FILE_PROCESSING_BATCH_SIZE, async (relativePath) => {\n const fileManager = new FileManager(\n Path.toAbsolute(relativePath),\n this.files,\n this.fileOperations,\n );\n this.files.set(relativePath, fileManager);\n await fileManager.process();\n });\n devLogSuccess(`processed ${filePaths.length} files`);\n }\n\n private async reconcileFiles(filesInFilesystem: string[]) {\n const filesInManifest = new Set(this.manifest.getAllFilePaths());\n const filesInFilesystemSet = new Set(filesInFilesystem);\n\n const newFiles = filesInFilesystem.filter((f) => !filesInManifest.has(f));\n const deletedFiles = Array.from(filesInManifest).filter((f) => !filesInFilesystemSet.has(f));\n const existingFiles = filesInFilesystem.filter((f) => filesInManifest.has(f));\n\n if (newFiles.length > 0 || deletedFiles.length > 0) {\n devLogDim(\n `reconciling: ${colors.green(newFiles.length)} new, ${colors.red(deletedFiles.length)} deleted, ${colors.blue(existingFiles.length)} existing`,\n );\n }\n\n await this.processFiles(newFiles);\n\n for (const relativePath of deletedFiles) {\n this.manifest.removeFile(relativePath);\n this.files.delete(relativePath);\n }\n\n await runInBatches(existingFiles, FILE_PROCESSING_BATCH_SIZE, async (relativePath) => {\n const fileManager = new FileManager(\n Path.toAbsolute(relativePath),\n this.files,\n this.fileOperations,\n );\n this.files.set(relativePath, fileManager);\n await fileManager.init(this.manifest.getFile(relativePath));\n });\n }\n\n public async watchFiles() {\n devLogSuccess(\"watching for file changes (not serving yet)\");\n\n this.filesWatcher.onFileChange((p, settleMs) => this.eventHandler.handleFileChange(p, settleMs));\n this.filesWatcher.onFileAdd((p, settleMs) => this.eventHandler.handleFileAdd(p, settleMs));\n this.filesWatcher.onFileDelete((p, settleMs) => this.eventHandler.handleFileDelete(p, settleMs));\n\n const watchConfig = warlockConfigManager.get(\"devServer\")?.watch;\n if (watchConfig?.include?.length) {\n this.eventHandler.setIncludeMatcher(createIgnoredMatcher(watchConfig.include));\n }\n\n await this.filesWatcher.watch(watchConfig);\n }\n}\n\nasync function runInBatches<T>(\n items: T[],\n size: number,\n fn: (item: T) => Promise<unknown>,\n): Promise<void> {\n if (items.length === 0) return;\n for (let i = 0; i < items.length; i += size) {\n await Promise.all(items.slice(i, i + size).map(fn));\n }\n}\n\nexport const filesOrchestrator = new FilesOrchestrator();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"files-orchestrator.mjs","names":[],"sources":["../../../../../../../../packages/core/src/dev-server/files-orchestrator.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { init } from \"es-module-lexer\";\nimport { fileURLToPath } from \"node:url\";\nimport type { MessagePort } from \"node:worker_threads\";\nimport { warlockConfigManager } from \"../warlock-config/warlock-config.manager\";\nimport { getDevelopmentAppModuleRegistry } from \"./app-module-registry\";\nimport { DependencyGraph } from \"./dependency-graph\";\nimport { devLogDim, devLogSuccess } from \"./dev-logger\";\nimport { FileEventHandler } from \"./file-event-handler\";\nimport { FileManager } from \"./file-manager\";\nimport { FileOperations } from \"./file-operations\";\nimport { FilesWatcher, createIgnoredMatcher } from \"./files-watcher\";\nimport { FILE_PROCESSING_BATCH_SIZE } from \"./flags\";\nimport { defaultHealthCheckers } from \"./health-checker/default-health-checkers\";\nimport type {\n BuiltInHealthCheckerOptions,\n FileHealthCheckerContract,\n} from \"./health-checker/file-health-checker.contract\";\nimport { FilesHealthcareManager } from \"./health-checker/files-healthcare.manager\";\nimport { buildTranspileInit } from \"./loader/build-transpile-init.js\";\nimport { trackLoaderPortAcks, type LoaderPortAcks } from \"./loader/loader-port-acks\";\nimport { registerLoader } from \"./loader/register-loader.js\";\nimport { ManifestManager } from \"./manifest-manager\";\nimport { ModuleLoader } from \"./module-loader\";\nimport { packageJsonManager } from \"./package-json-manager\";\nimport { Path } from \"../utils/normalized-path\";\nimport { SpecialFilesCollector } from \"./special-files-collector\";\nimport { tsconfigManager } from \"./tsconfig-manager\";\nimport { ensureWarlockDirectory, getFilesFromDirectory } from \"./utils\";\n\n/** Module dictionaries, relative to `src/`; matches what `isLocaleFile` accepts as JSON. */\nexport const MODULE_LOCALES_JSON_GLOB = \"app/*/utils/locales.json\";\n\n/**\n * Register a cleanup callback that fires before the current module is\n * unloaded by HMR. Stack-inspects the caller so user code doesn't need to\n * thread the FileManager through.\n */\nexport function onCleanup(callback: () => any) {\n if (globalThis.__currentModuleFile) {\n globalThis.__currentModuleFile.addCleanup(callback);\n return;\n }\n\n const stack = new Error().stack;\n const callerLine = stack?.split(\"\\n\")[2];\n const match = callerLine?.match(/\\((.+?):\\d+:\\d+\\)/) || callerLine?.match(/at (.+?):\\d+:\\d+/);\n const rawCaller = match?.[1];\n\n // Loaded modules report `file:///…?v=N`; turn that back into a plain path.\n const callerFile = rawCaller?.startsWith(\"file://\")\n ? fileURLToPath(rawCaller.replace(/\\?.*$/, \"\"))\n : rawCaller;\n\n if (!callerFile) return;\n const fileManager = filesOrchestrator.files.get(Path.toRelative(callerFile));\n fileManager?.addCleanup(callback);\n}\n\n/**\n * Top-level coordinator for the dev server's file system.\n *\n * Owns: file discovery, the dependency graph, the manifest, the special-files\n * index, the file watcher, and the lifecycle of the ESM loader hook (which\n * provides cache-busting via `?v=N` version tokens).\n */\nexport class FilesOrchestrator {\n public readonly filesWatcher = new FilesWatcher();\n public readonly files = new Map<string, FileManager>();\n private readonly manifest = new ManifestManager(this.files);\n private readonly dependencyGraph = new DependencyGraph();\n private readonly healthCheckerManager = new FilesHealthcareManager(this.files);\n public readonly specialFilesCollector = new SpecialFilesCollector();\n public readonly moduleLoader = new ModuleLoader(this.specialFilesCollector);\n public readonly fileOperations: FileOperations;\n private readonly eventHandler: FileEventHandler;\n\n /** Main-thread end of the MessageChannel to the loader hook worker. */\n private loaderPort: MessagePort | null = null;\n\n /** `sync`/`sync-ack` round trips on {@link loaderPort}; never holds the process open. */\n private loaderAcks: LoaderPortAcks | null = null;\n\n /**\n * Files bumped since the last `flushVersionBumps()`. They are published to\n * the development app-module carrier only once the hook thread acknowledged\n * the bump, so a subscriber that imports the published URL cannot get the\n * previous instance.\n */\n private pendingBumpedPaths: string[] = [];\n\n public isInitialized = false;\n\n public constructor() {\n // Web creates its Vite bridge after this orchestrator exists; create the\n // carrier now so it can subscribe before the first bump happens.\n getDevelopmentAppModuleRegistry();\n\n this.fileOperations = new FileOperations(\n this.files,\n this.dependencyGraph,\n this.manifest,\n this.specialFilesCollector,\n );\n\n this.eventHandler = new FileEventHandler(\n this.fileOperations,\n this.manifest,\n this.dependencyGraph,\n this.files,\n );\n }\n\n public async add(relativePath: string): Promise<FileManager> {\n return this.fileOperations.addFile(relativePath);\n }\n\n public async load<T>(relativePath: string, type = \"other\") {\n // Guarantee the ESM loader hook is registered before we import anything.\n // `load()` is the dynamic-import entrypoint, so it is the one place that\n // must satisfy `init()`'s documented precondition (\"Must be called before\n // any user src/ module is dynamically imported\") on its own — it cannot\n // assume a caller ran `init()` first.\n //\n // The CLI command-resolution path proves why: `cliCommandsLoader.load()`\n // imports a project command module during command *lookup* (before the\n // command's own `execute()` runs), whereas `loadPreloaders()` only calls\n // `init()` from *inside* `execute()`. So a `warlock <command>` whose\n // command file imports an `app/*` alias or a `.ts` sibling was imported\n // with no hook registered and died on `ERR_MODULE_NOT_FOUND` (f9d8f99f).\n //\n // `init()` is idempotent (guarded by `isInitialized`), so this is a no-op\n // on the dev-server path, which already calls it explicitly at startup.\n await this.init();\n\n const fileManager = await this.add(relativePath);\n return this.moduleLoader.loadModule<T>(fileManager, fileManager.type || type);\n }\n\n public getDependencyGraph(): DependencyGraph {\n return this.dependencyGraph;\n }\n\n public getInvalidationChain(file: string): string[] {\n return this.dependencyGraph.getInvalidationChain(file);\n }\n\n public getFiles(): Map<string, FileManager> {\n return this.files;\n }\n\n public getHealthCheckerManager(): FilesHealthcareManager {\n return this.healthCheckerManager;\n }\n\n /**\n * Initialise managers and register the ESM loader hook. Must be called\n * before any user `src/` module is dynamically imported.\n */\n public async init() {\n if (this.isInitialized) return;\n this.isInitialized = true;\n\n await init;\n await Promise.all([tsconfigManager.init(), packageJsonManager.init()]);\n\n // The loader hook writes itself into .warlock/, so ensure the dir exists.\n await ensureWarlockDirectory();\n\n const devServerConfig = await warlockConfigManager.lazyGet(\"devServer\");\n const transpileInit = buildTranspileInit(\n tsconfigManager.tsconfig?.compilerOptions,\n devServerConfig?.transpileCacheDebug === true,\n );\n\n this.loaderPort = await registerLoader(transpileInit);\n this.loaderAcks = trackLoaderPortAcks(this.loaderPort);\n }\n\n /**\n * Tell the hook worker a file changed. The next `import()` of it will get\n * a fresh `?v=N` URL → Node cache miss → fresh content.\n */\n public bumpVersion(absolutePath: string): void {\n if (!this.loaderPort) return;\n\n this.loaderPort.postMessage({ type: \"bump\", absolutePath });\n this.pendingBumpedPaths.push(absolutePath);\n }\n\n /**\n * Wait until the hook worker has processed every pending bump.\n *\n * `postMessage` is async — without this, a follow-up `import()` may\n * resolve before the worker increments the counter and Node will return\n * the cached old module.\n */\n public flushVersionBumps(): Promise<void> {\n if (!this.loaderAcks) return Promise.resolve();\n\n // Everything posted before this `sync` message is processed by the hook\n // thread before it answers, so exactly this batch is safe to publish on ack.\n const bumpedPaths = this.pendingBumpedPaths;\n this.pendingBumpedPaths = [];\n\n return this.loaderAcks.sync().then(() => {\n const appModules = getDevelopmentAppModuleRegistry();\n\n for (const absolutePath of bumpedPaths) appModules.bump(absolutePath);\n });\n }\n\n /**\n * Discover files on disk, reconcile against the manifest, build the dep\n * graph, and persist the new manifest. Idempotent.\n */\n public async initializeAll() {\n const [filesInFilesystem, manifestExists] = await Promise.all([\n this.getAllFilesFromFilesystem(),\n this.manifest.init(),\n ]);\n\n if (!manifestExists) {\n await this.processFiles(filesInFilesystem);\n } else {\n await this.reconcileFiles(filesInFilesystem);\n }\n\n this.dependencyGraph.build(this.files);\n this.fileOperations.updateFileDependents();\n this.fileOperations.syncFilesToManifest();\n await this.manifest.save();\n }\n\n public async checkHealth(files: { added: string[]; changed: string[]; deleted: string[] }) {\n const filesToCheck = [...files.added, ...files.changed]\n .map((file) => this.files.get(Path.toRelative(file)))\n .filter((file): file is FileManager => !!file);\n\n const filesToDelete = files.deleted\n .map((file) => this.files.get(Path.toRelative(file)))\n .filter((file): file is FileManager => !!file);\n\n await this.healthCheckerManager.onFileChanges(filesToCheck);\n this.healthCheckerManager.removeFiles(filesToDelete);\n this.healthCheckerManager.checkFiles(filesToCheck);\n }\n\n public async startCheckingHealth(\n healthCheckers?: FileHealthCheckerContract[] | BuiltInHealthCheckerOptions,\n ): Promise<void> {\n devLogDim(\"Started File Health Checks in the background.\");\n\n const checkers = Array.isArray(healthCheckers)\n ? healthCheckers\n : defaultHealthCheckers(healthCheckers);\n await this.healthCheckerManager.setHealthCheckers(checkers).initialize();\n await this.healthCheckerManager.validateAllFiles();\n }\n\n /**\n * Glob the src directory, returning relative paths: every `.ts`/`.tsx`\n * file plus each module's `utils/locales.json`.\n *\n * The JSON dictionaries must be in the boot set: the module loader\n * registers them like any other locale file, but a code-only glob left them\n * out, so `t()` printed raw keys until the watcher reported an edit.\n */\n public async getAllFilesFromFilesystem(): Promise<string[]> {\n const [codePaths, localePaths] = await Promise.all([\n getFilesFromDirectory(),\n getFilesFromDirectory(undefined, MODULE_LOCALES_JSON_GLOB),\n ]);\n\n return Array.from(\n new Set([...codePaths, ...localePaths].map((absPath) => Path.toRelative(absPath))),\n );\n }\n\n /**\n * Process every file from scratch — used when no manifest exists.\n */\n private async processFiles(filePaths: string[]) {\n devLogDim(`processing ${filePaths.length} files...`);\n await runInBatches(filePaths, FILE_PROCESSING_BATCH_SIZE, async (relativePath) => {\n const fileManager = new FileManager(\n Path.toAbsolute(relativePath),\n this.files,\n this.fileOperations,\n );\n this.files.set(relativePath, fileManager);\n await fileManager.process();\n });\n devLogSuccess(`processed ${filePaths.length} files`);\n }\n\n private async reconcileFiles(filesInFilesystem: string[]) {\n const filesInManifest = new Set(this.manifest.getAllFilePaths());\n const filesInFilesystemSet = new Set(filesInFilesystem);\n\n const newFiles = filesInFilesystem.filter((f) => !filesInManifest.has(f));\n const deletedFiles = Array.from(filesInManifest).filter((f) => !filesInFilesystemSet.has(f));\n const existingFiles = filesInFilesystem.filter((f) => filesInManifest.has(f));\n\n if (newFiles.length > 0 || deletedFiles.length > 0) {\n devLogDim(\n `reconciling: ${colors.green(newFiles.length)} new, ${colors.red(deletedFiles.length)} deleted, ${colors.blue(existingFiles.length)} existing`,\n );\n }\n\n await this.processFiles(newFiles);\n\n for (const relativePath of deletedFiles) {\n this.manifest.removeFile(relativePath);\n this.files.delete(relativePath);\n }\n\n await runInBatches(existingFiles, FILE_PROCESSING_BATCH_SIZE, async (relativePath) => {\n const fileManager = new FileManager(\n Path.toAbsolute(relativePath),\n this.files,\n this.fileOperations,\n );\n this.files.set(relativePath, fileManager);\n await fileManager.init(this.manifest.getFile(relativePath));\n });\n }\n\n public async watchFiles() {\n devLogSuccess(\"watching for file changes (not serving yet)\");\n\n this.filesWatcher.onFileChange((p, settleMs) =>\n this.eventHandler.handleFileChange(p, settleMs),\n );\n this.filesWatcher.onFileAdd((p, settleMs) => this.eventHandler.handleFileAdd(p, settleMs));\n this.filesWatcher.onFileDelete((p, settleMs) =>\n this.eventHandler.handleFileDelete(p, settleMs),\n );\n\n const watchConfig = warlockConfigManager.get(\"devServer\")?.watch;\n if (watchConfig?.include?.length) {\n this.eventHandler.setIncludeMatcher(createIgnoredMatcher(watchConfig.include));\n }\n\n await this.filesWatcher.watch(watchConfig);\n }\n}\n\nasync function runInBatches<T>(\n items: T[],\n size: number,\n fn: (item: T) => Promise<unknown>,\n): Promise<void> {\n if (items.length === 0) return;\n for (let i = 0; i < items.length; i += size) {\n await Promise.all(items.slice(i, i + size).map(fn));\n }\n}\n\nexport const filesOrchestrator = new FilesOrchestrator();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAa,2BAA2B;;;;;;AAOxC,SAAgB,UAAU,UAAqB;CAC7C,IAAI,WAAW,qBAAqB;EAClC,WAAW,oBAAoB,WAAW,QAAQ;EAClD;CACF;CAGA,MAAM,8BADQ,IAAI,MAAM,EAAC,CAAC,OACA,MAAM,IAAI,CAAC,CAAC;CAEtC,MAAM,aADQ,YAAY,MAAM,mBAAmB,KAAK,YAAY,MAAM,kBAAkB,EACrE,GAAG;CAG1B,MAAM,aAAa,WAAW,WAAW,SAAS,IAC9C,cAAc,UAAU,QAAQ,SAAS,EAAE,CAAC,IAC5C;CAEJ,IAAI,CAAC,YAAY;CAEjB,AADoB,kBAAkB,MAAM,IAAI,KAAK,WAAW,UAAU,CAChE,CAAC,EAAE,WAAW,QAAQ;AAClC;;;;;;;;AASA,IAAa,oBAAb,MAA+B;CA2B7B,AAAO,cAAc;sBA1BU,IAAI,aAAa;+BACxB,IAAI,IAAyB;kBACzB,IAAI,gBAAgB,KAAK,KAAK;yBACvB,IAAI,gBAAgB;8BACf,IAAI,uBAAuB,KAAK,KAAK;+BACrC,IAAI,sBAAsB;sBACnC,IAAI,aAAa,KAAK,qBAAqB;oBAKjC;oBAGG;4BAQL,CAAC;uBAEjB;EAKrB,gCAAgC;EAEhC,KAAK,iBAAiB,IAAI,eACxB,KAAK,OACL,KAAK,iBACL,KAAK,UACL,KAAK,qBACP;EAEA,KAAK,eAAe,IAAI,iBACtB,KAAK,gBACL,KAAK,UACL,KAAK,iBACL,KAAK,KACP;CACF;CAEA,MAAa,IAAI,cAA4C;EAC3D,OAAO,KAAK,eAAe,QAAQ,YAAY;CACjD;CAEA,MAAa,KAAQ,cAAsB,OAAO,SAAS;EAgBzD,MAAM,KAAK,KAAK;EAEhB,MAAM,cAAc,MAAM,KAAK,IAAI,YAAY;EAC/C,OAAO,KAAK,aAAa,WAAc,aAAa,YAAY,QAAQ,IAAI;CAC9E;CAEA,AAAO,qBAAsC;EAC3C,OAAO,KAAK;CACd;CAEA,AAAO,qBAAqB,MAAwB;EAClD,OAAO,KAAK,gBAAgB,qBAAqB,IAAI;CACvD;CAEA,AAAO,WAAqC;EAC1C,OAAO,KAAK;CACd;CAEA,AAAO,0BAAkD;EACvD,OAAO,KAAK;CACd;;;;;CAMA,MAAa,OAAO;EAClB,IAAI,KAAK,eAAe;EACxB,KAAK,gBAAgB;EAErB,MAAM;EACN,MAAM,QAAQ,IAAI,CAAC,gBAAgB,KAAK,GAAG,mBAAmB,KAAK,CAAC,CAAC;EAGrE,MAAM,uBAAuB;EAE7B,MAAM,kBAAkB,MAAM,qBAAqB,QAAQ,WAAW;EACtE,MAAM,gBAAgB,mBACpB,gBAAgB,UAAU,iBAC1B,iBAAiB,wBAAwB,IAC3C;EAEA,KAAK,aAAa,MAAM,eAAe,aAAa;EACpD,KAAK,aAAa,oBAAoB,KAAK,UAAU;CACvD;;;;;CAMA,AAAO,YAAY,cAA4B;EAC7C,IAAI,CAAC,KAAK,YAAY;EAEtB,KAAK,WAAW,YAAY;GAAE,MAAM;GAAQ;EAAa,CAAC;EAC1D,KAAK,mBAAmB,KAAK,YAAY;CAC3C;;;;;;;;CASA,AAAO,oBAAmC;EACxC,IAAI,CAAC,KAAK,YAAY,OAAO,QAAQ,QAAQ;EAI7C,MAAM,cAAc,KAAK;EACzB,KAAK,qBAAqB,CAAC;EAE3B,OAAO,KAAK,WAAW,KAAK,CAAC,CAAC,WAAW;GACvC,MAAM,aAAa,gCAAgC;GAEnD,KAAK,MAAM,gBAAgB,aAAa,WAAW,KAAK,YAAY;EACtE,CAAC;CACH;;;;;CAMA,MAAa,gBAAgB;EAC3B,MAAM,CAAC,mBAAmB,kBAAkB,MAAM,QAAQ,IAAI,CAC5D,KAAK,0BAA0B,GAC/B,KAAK,SAAS,KAAK,CACrB,CAAC;EAED,IAAI,CAAC,gBACH,MAAM,KAAK,aAAa,iBAAiB;OAEzC,MAAM,KAAK,eAAe,iBAAiB;EAG7C,KAAK,gBAAgB,MAAM,KAAK,KAAK;EACrC,KAAK,eAAe,qBAAqB;EACzC,KAAK,eAAe,oBAAoB;EACxC,MAAM,KAAK,SAAS,KAAK;CAC3B;CAEA,MAAa,YAAY,OAAkE;EACzF,MAAM,eAAe,CAAC,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,CACpD,KAAK,SAAS,KAAK,MAAM,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,CACpD,QAAQ,SAA8B,CAAC,CAAC,IAAI;EAE/C,MAAM,gBAAgB,MAAM,QACzB,KAAK,SAAS,KAAK,MAAM,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,CAAC,CACpD,QAAQ,SAA8B,CAAC,CAAC,IAAI;EAE/C,MAAM,KAAK,qBAAqB,cAAc,YAAY;EAC1D,KAAK,qBAAqB,YAAY,aAAa;EACnD,KAAK,qBAAqB,WAAW,YAAY;CACnD;CAEA,MAAa,oBACX,gBACe;EACf,UAAU,+CAA+C;EAEzD,MAAM,WAAW,MAAM,QAAQ,cAAc,IACzC,iBACA,sBAAsB,cAAc;EACxC,MAAM,KAAK,qBAAqB,kBAAkB,QAAQ,CAAC,CAAC,WAAW;EACvE,MAAM,KAAK,qBAAqB,iBAAiB;CACnD;;;;;;;;;CAUA,MAAa,4BAA+C;EAC1D,MAAM,CAAC,WAAW,eAAe,MAAM,QAAQ,IAAI,CACjD,sBAAsB,GACtB,sBAAsB,QAAW,wBAAwB,CAC3D,CAAC;EAED,OAAO,MAAM,KACX,IAAI,IAAI,CAAC,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC,KAAK,YAAY,KAAK,WAAW,OAAO,CAAC,CAAC,CACnF;CACF;;;;CAKA,MAAc,aAAa,WAAqB;EAC9C,UAAU,cAAc,UAAU,OAAO,UAAU;EACnD,MAAM,aAAa,gBAAuC,OAAO,iBAAiB;GAChF,MAAM,cAAc,IAAI,YACtB,KAAK,WAAW,YAAY,GAC5B,KAAK,OACL,KAAK,cACP;GACA,KAAK,MAAM,IAAI,cAAc,WAAW;GACxC,MAAM,YAAY,QAAQ;EAC5B,CAAC;EACD,cAAc,aAAa,UAAU,OAAO,OAAO;CACrD;CAEA,MAAc,eAAe,mBAA6B;EACxD,MAAM,kBAAkB,IAAI,IAAI,KAAK,SAAS,gBAAgB,CAAC;EAC/D,MAAM,uBAAuB,IAAI,IAAI,iBAAiB;EAEtD,MAAM,WAAW,kBAAkB,QAAQ,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;EACxE,MAAM,eAAe,MAAM,KAAK,eAAe,CAAC,CAAC,QAAQ,MAAM,CAAC,qBAAqB,IAAI,CAAC,CAAC;EAC3F,MAAM,gBAAgB,kBAAkB,QAAQ,MAAM,gBAAgB,IAAI,CAAC,CAAC;EAE5E,IAAI,SAAS,SAAS,KAAK,aAAa,SAAS,GAC/C,UACE,gBAAgB,OAAO,MAAM,SAAS,MAAM,EAAE,QAAQ,OAAO,IAAI,aAAa,MAAM,EAAE,YAAY,OAAO,KAAK,cAAc,MAAM,EAAE,UACtI;EAGF,MAAM,KAAK,aAAa,QAAQ;EAEhC,KAAK,MAAM,gBAAgB,cAAc;GACvC,KAAK,SAAS,WAAW,YAAY;GACrC,KAAK,MAAM,OAAO,YAAY;EAChC;EAEA,MAAM,aAAa,oBAA2C,OAAO,iBAAiB;GACpF,MAAM,cAAc,IAAI,YACtB,KAAK,WAAW,YAAY,GAC5B,KAAK,OACL,KAAK,cACP;GACA,KAAK,MAAM,IAAI,cAAc,WAAW;GACxC,MAAM,YAAY,KAAK,KAAK,SAAS,QAAQ,YAAY,CAAC;EAC5D,CAAC;CACH;CAEA,MAAa,aAAa;EACxB,cAAc,6CAA6C;EAE3D,KAAK,aAAa,cAAc,GAAG,aACjC,KAAK,aAAa,iBAAiB,GAAG,QAAQ,CAChD;EACA,KAAK,aAAa,WAAW,GAAG,aAAa,KAAK,aAAa,cAAc,GAAG,QAAQ,CAAC;EACzF,KAAK,aAAa,cAAc,GAAG,aACjC,KAAK,aAAa,iBAAiB,GAAG,QAAQ,CAChD;EAEA,MAAM,cAAc,qBAAqB,IAAI,WAAW,CAAC,EAAE;EAC3D,IAAI,aAAa,SAAS,QACxB,KAAK,aAAa,kBAAkB,qBAAqB,YAAY,OAAO,CAAC;EAG/E,MAAM,KAAK,aAAa,MAAM,WAAW;CAC3C;AACF;AAEA,eAAe,aACb,OACA,MACA,IACe;CACf,IAAI,MAAM,WAAW,GAAG;CACxB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,MACrC,MAAM,QAAQ,IAAI,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAEtD;AAEA,MAAa,oBAAoB,IAAI,kBAAkB"}
|
|
@@ -4,8 +4,8 @@ import "../utils/index.mjs";
|
|
|
4
4
|
import { warlockConfigManager } from "../warlock-config/warlock-config.manager.mjs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { Random } from "@mongez/reinforcements";
|
|
7
|
-
import events from "@mongez/events";
|
|
8
7
|
import fs from "node:fs";
|
|
8
|
+
import events from "@mongez/events";
|
|
9
9
|
import glob from "fast-glob";
|
|
10
10
|
import chokidar from "chokidar";
|
|
11
11
|
|
|
@@ -109,13 +109,12 @@ var EslintHealthChecker = class extends BaseHealthChecker {
|
|
|
109
109
|
return result;
|
|
110
110
|
}
|
|
111
111
|
try {
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
112
|
+
const lintResult = (await this.eslint.lintText(file.source, { filePath: file.absolutePath }))[0];
|
|
113
|
+
if (!lintResult) {
|
|
114
114
|
console.log("No lint results", file.relativePath);
|
|
115
115
|
result.markAsHealthy();
|
|
116
116
|
return result;
|
|
117
117
|
}
|
|
118
|
-
const lintResult = lintResults[0];
|
|
119
118
|
const errors = [];
|
|
120
119
|
const warnings = [];
|
|
121
120
|
for (const message of lintResult.messages) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eslint-health-checker.mjs","names":[],"sources":["../../../../../../../../../../packages/core/src/dev-server/health-checker/checkers/eslint-health-checker.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { ESLint } from \"eslint\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { FileManager } from \"../../file-manager\";\nimport type { FileHealthCheckerContract } from \"../file-health-checker.contract\";\nimport { FileHealthResult } from \"../file-health-result\";\nimport { BaseHealthChecker } from \"./base-health-checker\";\n\nexport class EslintHealthChecker extends BaseHealthChecker implements FileHealthCheckerContract {\n /**\n * ESLint instance (using new ESLint v9 API with flat config)\n */\n private eslint: ESLint | null = null;\n\n /**\n * Health checker name\n */\n public name: string = \"ESLint\";\n\n /**\n * Path to dedicated worker file for ESLint checking\n * Runs in a separate thread to avoid blocking the main dev server\n */\n public workerPath: string = \"./workers/eslint-health.worker\";\n\n /**\n * Whether checker is initialized\n */\n private initialized: boolean = false;\n\n /**\n * Check if file is a lintable file\n */\n private isLintableFile(filePath: string): boolean {\n const ext = filePath.toLowerCase();\n return (\n ext.endsWith(\".ts\") || ext.endsWith(\".tsx\") || ext.endsWith(\".js\") || ext.endsWith(\".jsx\")\n );\n }\n\n /**\n * Initialize the health checker\n */\n public initialize(): EslintHealthChecker {\n try {\n // Check if eslint.config.js exists (new flat config format)\n const flatConfigPath = path.join(process.cwd(), \"eslint.config.js\");\n const flatConfigMjsPath = path.join(process.cwd(), \"eslint.config.mjs\");\n const flatConfigCjsPath = path.join(process.cwd(), \"eslint.config.cjs\");\n\n const hasFlatConfig =\n fs.existsSync(flatConfigPath) ||\n fs.existsSync(flatConfigMjsPath) ||\n fs.existsSync(flatConfigCjsPath);\n\n if (!hasFlatConfig) {\n // No flat config found, skip initialization\n this.initialized = true;\n return this;\n }\n\n // Use new ESLint v9 API with flat config\n // ESLint will automatically find eslint.config.js in the project root\n this.eslint = new ESLint({\n cwd: process.cwd(),\n });\n\n this.initialized = true;\n } catch (error) {\n // Handle any errors during initialization gracefully\n console.warn(\"ESLint Health Checker: Failed to initialize:\", error);\n this.initialized = true; // Mark as initialized to prevent retries\n }\n\n return this;\n }\n\n /**\n * Display health check results in a pretty format\n */\n private displayResults(file: FileManager, result: FileHealthResult): void {\n const stats = result.getStats();\n\n // Only display if there are errors or warnings\n if (stats.errors === 0 && stats.warnings === 0) {\n return;\n }\n\n const fileName = file.relativePath.replace(/\\\\/g, \"/\");\n const errorCount = stats.errors;\n const warningCount = stats.warnings;\n const sourceLines = file.source ? file.source.split(\"\\n\") : [];\n\n // Display errors\n if (errorCount > 0) {\n const errorMessages = result.messages.filter((m) => m.type === \"error\");\n for (const error of errorMessages) {\n const icon = colors.redBright(\"✖\");\n const level = colors.redBright(colors.bold(\"ERROR\"));\n console.log(\n `\\n${icon} ${level} ${colors.dim(\"in\")} ${colors.cyanBright(fileName)}${colors.dim(`(${error.lineNumber},${error.columnNumber})`)}`,\n );\n // Get rule ID from the error if available\n const ruleId = error.ruleId || \"eslint\";\n console.log(\n ` ${colors.magentaBright(ruleId)} ${colors.dim(\"→\")} ${colors.red(error.message)}`,\n );\n\n // Display code line with underline indicator\n if (\n sourceLines.length > 0 &&\n error.lineNumber > 0 &&\n error.lineNumber <= sourceLines.length\n ) {\n const lineIndex = error.lineNumber - 1; // Convert to 0-based index\n const lineContent = sourceLines[lineIndex];\n const lineNum = error.lineNumber.toString().padStart(4, \" \");\n const errorLength = error.length || 1;\n const columnIndex = error.columnNumber - 1; // Convert to 0-based index\n\n // Display the line with normal color (not all red)\n console.log(` ${colors.dim(lineNum)} ${colors.dim(\"│\")} ${lineContent || \"\"}`);\n\n // Display underline indicator\n // Padding accounts for: lineNum.length + 1 space + 1 (│) + 1 space = lineNum.length + 3\n // (The initial 2 spaces indent is already in the console.log)\n const prefixPadding = lineNum.length + 3;\n const columnPadding = \" \".repeat(columnIndex);\n const underline = colors.redBright(\"~\".repeat(Math.max(1, errorLength)));\n console.log(` ${colors.dim(\" \".repeat(prefixPadding))}${columnPadding}${underline}`);\n }\n }\n }\n\n // Display warnings\n if (warningCount > 0) {\n const warningMessages = result.messages.filter((m) => m.type === \"warning\");\n for (const warning of warningMessages) {\n const icon = colors.yellowBright(\"⚠\");\n const level = colors.yellowBright(colors.bold(\"WARNING\"));\n console.log(\n `\\n${icon} ${level} ${colors.dim(\"in\")} ${colors.cyanBright(fileName)}${colors.dim(`(${warning.lineNumber},${warning.columnNumber})`)}`,\n );\n // Get rule ID from the warning if available\n const ruleId = warning.ruleId || \"eslint\";\n console.log(\n ` ${colors.magentaBright(ruleId)} ${colors.dim(\"→\")} ${colors.yellow(warning.message)}`,\n );\n\n // Display code line with underline indicator\n if (\n sourceLines.length > 0 &&\n warning.lineNumber > 0 &&\n warning.lineNumber <= sourceLines.length\n ) {\n const lineIndex = warning.lineNumber - 1; // Convert to 0-based index\n const lineContent = sourceLines[lineIndex];\n const lineNum = warning.lineNumber.toString().padStart(4, \" \");\n const warningLength = warning.length || 1;\n const columnIndex = warning.columnNumber - 1; // Convert to 0-based index\n\n // Display the line with normal color (not all yellow)\n console.log(` ${colors.dim(lineNum)} ${colors.dim(\"│\")} ${lineContent || \"\"}`);\n\n // Display underline indicator\n // Padding accounts for: lineNum.length + 1 space + 1 (│) + 1 space = lineNum.length + 3\n // (The initial 2 spaces indent is already in the console.log)\n const prefixPadding = lineNum.length + 3;\n const columnPadding = \" \".repeat(columnIndex);\n const underline = colors.yellowBright(\"~\".repeat(Math.max(1, warningLength)));\n console.log(` ${colors.dim(\" \".repeat(prefixPadding))}${columnPadding}${underline}`);\n }\n }\n }\n\n // Display summary\n const summary = [];\n if (errorCount > 0) {\n summary.push(colors.red(`${errorCount} error${errorCount > 1 ? \"s\" : \"\"}`));\n }\n if (warningCount > 0) {\n summary.push(colors.yellow(`${warningCount} warning${warningCount > 1 ? \"s\" : \"\"}`));\n }\n }\n\n /**\n * Validate the health of the file\n */\n public async validate(file: FileManager, result: FileHealthResult): Promise<FileHealthResult> {\n // Early exit: skip non-lintable files\n if (!this.isLintableFile(file.absolutePath)) {\n result.markAsHealthy();\n return result;\n }\n\n // Early exit: check if ESLint is available\n if (!this.eslint) {\n result.markAsHealthy();\n return result;\n }\n\n try {\n // Use lintText to lint the source code directly from FileManager\n // This ensures we always use the latest content\n const lintResults = await this.eslint.lintText(file.source, {\n filePath: file.absolutePath,\n });\n\n if (lintResults.length === 0) {\n console.log(\"No lint results\", file.relativePath);\n result.markAsHealthy();\n return result;\n }\n\n const lintResult = lintResults[0];\n\n // Convert ESLint messages to FileHealthResult format\n const errors: Array<{\n message: string;\n type: \"error\";\n lineNumber: number;\n columnNumber: number;\n length: number;\n ruleId?: string;\n }> = [];\n const warnings: Array<{\n message: string;\n type: \"warning\";\n lineNumber: number;\n columnNumber: number;\n length: number;\n ruleId?: string;\n }> = [];\n\n for (const message of lintResult.messages) {\n const isError = message.severity === 2;\n const isWarning = message.severity === 1;\n\n if (isError) {\n errors.push({\n message: message.message,\n type: \"error\",\n lineNumber: message.line || 1,\n columnNumber: message.column || 1,\n length: message.endColumn && message.column ? message.endColumn - message.column : 1,\n ruleId: message.ruleId || undefined,\n });\n } else if (isWarning) {\n warnings.push({\n message: message.message,\n type: \"warning\",\n lineNumber: message.line || 1,\n columnNumber: message.column || 1,\n length: message.endColumn && message.column ? message.endColumn - message.column : 1,\n ruleId: message.ruleId || undefined,\n });\n }\n }\n\n // Add errors and warnings to result\n if (errors.length > 0) {\n result.addErrors(errors);\n }\n\n if (warnings.length > 0) {\n result.addWarnings(warnings);\n }\n\n // If no errors or warnings, mark as healthy\n if (errors.length === 0 && warnings.length === 0) {\n result.markAsHealthy();\n } else {\n // Display results if there are errors or warnings\n this.displayResults(file, result);\n }\n } catch (error) {\n // Handle any errors during validation gracefully\n console.log(\"ESlint Error:\", error);\n result.markAsHealthy(); // Return healthy on error to avoid blocking\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"eslint-health-checker.mjs","names":[],"sources":["../../../../../../../../../../packages/core/src/dev-server/health-checker/checkers/eslint-health-checker.ts"],"sourcesContent":["import { colors } from \"@mongez/copper\";\nimport { ESLint } from \"eslint\";\nimport fs from \"fs\";\nimport path from \"path\";\nimport type { FileManager } from \"../../file-manager\";\nimport type { FileHealthCheckerContract } from \"../file-health-checker.contract\";\nimport { FileHealthResult } from \"../file-health-result\";\nimport { BaseHealthChecker } from \"./base-health-checker\";\n\nexport class EslintHealthChecker extends BaseHealthChecker implements FileHealthCheckerContract {\n /**\n * ESLint instance (using new ESLint v9 API with flat config)\n */\n private eslint: ESLint | null = null;\n\n /**\n * Health checker name\n */\n public name: string = \"ESLint\";\n\n /**\n * Path to dedicated worker file for ESLint checking\n * Runs in a separate thread to avoid blocking the main dev server\n */\n public workerPath: string = \"./workers/eslint-health.worker\";\n\n /**\n * Whether checker is initialized\n */\n private initialized: boolean = false;\n\n /**\n * Check if file is a lintable file\n */\n private isLintableFile(filePath: string): boolean {\n const ext = filePath.toLowerCase();\n return (\n ext.endsWith(\".ts\") || ext.endsWith(\".tsx\") || ext.endsWith(\".js\") || ext.endsWith(\".jsx\")\n );\n }\n\n /**\n * Initialize the health checker\n */\n public initialize(): EslintHealthChecker {\n try {\n // Check if eslint.config.js exists (new flat config format)\n const flatConfigPath = path.join(process.cwd(), \"eslint.config.js\");\n const flatConfigMjsPath = path.join(process.cwd(), \"eslint.config.mjs\");\n const flatConfigCjsPath = path.join(process.cwd(), \"eslint.config.cjs\");\n\n const hasFlatConfig =\n fs.existsSync(flatConfigPath) ||\n fs.existsSync(flatConfigMjsPath) ||\n fs.existsSync(flatConfigCjsPath);\n\n if (!hasFlatConfig) {\n // No flat config found, skip initialization\n this.initialized = true;\n return this;\n }\n\n // Use new ESLint v9 API with flat config\n // ESLint will automatically find eslint.config.js in the project root\n this.eslint = new ESLint({\n cwd: process.cwd(),\n });\n\n this.initialized = true;\n } catch (error) {\n // Handle any errors during initialization gracefully\n console.warn(\"ESLint Health Checker: Failed to initialize:\", error);\n this.initialized = true; // Mark as initialized to prevent retries\n }\n\n return this;\n }\n\n /**\n * Display health check results in a pretty format\n */\n private displayResults(file: FileManager, result: FileHealthResult): void {\n const stats = result.getStats();\n\n // Only display if there are errors or warnings\n if (stats.errors === 0 && stats.warnings === 0) {\n return;\n }\n\n const fileName = file.relativePath.replace(/\\\\/g, \"/\");\n const errorCount = stats.errors;\n const warningCount = stats.warnings;\n const sourceLines = file.source ? file.source.split(\"\\n\") : [];\n\n // Display errors\n if (errorCount > 0) {\n const errorMessages = result.messages.filter((m) => m.type === \"error\");\n for (const error of errorMessages) {\n const icon = colors.redBright(\"✖\");\n const level = colors.redBright(colors.bold(\"ERROR\"));\n console.log(\n `\\n${icon} ${level} ${colors.dim(\"in\")} ${colors.cyanBright(fileName)}${colors.dim(`(${error.lineNumber},${error.columnNumber})`)}`,\n );\n // Get rule ID from the error if available\n const ruleId = error.ruleId || \"eslint\";\n console.log(\n ` ${colors.magentaBright(ruleId)} ${colors.dim(\"→\")} ${colors.red(error.message)}`,\n );\n\n // Display code line with underline indicator\n if (\n sourceLines.length > 0 &&\n error.lineNumber > 0 &&\n error.lineNumber <= sourceLines.length\n ) {\n const lineIndex = error.lineNumber - 1; // Convert to 0-based index\n const lineContent = sourceLines[lineIndex];\n const lineNum = error.lineNumber.toString().padStart(4, \" \");\n const errorLength = error.length || 1;\n const columnIndex = error.columnNumber - 1; // Convert to 0-based index\n\n // Display the line with normal color (not all red)\n console.log(` ${colors.dim(lineNum)} ${colors.dim(\"│\")} ${lineContent || \"\"}`);\n\n // Display underline indicator\n // Padding accounts for: lineNum.length + 1 space + 1 (│) + 1 space = lineNum.length + 3\n // (The initial 2 spaces indent is already in the console.log)\n const prefixPadding = lineNum.length + 3;\n const columnPadding = \" \".repeat(columnIndex);\n const underline = colors.redBright(\"~\".repeat(Math.max(1, errorLength)));\n console.log(` ${colors.dim(\" \".repeat(prefixPadding))}${columnPadding}${underline}`);\n }\n }\n }\n\n // Display warnings\n if (warningCount > 0) {\n const warningMessages = result.messages.filter((m) => m.type === \"warning\");\n for (const warning of warningMessages) {\n const icon = colors.yellowBright(\"⚠\");\n const level = colors.yellowBright(colors.bold(\"WARNING\"));\n console.log(\n `\\n${icon} ${level} ${colors.dim(\"in\")} ${colors.cyanBright(fileName)}${colors.dim(`(${warning.lineNumber},${warning.columnNumber})`)}`,\n );\n // Get rule ID from the warning if available\n const ruleId = warning.ruleId || \"eslint\";\n console.log(\n ` ${colors.magentaBright(ruleId)} ${colors.dim(\"→\")} ${colors.yellow(warning.message)}`,\n );\n\n // Display code line with underline indicator\n if (\n sourceLines.length > 0 &&\n warning.lineNumber > 0 &&\n warning.lineNumber <= sourceLines.length\n ) {\n const lineIndex = warning.lineNumber - 1; // Convert to 0-based index\n const lineContent = sourceLines[lineIndex];\n const lineNum = warning.lineNumber.toString().padStart(4, \" \");\n const warningLength = warning.length || 1;\n const columnIndex = warning.columnNumber - 1; // Convert to 0-based index\n\n // Display the line with normal color (not all yellow)\n console.log(` ${colors.dim(lineNum)} ${colors.dim(\"│\")} ${lineContent || \"\"}`);\n\n // Display underline indicator\n // Padding accounts for: lineNum.length + 1 space + 1 (│) + 1 space = lineNum.length + 3\n // (The initial 2 spaces indent is already in the console.log)\n const prefixPadding = lineNum.length + 3;\n const columnPadding = \" \".repeat(columnIndex);\n const underline = colors.yellowBright(\"~\".repeat(Math.max(1, warningLength)));\n console.log(` ${colors.dim(\" \".repeat(prefixPadding))}${columnPadding}${underline}`);\n }\n }\n }\n\n // Display summary\n const summary = [];\n if (errorCount > 0) {\n summary.push(colors.red(`${errorCount} error${errorCount > 1 ? \"s\" : \"\"}`));\n }\n if (warningCount > 0) {\n summary.push(colors.yellow(`${warningCount} warning${warningCount > 1 ? \"s\" : \"\"}`));\n }\n }\n\n /**\n * Validate the health of the file\n */\n public async validate(file: FileManager, result: FileHealthResult): Promise<FileHealthResult> {\n // Early exit: skip non-lintable files\n if (!this.isLintableFile(file.absolutePath)) {\n result.markAsHealthy();\n return result;\n }\n\n // Early exit: check if ESLint is available\n if (!this.eslint) {\n result.markAsHealthy();\n return result;\n }\n\n try {\n // Use lintText to lint the source code directly from FileManager\n // This ensures we always use the latest content\n const lintResults = await this.eslint.lintText(file.source, {\n filePath: file.absolutePath,\n });\n\n const lintResult = lintResults[0];\n if (!lintResult) {\n console.log(\"No lint results\", file.relativePath);\n result.markAsHealthy();\n return result;\n }\n\n // Convert ESLint messages to FileHealthResult format\n const errors: Array<{\n message: string;\n type: \"error\";\n lineNumber: number;\n columnNumber: number;\n length: number;\n ruleId?: string;\n }> = [];\n const warnings: Array<{\n message: string;\n type: \"warning\";\n lineNumber: number;\n columnNumber: number;\n length: number;\n ruleId?: string;\n }> = [];\n\n for (const message of lintResult.messages) {\n const isError = message.severity === 2;\n const isWarning = message.severity === 1;\n\n if (isError) {\n errors.push({\n message: message.message,\n type: \"error\",\n lineNumber: message.line || 1,\n columnNumber: message.column || 1,\n length: message.endColumn && message.column ? message.endColumn - message.column : 1,\n ruleId: message.ruleId || undefined,\n });\n } else if (isWarning) {\n warnings.push({\n message: message.message,\n type: \"warning\",\n lineNumber: message.line || 1,\n columnNumber: message.column || 1,\n length: message.endColumn && message.column ? message.endColumn - message.column : 1,\n ruleId: message.ruleId || undefined,\n });\n }\n }\n\n // Add errors and warnings to result\n if (errors.length > 0) {\n result.addErrors(errors);\n }\n\n if (warnings.length > 0) {\n result.addWarnings(warnings);\n }\n\n // If no errors or warnings, mark as healthy\n if (errors.length === 0 && warnings.length === 0) {\n result.markAsHealthy();\n } else {\n // Display results if there are errors or warnings\n this.displayResults(file, result);\n }\n } catch (error) {\n // Handle any errors during validation gracefully\n console.log(\"ESlint Error:\", error);\n result.markAsHealthy(); // Return healthy on error to avoid blocking\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BaseHealthChecker } from "./base-health-checker.mjs";
|
|
2
|
+
import { OxlintRunner } from "../oxlint-runner.mjs";
|
|
3
|
+
|
|
4
|
+
//#region ../../packages/core/src/dev-server/health-checker/checkers/oxlint-health-checker.ts
|
|
5
|
+
var OxlintHealthChecker = class extends BaseHealthChecker {
|
|
6
|
+
constructor(..._args) {
|
|
7
|
+
super(..._args);
|
|
8
|
+
this.name = "Oxlint";
|
|
9
|
+
this.workerPath = "./workers/oxlint-health.worker";
|
|
10
|
+
this.runner = new OxlintRunner();
|
|
11
|
+
}
|
|
12
|
+
initialize() {
|
|
13
|
+
this.runner.initialize(process.cwd());
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
async validate(file, result) {
|
|
17
|
+
try {
|
|
18
|
+
const [checked] = await this.runner.checkFiles([{
|
|
19
|
+
path: file.absolutePath,
|
|
20
|
+
relativePath: file.relativePath
|
|
21
|
+
}]);
|
|
22
|
+
if (checked?.errors.length) result.addErrors(checked.errors);
|
|
23
|
+
if (checked?.warnings.length) result.addWarnings(checked.warnings);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.warn("Oxlint Health Checker:", error instanceof Error ? error.message : String(error));
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { OxlintHealthChecker };
|
|
33
|
+
//# sourceMappingURL=oxlint-health-checker.mjs.map
|