@warlock.js/core 5.30.0 → 5.32.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 +165 -36
- package/README.md +28 -23
- package/bin/source-load-hook.mjs +63 -0
- package/bin/warlock.js +102 -42
- package/esm/application/app.d.mts +3 -3
- package/esm/application/app.d.mts.map +1 -1
- package/esm/application/application-config-types.d.mts +1 -2
- package/esm/application/application-config-types.d.mts.map +1 -1
- package/esm/application/application.d.mts +5 -7
- package/esm/application/application.d.mts.map +1 -1
- package/esm/application/application.mjs +3 -1
- package/esm/application/application.mjs.map +1 -1
- package/esm/application/boot-signal.d.mts +14 -12
- package/esm/application/boot-signal.d.mts.map +1 -1
- package/esm/application/index.d.mts +2 -1
- package/esm/application/index.mjs +1 -1
- package/esm/application/public-url.d.mts +1 -2
- package/esm/application/public-url.d.mts.map +1 -1
- package/esm/application/roles.d.mts +10 -11
- package/esm/application/roles.d.mts.map +1 -1
- package/esm/benchmark/benchmark-snapshots.d.mts +1 -3
- package/esm/benchmark/benchmark-snapshots.d.mts.map +1 -1
- package/esm/benchmark/benchmark.d.mts +1 -3
- package/esm/benchmark/benchmark.d.mts.map +1 -1
- package/esm/benchmark/channels/console.channel.d.mts +1 -3
- package/esm/benchmark/channels/console.channel.d.mts.map +1 -1
- package/esm/benchmark/channels/noop.channel.d.mts +1 -3
- package/esm/benchmark/channels/noop.channel.d.mts.map +1 -1
- package/esm/benchmark/index.mjs +1 -1
- package/esm/benchmark/profiler.d.mts +1 -3
- package/esm/benchmark/profiler.d.mts.map +1 -1
- package/esm/benchmark/profiler.mjs +2 -1
- package/esm/benchmark/profiler.mjs.map +1 -1
- package/esm/benchmark/types.d.mts +22 -17
- package/esm/benchmark/types.d.mts.map +1 -1
- package/esm/bootstrap/setup.d.mts +1 -2
- package/esm/bootstrap/setup.d.mts.map +1 -1
- package/esm/bootstrap.d.mts +1 -2
- package/esm/bootstrap.d.mts.map +1 -1
- package/esm/cache/database-cache-driver.d.mts +3 -5
- package/esm/cache/database-cache-driver.d.mts.map +1 -1
- package/esm/cache/database-cache-driver.mjs +1 -1
- package/esm/cache/index.d.mts +2 -1
- package/esm/cache/index.mjs +1 -1
- package/esm/cli/cli-commands.manager.mjs +6 -3
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- 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 +70 -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 +12 -3
- 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 +89 -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 +23 -27
- 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 +15 -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/controller.generator.mjs +5 -2
- package/esm/cli/commands/generate/generators/controller.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/endpoint.generator.mjs +313 -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 +4 -3
- package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/repository.generator.mjs +3 -1
- package/esm/cli/commands/generate/generators/repository.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/resource.generator.mjs +3 -1
- package/esm/cli/commands/generate/generators/resource.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/service.generator.mjs +3 -1
- package/esm/cli/commands/generate/generators/service.generator.mjs.map +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 +136 -0
- package/esm/cli/commands/generate/utils/endpoint-schema.mjs.map +1 -0
- package/esm/cli/commands/generate/utils/name-parser.mjs +2 -2
- package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/path-resolver.mjs +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 +73 -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/issue/collect-environment.mjs +187 -0
- package/esm/cli/commands/issue/collect-environment.mjs.map +1 -0
- package/esm/cli/commands/issue/issue-command.action.mjs +70 -0
- package/esm/cli/commands/issue/issue-command.action.mjs.map +1 -0
- package/esm/cli/commands/issue.command.mjs +31 -0
- package/esm/cli/commands/issue.command.mjs.map +1 -0
- package/esm/cli/commands/mcp/mcp-command.action.mjs +104 -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 +1 -1
- 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 +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/format-routes-table.mjs +1 -1
- package/esm/cli/commands/routes/route-row.mjs +1 -1
- package/esm/cli/commands/routes/routes-diff.action.mjs +3 -3
- package/esm/cli/commands/routes/routes-diff.action.mjs.map +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/commands-loader.mjs +1 -1
- 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 +25 -1
- package/esm/cli/framework-cli-commands.mjs.map +1 -1
- package/esm/cli/parse-cli-args.mjs +3 -2
- package/esm/cli/parse-cli-args.mjs.map +1 -1
- package/esm/cli/start.d.mts +1 -1
- package/esm/cli/string-similarity.mjs +1 -1
- package/esm/commands/cli-command.d.mts +2 -4
- package/esm/commands/cli-command.d.mts.map +1 -1
- package/esm/commands/index.d.mts +2 -1
- package/esm/commands/index.mjs +1 -1
- package/esm/commands/types.d.mts +8 -8
- package/esm/commands/types.d.mts.map +1 -1
- package/esm/config/config-getter.d.mts +2 -3
- package/esm/config/config-getter.d.mts.map +1 -1
- package/esm/config/config-getter.mjs +5 -5
- package/esm/config/config-getter.mjs.map +1 -1
- package/esm/config/config-handlers.d.mts +1 -3
- package/esm/config/config-handlers.d.mts.map +1 -1
- package/esm/config/config-loader.d.mts +1 -2
- package/esm/config/config-loader.d.mts.map +1 -1
- package/esm/config/config-loader.mjs +35 -14
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/config/config-manager.mjs +1 -1
- package/esm/config/config-schema.d.mts +70 -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/config-setter.d.mts +2 -4
- package/esm/config/config-setter.d.mts.map +1 -1
- package/esm/config/config-setter.mjs +2 -2
- package/esm/config/config-setter.mjs.map +1 -1
- package/esm/config/config-special-handlers.d.mts +2 -4
- package/esm/config/config-special-handlers.d.mts.map +1 -1
- package/esm/config/index.d.mts +7 -0
- package/esm/config/index.mjs +2 -1
- package/esm/config/types.d.mts +4 -5
- package/esm/config/types.d.mts.map +1 -1
- package/esm/connectors/access-connector.d.mts +1 -3
- package/esm/connectors/access-connector.d.mts.map +1 -1
- package/esm/connectors/access-connector.mjs +2 -2
- package/esm/connectors/access-connector.mjs.map +1 -1
- package/esm/connectors/ai-connector.d.mts +1 -3
- package/esm/connectors/ai-connector.d.mts.map +1 -1
- package/esm/connectors/ai-connector.mjs +2 -2
- package/esm/connectors/ai-connector.mjs.map +1 -1
- package/esm/connectors/assert-no-reserved-connector-names.d.mts +1 -3
- 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 +1 -3
- package/esm/connectors/assert-unique-connector-names.d.mts.map +1 -1
- package/esm/connectors/assert-unique-connector-names.mjs +26 -1
- package/esm/connectors/assert-unique-connector-names.mjs.map +1 -1
- package/esm/connectors/base-connector.d.mts +1 -3
- package/esm/connectors/base-connector.d.mts.map +1 -1
- package/esm/connectors/cache-connector.d.mts +1 -3
- package/esm/connectors/cache-connector.d.mts.map +1 -1
- package/esm/connectors/cache-connector.mjs +3 -3
- package/esm/connectors/cache-connector.mjs.map +1 -1
- package/esm/connectors/connectors-manager.d.mts +2 -4
- package/esm/connectors/connectors-manager.d.mts.map +1 -1
- package/esm/connectors/connectors-manager.mjs +2 -2
- package/esm/connectors/connectors-manager.mjs.map +1 -1
- package/esm/connectors/database-connector.d.mts +1 -3
- package/esm/connectors/database-connector.d.mts.map +1 -1
- package/esm/connectors/database-connector.mjs +2 -2
- package/esm/connectors/database-connector.mjs.map +1 -1
- package/esm/connectors/describe-server-address.mjs +4 -4
- package/esm/connectors/describe-server-address.mjs.map +1 -1
- package/esm/connectors/herald-connector.d.mts +1 -3
- package/esm/connectors/herald-connector.d.mts.map +1 -1
- package/esm/connectors/herald-connector.mjs +2 -2
- package/esm/connectors/herald-connector.mjs.map +1 -1
- package/esm/connectors/http-connector.d.mts +1 -3
- package/esm/connectors/http-connector.d.mts.map +1 -1
- package/esm/connectors/http-connector.mjs +11 -9
- package/esm/connectors/http-connector.mjs.map +1 -1
- package/esm/connectors/index.d.mts +2 -1
- package/esm/connectors/index.mjs +1 -1
- package/esm/connectors/logger-connector.d.mts +1 -3
- package/esm/connectors/logger-connector.d.mts.map +1 -1
- package/esm/connectors/logger-connector.mjs +2 -2
- package/esm/connectors/logger-connector.mjs.map +1 -1
- package/esm/connectors/mail-connector.d.mts +1 -3
- package/esm/connectors/mail-connector.d.mts.map +1 -1
- package/esm/connectors/mail-connector.mjs +2 -2
- package/esm/connectors/mail-connector.mjs.map +1 -1
- package/esm/connectors/notifications-connector.d.mts +1 -3
- package/esm/connectors/notifications-connector.d.mts.map +1 -1
- package/esm/connectors/notifications-connector.mjs +2 -2
- package/esm/connectors/notifications-connector.mjs.map +1 -1
- package/esm/connectors/register-configured-connectors.d.mts +2 -4
- package/esm/connectors/register-configured-connectors.d.mts.map +1 -1
- package/esm/connectors/single-server-warnings.mjs.map +1 -1
- package/esm/connectors/socket-connector.d.mts +1 -3
- package/esm/connectors/socket-connector.d.mts.map +1 -1
- package/esm/connectors/socket-connector.mjs +12 -10
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/connectors/storage.connector.d.mts +1 -3
- package/esm/connectors/storage.connector.d.mts.map +1 -1
- package/esm/connectors/storage.connector.mjs +2 -2
- package/esm/connectors/storage.connector.mjs.map +1 -1
- package/esm/connectors/types.d.mts +17 -14
- package/esm/connectors/types.d.mts.map +1 -1
- package/esm/container/container-instance-registry.mjs.map +1 -1
- package/esm/container/development-app-modules.d.mts +7 -5
- package/esm/container/development-app-modules.d.mts.map +1 -1
- package/esm/container/development-model-modules.d.mts +6 -5
- package/esm/container/development-model-modules.d.mts.map +1 -1
- package/esm/container/index.d.mts +4 -4
- package/esm/container/index.d.mts.map +1 -1
- package/esm/container/index.mjs.map +1 -1
- package/esm/database/index.d.mts +3 -1
- package/esm/database/index.mjs +1 -1
- package/esm/database/migrate-action.mjs +1 -1
- package/esm/database/migrate-action.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.d.mts +2 -31
- package/esm/database/models/database-log/database-log.d.mts.map +1 -1
- package/esm/database/models/database-log/index.d.mts +2 -1
- package/esm/database/models/database-log/index.mjs +1 -1
- package/esm/database/seed-command-action.mjs +1 -1
- package/esm/database/seeds/seeder.d.mts +2 -4
- package/esm/database/seeds/seeder.d.mts.map +1 -1
- package/esm/database/seeds/seeder.errors.d.mts +6 -3
- 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/database/seeds/seeders.manager.mjs +2 -1
- package/esm/database/seeds/seeders.manager.mjs.map +1 -1
- package/esm/database/seeds/types.d.mts +7 -8
- package/esm/database/seeds/types.d.mts.map +1 -1
- package/esm/database/utils.d.mts +4 -5
- package/esm/database/utils.d.mts.map +1 -1
- package/esm/dev-server/app-module-registry.mjs +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 +17 -9
- package/esm/dev-server/create-worker.mjs.map +1 -1
- package/esm/dev-server/dependency-graph.d.mts +1 -3
- package/esm/dev-server/dependency-graph.d.mts.map +1 -1
- package/esm/dev-server/dependency-graph.mjs +1 -1
- package/esm/dev-server/dependency-graph.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/extract-translation-keys.mjs +16 -17
- package/esm/dev-server/extract-translation-keys.mjs.map +1 -1
- package/esm/dev-server/file-manager.d.mts +3 -7
- package/esm/dev-server/file-manager.d.mts.map +1 -1
- package/esm/dev-server/file-operations.d.mts +1 -3
- package/esm/dev-server/file-operations.d.mts.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 +12 -11
- package/esm/dev-server/files-watcher.mjs.map +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/checkers/typescript-health-checker.mjs +36 -115
- package/esm/dev-server/health-checker/checkers/typescript-health-checker.mjs.map +1 -1
- 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 +12 -6
- package/esm/dev-server/health-checker/file-health-checker.contract.d.mts.map +1 -1
- package/esm/dev-server/health-checker/file-health-result.d.mts +2 -2
- package/esm/dev-server/health-checker/file-health-result.d.mts.map +1 -1
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs +16 -4
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
- package/esm/dev-server/health-checker/oxlint-runner.mjs +303 -0
- package/esm/dev-server/health-checker/oxlint-runner.mjs.map +1 -0
- package/esm/dev-server/health-checker/workers/eslint-health.worker.d.mts +1 -1
- 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/health-checker/workers/ts-health.worker.d.mts +1 -1
- package/esm/dev-server/health-checker/workers/ts-health.worker.mjs +40 -174
- package/esm/dev-server/health-checker/workers/ts-health.worker.mjs.map +1 -1
- package/esm/dev-server/loader/hook-thread.d.mts +4 -8
- package/esm/dev-server/loader/hook-thread.d.mts.map +1 -1
- package/esm/dev-server/loader/load-hook.d.mts +10 -6
- package/esm/dev-server/loader/load-hook.d.mts.map +1 -1
- package/esm/dev-server/loader/load-hook.mjs +4 -3
- package/esm/dev-server/loader/load-hook.mjs.map +1 -1
- 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/own-resolver.mjs +1 -1
- package/esm/dev-server/loader/register-loader.mjs +4 -3
- package/esm/dev-server/loader/register-loader.mjs.map +1 -1
- package/esm/dev-server/loader/resolve-hook.d.mts +2 -2
- package/esm/dev-server/loader/resolve-hook.d.mts.map +1 -1
- package/esm/dev-server/loader/resolve-hook.mjs +3 -2
- package/esm/dev-server/loader/resolve-hook.mjs.map +1 -1
- package/esm/dev-server/loader/transpile-cache.mjs +3 -2
- package/esm/dev-server/loader/transpile-cache.mjs.map +1 -1
- package/esm/dev-server/manifest-manager.d.mts +1 -3
- package/esm/dev-server/manifest-manager.d.mts.map +1 -1
- package/esm/dev-server/model-module-registry.mjs +3 -3
- package/esm/dev-server/model-module-registry.mjs.map +1 -1
- package/esm/dev-server/model-resource-typings.mjs +40 -47
- package/esm/dev-server/model-resource-typings.mjs.map +1 -1
- package/esm/dev-server/module-loader.mjs +3 -2
- package/esm/dev-server/module-loader.mjs.map +1 -1
- package/esm/dev-server/package-json-manager.mjs +1 -1
- package/esm/dev-server/parse-imports.mjs +7 -39
- package/esm/dev-server/parse-imports.mjs.map +1 -1
- package/esm/dev-server/read-config-ast.mjs +3 -33
- package/esm/dev-server/read-config-ast.mjs.map +1 -1
- package/esm/dev-server/ready-block.mjs +1 -1
- package/esm/dev-server/route-types-publisher.mjs +1 -1
- package/esm/dev-server/shortcuts.mjs +1 -1
- package/esm/dev-server/special-files-collector.d.mts +2 -4
- package/esm/dev-server/special-files-collector.d.mts.map +1 -1
- package/esm/dev-server/start-development-server.mjs.map +1 -1
- package/esm/dev-server/supervisor.mjs +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 +3 -3
- package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
- package/esm/dev-server/type-generator.mjs +31 -38
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/dev-server/types.d.mts +3 -4
- package/esm/dev-server/types.d.mts.map +1 -1
- package/esm/dev-server/update-check-cache.mjs +2 -2
- package/esm/dev-server/update-check-cache.mjs.map +1 -1
- package/esm/encryption/encrypt.d.mts +2 -3
- package/esm/encryption/encrypt.d.mts.map +1 -1
- package/esm/encryption/hash.d.mts +1 -2
- package/esm/encryption/hash.d.mts.map +1 -1
- package/esm/encryption/index.mjs +1 -1
- package/esm/encryption/password.d.mts +2 -3
- package/esm/encryption/password.d.mts.map +1 -1
- package/esm/encryption/types.d.mts +2 -3
- package/esm/encryption/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 +660 -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 +21 -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 +22 -5
- 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 +3 -2
- 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 +7 -3
- 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 +16 -23
- package/esm/generations/features/shared/merge-web-sitemap-config.mjs.map +1 -1
- package/esm/generations/features/shared/patch-tsconfig-include.mjs +2 -2
- package/esm/generations/features/shared/patch-tsconfig-include.mjs.map +1 -1
- package/esm/generations/features/shared/relocate-conflicting-home-route.mjs +2 -2
- package/esm/generations/features/shared/relocate-conflicting-home-route.mjs.map +1 -1
- package/esm/generations/features/sitemap.feature.mjs +3 -2
- 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 +156 -14
- package/esm/generations/stubs.mjs.map +1 -1
- package/esm/http/boot-port-preflight.d.mts +4 -5
- package/esm/http/boot-port-preflight.d.mts.map +1 -1
- package/esm/http/boot-port-preflight.mjs +2 -2
- package/esm/http/boot-port-preflight.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-cors-options.mjs +2 -2
- package/esm/http/build-cors-options.mjs.map +1 -1
- package/esm/http/build-rate-limit-options.d.mts +15 -3
- package/esm/http/build-rate-limit-options.d.mts.map +1 -1
- package/esm/http/build-rate-limit-options.mjs +1 -1
- package/esm/http/build-rate-limit-options.mjs.map +1 -1
- package/esm/http/conditional-request.d.mts +87 -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/config.d.mts +2 -4
- package/esm/http/config.d.mts.map +1 -1
- package/esm/http/config.mjs +2 -2
- package/esm/http/config.mjs.map +1 -1
- package/esm/http/context/request-context.d.mts +6 -7
- package/esm/http/context/request-context.d.mts.map +1 -1
- package/esm/http/context/request-memo.d.mts +1 -2
- package/esm/http/context/request-memo.d.mts.map +1 -1
- package/esm/http/createHttpApplication.d.mts +2 -3
- package/esm/http/createHttpApplication.d.mts.map +1 -1
- package/esm/http/createHttpApplication.mjs +2 -2
- package/esm/http/createHttpApplication.mjs.map +1 -1
- package/esm/http/csp.d.mts +12 -12
- package/esm/http/csp.d.mts.map +1 -1
- package/esm/http/csp.mjs +3 -2
- package/esm/http/csp.mjs.map +1 -1
- package/esm/http/csrf-default-guard.d.mts +2 -4
- package/esm/http/csrf-default-guard.d.mts.map +1 -1
- package/esm/http/csrf-default-guard.mjs +1 -1
- package/esm/http/csrf-default-guard.mjs.map +1 -1
- package/esm/http/csrf-origin-policy.d.mts +7 -9
- package/esm/http/csrf-origin-policy.d.mts.map +1 -1
- package/esm/http/csrf-origin-policy.mjs +2 -2
- package/esm/http/csrf-origin-policy.mjs.map +1 -1
- package/esm/http/database/RequestLog.d.mts +26 -87
- package/esm/http/database/RequestLog.d.mts.map +1 -1
- package/esm/http/error-codes.d.mts +1 -2
- package/esm/http/error-codes.d.mts.map +1 -1
- package/esm/http/error-mapper.d.mts +2 -4
- package/esm/http/error-mapper.d.mts.map +1 -1
- package/esm/http/error-mapper.mjs +2 -2
- package/esm/http/error-mapper.mjs.map +1 -1
- package/esm/http/errors/errors.d.mts +30 -29
- 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 +17 -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/events.d.mts +2 -4
- package/esm/http/events.d.mts.map +1 -1
- package/esm/http/flush-pending-cookies.mjs.map +1 -1
- package/esm/http/health.d.mts +4 -4
- package/esm/http/health.d.mts.map +1 -1
- package/esm/http/index.d.mts +9 -3
- package/esm/http/index.mjs +5 -2
- package/esm/http/lazy-static.mjs +194 -0
- package/esm/http/lazy-static.mjs.map +1 -0
- package/esm/http/middleware/cache-response-middleware.d.mts +2 -4
- package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
- package/esm/http/middleware/concurrency-limit.middleware.d.mts +3 -3
- package/esm/http/middleware/concurrency-limit.middleware.d.mts.map +1 -1
- package/esm/http/middleware/idempotency.middleware.d.mts +3 -3
- package/esm/http/middleware/idempotency.middleware.d.mts.map +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs +6 -6
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/middleware/index.d.mts +3 -1
- package/esm/http/middleware/index.mjs +1 -1
- package/esm/http/middleware/inject-request-context.d.mts +2 -4
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +3 -3
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/ip-filter.middleware.d.mts +3 -3
- package/esm/http/middleware/ip-filter.middleware.d.mts.map +1 -1
- package/esm/http/middleware/maintenance.middleware.d.mts +3 -3
- package/esm/http/middleware/maintenance.middleware.d.mts.map +1 -1
- package/esm/http/middleware/maintenance.middleware.mjs +4 -4
- package/esm/http/middleware/maintenance.middleware.mjs.map +1 -1
- package/esm/http/middleware/max-body-size.middleware.d.mts +2 -2
- package/esm/http/middleware/max-body-size.middleware.d.mts.map +1 -1
- package/esm/http/middleware/middleware-list.d.mts +1 -3
- package/esm/http/middleware/middleware-list.d.mts.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.d.mts +3 -3
- package/esm/http/middleware/rate-limit.middleware.d.mts.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs +2 -2
- package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/utils/cidr-match.d.mts +2 -3
- package/esm/http/middleware/utils/cidr-match.d.mts.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.d.mts +3 -5
- package/esm/http/middleware/utils/idempotency-key.d.mts.map +1 -1
- package/esm/http/middleware/utils/index.d.mts +2 -1
- package/esm/http/middleware/utils/parse-size.d.mts +1 -2
- package/esm/http/middleware/utils/parse-size.d.mts.map +1 -1
- package/esm/http/middleware/utils/parse-size.mjs +2 -2
- package/esm/http/middleware/utils/parse-size.mjs.map +1 -1
- package/esm/http/plugins.d.mts +2 -4
- package/esm/http/plugins.d.mts.map +1 -1
- package/esm/http/plugins.mjs +17 -14
- package/esm/http/plugins.mjs.map +1 -1
- package/esm/http/port-preflight.d.mts +3 -4
- package/esm/http/port-preflight.d.mts.map +1 -1
- package/esm/http/rate-limit-cache-store.mjs +6 -4
- package/esm/http/rate-limit-cache-store.mjs.map +1 -1
- package/esm/http/ready-report.d.mts +15 -10
- package/esm/http/ready-report.d.mts.map +1 -1
- package/esm/http/request-controller.d.mts +1 -3
- package/esm/http/request-controller.d.mts.map +1 -1
- package/esm/http/request-log-snapshot.d.mts +26 -15
- package/esm/http/request-log-snapshot.d.mts.map +1 -1
- package/esm/http/request-log-snapshot.mjs +85 -6
- package/esm/http/request-log-snapshot.mjs.map +1 -1
- package/esm/http/request.d.mts +6 -5
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +13 -11
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.d.mts +23 -12
- package/esm/http/response.d.mts.map +1 -1
- package/esm/http/response.mjs +169 -81
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/safe-redirect.d.mts +50 -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 +12 -13
- package/esm/http/serialized.d.mts.map +1 -1
- package/esm/http/server-rebuilt.d.mts +3 -5
- package/esm/http/server-rebuilt.d.mts.map +1 -1
- package/esm/http/server.d.mts +11 -9
- package/esm/http/server.d.mts.map +1 -1
- package/esm/http/server.mjs +17 -7
- package/esm/http/server.mjs.map +1 -1
- package/esm/http/stream-react-response.d.mts +7 -7
- package/esm/http/stream-react-response.d.mts.map +1 -1
- package/esm/http/stream-transport.mjs +4 -2
- package/esm/http/stream-transport.mjs.map +1 -1
- package/esm/http/tracing/index.mjs +1 -1
- package/esm/http/tracing/trace-id.d.mts +2 -3
- package/esm/http/tracing/trace-id.d.mts.map +1 -1
- package/esm/http/tracing/tracing-dispatcher.d.mts +10 -11
- package/esm/http/tracing/tracing-dispatcher.d.mts.map +1 -1
- package/esm/http/tracing/tracing-dispatcher.mjs +2 -2
- package/esm/http/tracing/tracing-dispatcher.mjs.map +1 -1
- package/esm/http/tracing/tracing.type.d.mts +11 -9
- package/esm/http/tracing/tracing.type.d.mts.map +1 -1
- package/esm/http/types.d.mts +78 -39
- package/esm/http/types.d.mts.map +1 -1
- package/esm/http/uploaded-file.d.mts +6 -5
- package/esm/http/uploaded-file.d.mts.map +1 -1
- package/esm/http/uploads/generate-image-variant.mjs +1 -1
- package/esm/http/uploads/generate-image-variants.d.mts +13 -10
- package/esm/http/uploads/generate-image-variants.d.mts.map +1 -1
- package/esm/http/uploads/generate-image-variants.mjs +62 -25
- 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 +9 -9
- package/esm/http/uploads/image-variant-types.d.mts.map +1 -1
- package/esm/http/uploads/image-variants-config-error.d.mts +4 -3
- 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/index.d.mts +2 -1
- package/esm/http/uploads/index.mjs +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/parse-uploaded-file-query.mjs +1 -1
- package/esm/http/uploads/parse-uploaded-file-query.mjs.map +1 -1
- package/esm/http/uploads/purge-image-variants.d.mts +9 -6
- 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 +6 -9
- 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 +7 -5
- package/esm/http/uploads/resolve-image-variants-config.mjs.map +1 -1
- package/esm/http/uploads/resolve-original-content-type.mjs +1 -1
- package/esm/http/uploads/resolve-original-content-type.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 +9 -6
- package/esm/http/uploads/uploaded-file.controller.d.mts.map +1 -1
- package/esm/http/uploads/uploaded-file.controller.mjs +18 -9
- package/esm/http/uploads/uploaded-file.controller.mjs.map +1 -1
- package/esm/http/uploads/variant-cache-key.mjs +2 -2
- package/esm/http/uploads-config.d.mts +2 -4
- package/esm/http/uploads-config.d.mts.map +1 -1
- package/esm/http/uploads-types.d.mts +22 -16
- package/esm/http/uploads-types.d.mts.map +1 -1
- package/esm/http/xmlable.d.mts +1 -2
- package/esm/http/xmlable.d.mts.map +1 -1
- package/esm/image/image.d.mts +6 -7
- package/esm/image/image.d.mts.map +1 -1
- package/esm/image/image.mjs.map +1 -1
- package/esm/image/index.d.mts +2 -1
- package/esm/image/index.mjs +1 -1
- package/esm/index.d.mts +38 -6
- package/esm/index.mjs +14 -3
- package/esm/loader/app-module-importer.d.mts +1 -2
- package/esm/loader/app-module-importer.d.mts.map +1 -1
- package/esm/localization/index.mjs +1 -1
- package/esm/localization/parse-locale-dictionary.d.mts +6 -5
- package/esm/localization/parse-locale-dictionary.d.mts.map +1 -1
- package/esm/localization/parse-locale-dictionary.mjs +2 -1
- package/esm/localization/parse-locale-dictionary.mjs.map +1 -1
- package/esm/localization/register-locale-dictionary.d.mts +3 -4
- package/esm/localization/register-locale-dictionary.d.mts.map +1 -1
- package/esm/localization/register-locale-dictionary.mjs +2 -2
- package/esm/localization/register-locale-dictionary.mjs.map +1 -1
- package/esm/logger/fatal-visibility.d.mts +1 -2
- package/esm/logger/fatal-visibility.d.mts.map +1 -1
- package/esm/logger/index.d.mts +2 -1
- package/esm/logger/index.mjs +1 -1
- package/esm/logger/logger.d.mts +1 -3
- package/esm/logger/logger.d.mts.map +1 -1
- package/esm/logger/types.d.mts +2 -3
- package/esm/logger/types.d.mts.map +1 -1
- package/esm/mail/config.d.mts +21 -12
- 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/events.d.mts +4 -6
- package/esm/mail/events.d.mts.map +1 -1
- package/esm/mail/index.d.mts +3 -2
- package/esm/mail/index.mjs +2 -2
- package/esm/mail/mail.d.mts +1 -3
- package/esm/mail/mail.d.mts.map +1 -1
- package/esm/mail/mailer-pool.d.mts +5 -7
- package/esm/mail/mailer-pool.d.mts.map +1 -1
- package/esm/mail/react-mail.d.mts +1 -3
- package/esm/mail/react-mail.d.mts.map +1 -1
- package/esm/mail/send-mail.d.mts +1 -3
- package/esm/mail/send-mail.d.mts.map +1 -1
- package/esm/mail/send-mail.mjs +2 -1
- package/esm/mail/send-mail.mjs.map +1 -1
- package/esm/mail/test-mailbox.d.mts +11 -13
- package/esm/mail/test-mailbox.d.mts.map +1 -1
- package/esm/mail/types.d.mts +17 -18
- package/esm/mail/types.d.mts.map +1 -1
- package/esm/manifest/manifest-manager.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 +2 -4
- 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/cast-schema.mjs +1 -1
- package/esm/openapi/development-openapi-provider.d.mts +5 -6
- package/esm/openapi/development-openapi-provider.d.mts.map +1 -1
- package/esm/openapi/error-responses.mjs +28 -2
- package/esm/openapi/error-responses.mjs.map +1 -1
- package/esm/openapi/index.d.mts +3 -1
- package/esm/openapi/index.mjs +1 -1
- package/esm/openapi/openapi-child-output.mjs +2 -2
- package/esm/openapi/openapi-child-output.mjs.map +1 -1
- package/esm/openapi/postman/build-request-body.mjs.map +1 -1
- package/esm/openapi/postman/build-request-url.mjs +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 +1 -3
- 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/index.d.mts +2 -1
- package/esm/openapi/postman/openapi-to-postman-collection.d.mts +3 -5
- 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/postman-types.d.mts +19 -18
- package/esm/openapi/postman/postman-types.d.mts.map +1 -1
- package/esm/openapi/postman/schema-refs.d.mts +1 -3
- package/esm/openapi/postman/schema-refs.d.mts.map +1 -1
- package/esm/openapi/postman/schema-refs.mjs.map +1 -1
- package/esm/openapi/postman/uuid-v5.mjs +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 +1 -1
- package/esm/openapi/security.mjs.map +1 -1
- package/esm/openapi/types.d.mts +23 -20
- package/esm/openapi/types.d.mts.map +1 -1
- package/esm/production/assert-generated-imports.mjs +2 -1
- package/esm/production/assert-generated-imports.mjs.map +1 -1
- package/esm/production/build-contributions.mjs +1 -1
- package/esm/production/bundle-framework-dependencies.mjs +1 -1
- package/esm/production/dist-build-manifest.mjs +1 -1
- package/esm/production/esbuild-plugins.mjs.map +1 -1
- package/esm/production/esbuild-preflight.mjs +1 -1
- package/esm/production/production-builder.mjs +14 -5
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/production-supervisor.mjs +1 -1
- package/esm/production/registration-child-runner.mjs +4 -3
- package/esm/production/registration-child-runner.mjs.map +1 -1
- package/esm/production/resolve-build-config.d.mts +4 -4
- package/esm/production/resolve-build-config.d.mts.map +1 -1
- package/esm/production/resolve-build-config.mjs +2 -1
- package/esm/production/resolve-build-config.mjs.map +1 -1
- package/esm/production/route-registration-child.d.mts +1 -1
- package/esm/production/route-registration-child.mjs +8 -7
- package/esm/production/route-registration-child.mjs.map +1 -1
- package/esm/production/route-registration-snapshot.mjs.map +1 -1
- package/esm/production/tsconfig-path-aliases.mjs +1 -1
- package/esm/react/index.d.mts +1 -3
- package/esm/react/index.d.mts.map +1 -1
- package/esm/react/index.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-adapter.d.mts +3 -4
- package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +2 -3
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts.map +1 -1
- package/esm/repositories/adapters/cascade/filter-applicator.mjs +10 -9
- package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/index.d.mts +2 -1
- package/esm/repositories/adapters/cascade/index.mjs +1 -1
- package/esm/repositories/contracts/index.d.mts +2 -1
- package/esm/repositories/contracts/query-builder.contract.d.mts +4 -6
- package/esm/repositories/contracts/query-builder.contract.d.mts.map +1 -1
- package/esm/repositories/contracts/repository-adapter.contract.d.mts +1 -3
- package/esm/repositories/contracts/repository-adapter.contract.d.mts.map +1 -1
- package/esm/repositories/contracts/types.d.mts +23 -25
- package/esm/repositories/contracts/types.d.mts.map +1 -1
- package/esm/repositories/index.d.mts +4 -1
- package/esm/repositories/index.mjs +1 -1
- package/esm/repositories/repository.manager.d.mts +2 -3
- package/esm/repositories/repository.manager.d.mts.map +1 -1
- package/esm/repositories/repository.manager.mjs +2 -2
- package/esm/repositories/repository.manager.mjs.map +1 -1
- package/esm/resource/define-resource.d.mts +3 -5
- package/esm/resource/define-resource.d.mts.map +1 -1
- package/esm/resource/index.d.mts +2 -1
- package/esm/resource/index.mjs +1 -1
- package/esm/resource/nullable-resource.d.mts +5 -7
- package/esm/resource/nullable-resource.d.mts.map +1 -1
- package/esm/resource/register-resource.d.mts +1 -3
- package/esm/resource/register-resource.d.mts.map +1 -1
- package/esm/resource/resource-field-builder.d.mts +1 -3
- package/esm/resource/resource-field-builder.d.mts.map +1 -1
- package/esm/resource/resource.d.mts +3 -5
- package/esm/resource/resource.d.mts.map +1 -1
- package/esm/resource/resource.mjs +4 -2
- package/esm/resource/resource.mjs.map +1 -1
- package/esm/resource/types.d.mts +21 -21
- package/esm/resource/types.d.mts.map +1 -1
- package/esm/restful/index.d.mts +2 -1
- package/esm/restful/index.mjs +1 -1
- package/esm/restful/restful.d.mts +11 -31
- 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 +5 -2
- package/esm/router/index.mjs +3 -1
- package/esm/router/log-request-lifecycle.mjs.map +1 -1
- package/esm/router/named-api-routes-with-responses.mjs +2 -1
- package/esm/router/named-api-routes-with-responses.mjs.map +1 -1
- package/esm/router/normalize-request-path.d.mts +1 -2
- package/esm/router/normalize-request-path.d.mts.map +1 -1
- package/esm/router/normalize-route-path.d.mts +1 -2
- package/esm/router/normalize-route-path.d.mts.map +1 -1
- package/esm/router/positional-handler-diagnostics.d.mts +15 -13
- 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-builder.d.mts +1 -3
- package/esm/router/route-builder.d.mts.map +1 -1
- package/esm/router/route-guard-names.mjs +30 -0
- package/esm/router/route-guard-names.mjs.map +1 -0
- package/esm/router/route-name-method-suffix.d.mts +2 -3
- package/esm/router/route-name-method-suffix.d.mts.map +1 -1
- package/esm/router/route-name-taken-error.d.mts +12 -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/route-registry.d.mts +1 -3
- package/esm/router/route-registry.d.mts.map +1 -1
- package/esm/router/router.d.mts +34 -17
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +74 -39
- package/esm/router/router.mjs.map +1 -1
- package/esm/router/types.d.mts +156 -37
- package/esm/router/types.d.mts.map +1 -1
- package/esm/router/unguarded-route-diagnostics.d.mts +38 -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/socket/index.d.mts +2 -1
- package/esm/socket/index.mjs +1 -1
- package/esm/socket/types.d.mts +2 -4
- package/esm/socket/types.d.mts.map +1 -1
- package/esm/socket/utils.d.mts +1 -3
- package/esm/socket/utils.d.mts.map +1 -1
- package/esm/storage/config.d.mts +4 -6
- package/esm/storage/config.d.mts.map +1 -1
- package/esm/storage/context/storage-driver-context.d.mts +3 -4
- package/esm/storage/context/storage-driver-context.d.mts.map +1 -1
- package/esm/storage/drivers/cloud-driver.d.mts +2 -4
- 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/do-spaces-driver.d.mts +1 -3
- package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
- package/esm/storage/drivers/local-driver.d.mts +2 -3
- package/esm/storage/drivers/local-driver.d.mts.map +1 -1
- package/esm/storage/drivers/local-driver.mjs +8 -3
- package/esm/storage/drivers/local-driver.mjs.map +1 -1
- package/esm/storage/drivers/r2-driver.d.mts +1 -3
- package/esm/storage/drivers/r2-driver.d.mts.map +1 -1
- package/esm/storage/drivers/s3-driver.d.mts +1 -3
- package/esm/storage/drivers/s3-driver.d.mts.map +1 -1
- package/esm/storage/index.d.mts +2 -1
- package/esm/storage/index.mjs +1 -1
- package/esm/storage/local-disk-roots.mjs +24 -0
- package/esm/storage/local-disk-roots.mjs.map +1 -0
- package/esm/storage/scoped-storage.d.mts +2 -3
- package/esm/storage/scoped-storage.d.mts.map +1 -1
- package/esm/storage/storage-file.d.mts +1 -3
- package/esm/storage/storage-file.d.mts.map +1 -1
- package/esm/storage/storage.d.mts +17 -4
- 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 +36 -36
- package/esm/storage/types.d.mts.map +1 -1
- package/esm/storage/utils/classify-ip-address.d.mts +1 -2
- package/esm/storage/utils/classify-ip-address.d.mts.map +1 -1
- package/esm/storage/utils/contain-path.d.mts +1 -2
- package/esm/storage/utils/contain-path.d.mts.map +1 -1
- package/esm/storage/utils/mime.d.mts +2 -3
- package/esm/storage/utils/mime.d.mts.map +1 -1
- package/esm/storage/utils/safe-fetch.d.mts +6 -6
- package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
- package/esm/storage/utils/safe-fetch.mjs +3 -3
- package/esm/storage/utils/safe-fetch.mjs.map +1 -1
- package/esm/storage/utils/storage-capability-error.d.mts +1 -3
- package/esm/storage/utils/storage-capability-error.d.mts.map +1 -1
- package/esm/storage/utils/storage-error.d.mts +2 -3
- package/esm/storage/utils/storage-error.d.mts.map +1 -1
- package/esm/storage/utils/storage-not-initialized-error.d.mts +3 -2
- 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 +31 -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 +74 -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 +34 -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 +37 -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 +12 -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 +23 -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 +9 -0
- package/esm/tests/fakes/index.mjs +10 -0
- package/esm/tests/fakes/mail-fake.d.mts +49 -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 +56 -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 +35 -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 +38 -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 +15 -2
- package/esm/tests/index.mjs +15 -2
- package/esm/tests/snapshot-response.d.mts +33 -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 +25 -5
- package/esm/tests/start-http-development-server.d.mts.map +1 -1
- package/esm/tests/start-http-development-server.mjs +41 -8
- package/esm/tests/start-http-development-server.mjs.map +1 -1
- package/esm/tests/test-connectors-selection.d.mts +2 -2
- package/esm/tests/test-connectors-selection.d.mts.map +1 -1
- package/esm/tests/test-connectors-selection.mjs +1 -1
- package/esm/tests/test-helpers.d.mts +28 -10
- 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 +66 -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/test-lifecycle-state.mjs +1 -1
- package/esm/tests/vitest-setup.d.mts +17 -7
- 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 +26 -0
- package/esm/tooling/agents-md/agents-md-markers.d.mts.map +1 -0
- package/esm/tooling/agents-md/agents-md-markers.mjs +60 -0
- package/esm/tooling/agents-md/agents-md-markers.mjs.map +1 -0
- package/esm/tooling/agents-md/agents-md-refresher.d.mts +43 -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 +34 -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 +34 -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 +38 -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 +29 -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 +121 -0
- package/esm/tooling/board/board.d.mts.map +1 -0
- package/esm/tooling/board/board.mjs +407 -0
- package/esm/tooling/board/board.mjs.map +1 -0
- package/esm/tooling/board/board.types.d.mts +81 -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 +31 -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 +67 -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 +32 -0
- package/esm/tooling/check/conventions-step.d.mts.map +1 -0
- package/esm/tooling/check/conventions-step.mjs +173 -0
- package/esm/tooling/check/conventions-step.mjs.map +1 -0
- package/esm/tooling/check/environment-step.d.mts +16 -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.mjs +10 -0
- package/esm/tooling/check/lint-step.d.mts +18 -0
- package/esm/tooling/check/lint-step.d.mts.map +1 -0
- package/esm/tooling/check/lint-step.mjs +112 -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 +43 -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 +55 -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 +650 -0
- package/esm/tooling/check/security-conventions.mjs.map +1 -0
- package/esm/tooling/check/source-ast.mjs +155 -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 +33 -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 +43 -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 +100 -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 +90 -0
- package/esm/tooling/generate/generation.d.mts.map +1 -0
- package/esm/tooling/generate/generation.mjs +127 -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 +43 -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 +40 -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 +42 -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 +10 -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 +9 -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 +8 -0
- package/esm/tooling/inspect/index.mjs +7 -0
- package/esm/tooling/inspect/inspect-app.d.mts +62 -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 +14 -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 +228 -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 +29 -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 +50 -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 +77 -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 +61 -0
- package/esm/tooling/mcp/load-ai-tools.d.mts.map +1 -0
- package/esm/tooling/mcp/load-ai-tools.mjs +45 -0
- package/esm/tooling/mcp/load-ai-tools.mjs.map +1 -0
- package/esm/tooling/mcp/mcp-tools.d.mts +70 -0
- package/esm/tooling/mcp/mcp-tools.d.mts.map +1 -0
- package/esm/tooling/mcp/mcp-tools.mjs +514 -0
- package/esm/tooling/mcp/mcp-tools.mjs.map +1 -0
- package/esm/tooling/mcp/start-mcp-server.d.mts +63 -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 +55 -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/syntax/ast.mjs +230 -0
- package/esm/tooling/syntax/ast.mjs.map +1 -0
- package/esm/tooling/syntax/imports.mjs +34 -0
- package/esm/tooling/syntax/imports.mjs.map +1 -0
- package/esm/tooling/trace/trace-report.types.d.mts +85 -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 +90 -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.mjs +3 -0
- package/esm/tooling/typecheck/run-typecheck.d.mts +26 -0
- package/esm/tooling/typecheck/run-typecheck.d.mts.map +1 -0
- package/esm/tooling/typecheck/run-typecheck.mjs +90 -0
- package/esm/tooling/typecheck/run-typecheck.mjs.map +1 -0
- package/esm/tooling/typescript/compiler.d.mts +31 -0
- package/esm/tooling/typescript/compiler.d.mts.map +1 -0
- package/esm/tooling/typescript/compiler.mjs +120 -0
- package/esm/tooling/typescript/compiler.mjs.map +1 -0
- package/esm/updater/update-warlock-packages.mjs +3 -2
- package/esm/updater/update-warlock-packages.mjs.map +1 -1
- 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 +49 -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/index.d.mts +2 -1
- package/esm/use-cases/index.mjs +1 -1
- package/esm/use-cases/types.d.mts +116 -63
- package/esm/use-cases/types.d.mts.map +1 -1
- package/esm/use-cases/use-case-broadcast.d.mts +1 -3
- package/esm/use-cases/use-case-broadcast.d.mts.map +1 -1
- package/esm/use-cases/use-case-events.d.mts +3 -5
- package/esm/use-cases/use-case-events.d.mts.map +1 -1
- package/esm/use-cases/use-case-pipeline.d.mts +6 -6
- package/esm/use-cases/use-case-pipeline.d.mts.map +1 -1
- package/esm/use-cases/use-case.d.mts +2 -4
- package/esm/use-cases/use-case.d.mts.map +1 -1
- package/esm/use-cases/use-case.errors.d.mts +1 -3
- package/esm/use-cases/use-case.errors.d.mts.map +1 -1
- package/esm/use-cases/use-cases-registry.d.mts +8 -10
- package/esm/use-cases/use-cases-registry.d.mts.map +1 -1
- package/esm/use-cases/use-cases-registry.mjs.map +1 -1
- package/esm/utils/app-log.d.mts +1 -2
- package/esm/utils/app-log.d.mts.map +1 -1
- package/esm/utils/clock.d.mts +35 -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/database-log.d.mts +3 -4
- package/esm/utils/database-log.d.mts.map +1 -1
- package/esm/utils/environment.d.mts +4 -5
- package/esm/utils/environment.d.mts.map +1 -1
- package/esm/utils/framework-vesion.mjs +1 -1
- package/esm/utils/framework-vesion.mjs.map +1 -1
- package/esm/utils/get-localized.d.mts +2 -3
- package/esm/utils/get-localized.d.mts.map +1 -1
- package/esm/utils/ids.d.mts +35 -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 +5 -1
- package/esm/utils/index.mjs +4 -1
- package/esm/utils/normalized-path.d.mts +1 -2
- package/esm/utils/normalized-path.d.mts.map +1 -1
- package/esm/utils/npm-registry.d.mts +1 -2
- package/esm/utils/npm-registry.d.mts.map +1 -1
- package/esm/utils/paths.d.mts +13 -14
- package/esm/utils/paths.d.mts.map +1 -1
- package/esm/utils/paths.mjs +2 -2
- package/esm/utils/paths.mjs.map +1 -1
- package/esm/utils/promise-all-object.d.mts +1 -2
- package/esm/utils/promise-all-object.d.mts.map +1 -1
- package/esm/utils/queue.d.mts +1 -2
- package/esm/utils/queue.d.mts.map +1 -1
- package/esm/utils/runtime.d.mts +60 -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/utils/sleep.d.mts +1 -2
- package/esm/utils/sleep.d.mts.map +1 -1
- package/esm/utils/sluggable.d.mts +1 -3
- package/esm/utils/sluggable.d.mts.map +1 -1
- package/esm/utils/to-json.d.mts +1 -2
- package/esm/utils/to-json.d.mts.map +1 -1
- package/esm/utils/types.d.mts +1 -2
- package/esm/utils/types.d.mts.map +1 -1
- package/esm/utils/urls.d.mts +5 -6
- package/esm/utils/urls.d.mts.map +1 -1
- package/esm/utils/version-compare.d.mts +1 -2
- package/esm/utils/version-compare.d.mts.map +1 -1
- package/esm/validation/database/exists-except-current-id.d.mts +2 -3
- package/esm/validation/database/exists-except-current-id.d.mts.map +1 -1
- package/esm/validation/database/exists-except-current-user.d.mts +2 -3
- package/esm/validation/database/exists-except-current-user.d.mts.map +1 -1
- package/esm/validation/database/index.d.mts +2 -1
- package/esm/validation/database/index.mjs +1 -1
- package/esm/validation/database/types.d.mts +14 -10
- package/esm/validation/database/types.d.mts.map +1 -1
- package/esm/validation/database/unique-except-current-id.d.mts +2 -3
- package/esm/validation/database/unique-except-current-id.d.mts.map +1 -1
- package/esm/validation/database/unique-except-current-user.d.mts +2 -3
- package/esm/validation/database/unique-except-current-user.d.mts.map +1 -1
- package/esm/validation/file/file.d.mts +4 -6
- package/esm/validation/file/file.d.mts.map +1 -1
- package/esm/validation/file/index.d.mts +2 -1
- package/esm/validation/file/index.mjs +1 -1
- package/esm/validation/index.d.mts +6 -2
- package/esm/validation/index.mjs +1 -1
- package/esm/validation/plugins/index.mjs +1 -1
- package/esm/validation/types.d.mts +61 -4
- package/esm/validation/types.d.mts.map +1 -1
- package/esm/validation/validateAll.mjs +21 -4
- 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 +2 -20
- package/esm/validation/validators/file-validator.d.mts.map +1 -1
- package/esm/validation/validators/index.d.mts +2 -1
- package/esm/validation/validators/index.mjs +1 -1
- package/esm/vite/lower-stage3-decorators.d.mts +2 -3
- package/esm/vite/lower-stage3-decorators.d.mts.map +1 -1
- package/esm/warlock-config/bundle-config.mjs +1 -1
- package/esm/warlock-config/define-config.d.mts +1 -3
- package/esm/warlock-config/define-config.d.mts.map +1 -1
- package/esm/warlock-config/define-config.mjs +3 -2
- package/esm/warlock-config/define-config.mjs.map +1 -1
- package/esm/warlock-config/index.d.mts +2 -1
- package/esm/warlock-config/index.mjs +1 -1
- package/esm/warlock-config/types.d.mts +31 -6
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/esm/warlock-config/warlock-config.manager.d.mts +5 -7
- package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
- package/esm/warlock-config/warlock-config.manager.mjs +2 -1
- package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
- package/esm/warlock-config/warn-deprecated-config.mjs +1 -1
- package/llms-full.txt +3211 -731
- package/llms.txt +16 -6
- package/package.json +47 -15
- 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 +10 -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 +11 -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/report-framework-issue.md +154 -0
- 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 +107 -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 +454 -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 +133 -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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-image-variants.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/generate-image-variants.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { storage } from \"../../storage\";\nimport { HttpError } from \"../errors\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport type { ImageVariantOutputFormat } from \"../uploads-types\";\nimport { generateImageVariant } from \"./generate-image-variant\";\nimport {\n pruneStaleVariantGenerationsIfCurrent,\n retryOnVanishedDirectory,\n warnIfVariantCacheIsPublic,\n} from \"./image-variant-cache\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport type {\n GeneratedImageDescriptor,\n GeneratedImageVariant,\n VariantOutputFormat,\n} from \"./image-variant-types\";\nimport { loadVariantSource } from \"./load-variant-source\";\nimport { resolveImageVariantsConfig } from \"./resolve-image-variants-config\";\nimport { resolveVariantCandidate } from \"./resolve-variant-candidate\";\nimport {\n variantCacheKey,\n variantCachePath,\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\nimport { variantGenerations } from \"./variant-generations\";\n\n/**\n * Options for `generateImageVariants`\n */\nexport type GenerateImageVariantsOptions = {\n /**\n * Limit generation to these variant names, instead of every variant in\n * `uploads.images.variants`.\n */\n variants?: readonly string[];\n};\n\nasync function exists(target: string): Promise<boolean> {\n try {\n await fs.access(target);\n\n return true;\n } catch {\n return false;\n }\n}\n\nfunction encodeUploadsPath(relativePath: string): string {\n return relativePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nfunction variantUrl(src: string, name: string, format?: VariantOutputFormat): string {\n const query = format\n ? `variant=${encodeURIComponent(name)}&format=${format}`\n : `variant=${encodeURIComponent(name)}`;\n\n return `${src}?${query}`;\n}\n\nasync function readDerivativeDimensions(\n target: string,\n): Promise<{ width: number; height: number }> {\n const derivative = new Image(await fs.readFile(target));\n const { width, height } = await derivative.metadata();\n\n return { width: width ?? 0, height: height ?? 0 };\n}\n\n/**\n * Every distinct format a variant is rendered in: the source format plus\n * whatever `uploads.images.formats` adds, with duplicates dropped so a format\n * that is both the source format and an allowed format is generated once.\n */\nfunction outputFormatsFor(\n sourceFormat: VariantOutputFormat,\n configuredFormats: readonly ImageVariantOutputFormat[],\n): VariantOutputFormat[] {\n return [...new Set<VariantOutputFormat>([sourceFormat, ...configuredFormats])];\n}\n\n/**\n * Render every configured variant of one uploaded image, right after it is\n * saved.\n *\n * Uses the exact same normalized config (`uploads.images`), cache key and\n * derivative path as `uploadedFileController`, so a variant generated here is\n * already on disk the first time `GET /uploads/<path>?variant=<name>` is\n * requested — no second render. `variantGenerations` (the single-flight used\n * by the route) is reused, so a concurrent request for a variant this call is\n * still generating joins the same run instead of starting a second one.\n *\n * The returned descriptor is plain JSON, safe to store next to the record\n * that owns the image, or to carry through loader data. On local storage the\n * `url`/`urls` already point at `uploadedFileController`; an app serving\n * uploads from object storage or a CDN should not proxy the remote files\n * through this route at all — store the descriptor once generation runs\n * against the same bucket the CDN serves from, or resolve its URLs through a\n * custom `ImageLoader` on the client instead.\n *\n * @param relativePath - path of the saved upload, relative to the storage root\n * @param options.variants - limit generation to these variant names\n * @throws ImageVariantsConfigError when there is no local storage root, or\n * `uploads.images` is not configured — both are server misconfiguration, not\n * a bad request\n * @throws HttpError(400) when a name in `options.variants` is not declared in\n * `uploads.images.variants`\n * @throws HttpError(404) when `relativePath` does not resolve to a file\n * inside the storage root\n * @throws HttpError(413) when the source is over `maxSourceBytes` or\n * `maxSourcePixels`\n * @throws HttpError(415) when the source is not jpeg, png, webp or avif\n */\nexport async function generateImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions = {},\n): Promise<GeneratedImageDescriptor> {\n const storageRoot = storage.root();\n\n if (!storageRoot || storageRoot === \".\") {\n throw new ImageVariantsConfigError(\n \"generateImageVariants needs a local storage driver with a root.\",\n );\n }\n\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), storageRoot);\n\n if (!images) {\n throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n }\n\n const names = options.variants ?? Object.keys(images.variants);\n\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name)) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n }\n\n const candidate = await resolveVariantCandidate(relativePath, storageRoot, images);\n\n if (!candidate) {\n throw new HttpError(404, \"File Not Found\");\n }\n\n const { source, stats, sourceFormat } = candidate;\n\n const image = await loadVariantSource(source.absolutePath, {\n maxSourceBytes: images.maxSourceBytes,\n maxSourcePixels: images.maxSourcePixels,\n expectedFormat: sourceFormat,\n });\n\n const { width: sourceWidth, height: sourceHeight } = await image.metadata();\n warnIfVariantCacheIsPublic(images.cacheDirectory);\n\n const src = `/uploads/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n\n for (const name of names) {\n const variant = images.variants[name];\n if (variant === undefined) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const formats = outputFormatsFor(sourceFormat, images.formats);\n let dimensions: { width: number; height: number } | undefined;\n\n for (const format of formats) {\n const hash = variantCacheKey({\n relativePath: source.relativePath,\n sourceSize: stats.size,\n sourceMtimeMs: stats.mtimeMs,\n variant,\n format,\n });\n const sourceKey = variantSourceKey(source.root, source.relativePath);\n const generation = variantGenerationTag(stats.size, stats.mtimeMs);\n const target = variantCachePath(\n images.cacheDirectory,\n { sourceKey, generation },\n hash,\n format,\n );\n\n if (!(await exists(target))) {\n // keyed on the target, which includes the disk root (see resolveImageVariant)\n await variantGenerations.run(target, async () => {\n if (await exists(target)) return;\n\n await retryOnVanishedDirectory(() =>\n generateImageVariant({ image: image.clone(), variant, format, targetPath: target }),\n );\n await pruneStaleVariantGenerationsIfCurrent(\n source.absolutePath,\n variantSourceDirectory(images.cacheDirectory, sourceKey),\n generation,\n );\n });\n }\n\n if (dimensions === undefined) {\n dimensions = await readDerivativeDimensions(target);\n }\n }\n\n const urls: Partial<Record<ImageVariantOutputFormat, string>> = {};\n\n for (const format of images.formats) {\n urls[format] = variantUrl(src, name, format);\n }\n\n variants[name] = {\n width: dimensions?.width ?? variant.width,\n height:\n dimensions?.height ??\n variant.height ??\n Math.round(variant.width * ((sourceHeight ?? 1) / (sourceWidth ?? 1))),\n url: variantUrl(src, name),\n ...(Object.keys(urls).length > 0 ? { urls } : {}),\n };\n }\n\n return {\n src,\n width: sourceWidth ?? 0,\n height: sourceHeight ?? 0,\n variants,\n ...(images.formats.length > 0 ? { formats: images.formats } : {}),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate-image-variants.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/generate-image-variants.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport type { StorageDriverName } from \"../../storage/types\";\nimport { localDiskRoot } from \"./local-disk-root\";\nimport { remoteVariantDisk, remoteVariantSource } from \"./remote-variant-source\";\nimport { renderRemoteImageVariant } from \"./resolve-remote-image-variant\";\nimport { HttpError } from \"../errors\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport type { ImageVariantOutputFormat } from \"../uploads-types\";\nimport { generateImageVariant } from \"./generate-image-variant\";\nimport {\n pruneStaleVariantGenerationsIfCurrent,\n retryOnVanishedDirectory,\n warnIfVariantCacheIsPublic,\n} from \"./image-variant-cache\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport type {\n GeneratedImageDescriptor,\n GeneratedImageVariant,\n VariantOutputFormat,\n} from \"./image-variant-types\";\nimport { loadVariantSource } from \"./load-variant-source\";\nimport { resolveImageVariantsConfig } from \"./resolve-image-variants-config\";\nimport { resolveVariantCandidate } from \"./resolve-variant-candidate\";\nimport {\n variantCacheKey,\n variantCachePath,\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\nimport { freshImageVariant, scheduleImageVariantCacheTrim } from \"./trim-image-variant-cache\";\nimport { variantGenerations } from \"./variant-generations\";\n\n/**\n * Options for `generateImageVariants`\n */\nexport type GenerateImageVariantsOptions = {\n /**\n * Limit generation to these variant names, instead of every variant in\n * `uploads.images.variants`.\n */\n variants?: readonly string[];\n\n /** Disk holding the source; defaults to the active disk. */\n disk?: StorageDriverName;\n\n /** Route prefix serving variants of this disk (and originals for local disks). Default /uploads. */\n urlPrefix?: string;\n};\n\nfunction encodeUploadsPath(relativePath: string): string {\n return relativePath.split(\"/\").map(encodeURIComponent).join(\"/\");\n}\n\nfunction variantUrl(src: string, name: string, format?: VariantOutputFormat): string {\n const query = format\n ? `variant=${encodeURIComponent(name)}&format=${format}`\n : `variant=${encodeURIComponent(name)}`;\n\n return `${src}?${query}`;\n}\n\nasync function readDerivativeDimensions(\n target: string,\n): Promise<{ width: number; height: number }> {\n const derivative = new Image(await fs.readFile(target));\n const { width, height } = await derivative.metadata();\n\n return { width: width ?? 0, height: height ?? 0 };\n}\n\n/**\n * Every distinct format a variant is rendered in: the source format plus\n * whatever `uploads.images.formats` adds, with duplicates dropped so a format\n * that is both the source format and an allowed format is generated once.\n */\nfunction outputFormatsFor(\n sourceFormat: VariantOutputFormat,\n configuredFormats: readonly ImageVariantOutputFormat[],\n): VariantOutputFormat[] {\n return [...new Set<VariantOutputFormat>([sourceFormat, ...configuredFormats])];\n}\n\n/**\n * Render every configured variant of one uploaded image, right after it is\n * saved.\n *\n * Uses the exact same normalized config (`uploads.images`), cache key and\n * derivative path as `uploadedFileController`, so a variant generated here is\n * already on disk the first time `GET /uploads/<path>?variant=<name>` is\n * requested — no second render. `variantGenerations` (the single-flight used\n * by the route) is reused, so a concurrent request for a variant this call is\n * still generating joins the same run instead of starting a second one.\n *\n * The returned descriptor is plain JSON, safe to store next to the record\n * that owns the image, or to carry through loader data. On local storage the\n * `url`/`urls` already point at `uploadedFileController`; an app serving\n * uploads from object storage use the driver URL for the original, and\n * `options.urlPrefix` for the route serving locally cached derivatives.\n * Ingest downloads a remote source once for all variants and formats.\n * On-demand cache hits use ETag metadata; sources without ETags are hashed.\n *\n * @param relativePath - path of the saved upload, relative to the storage root\n * @param options.variants - limit generation to these variant names\n * @throws ImageVariantsConfigError when `uploads.images` is not\n * configured — this is server misconfiguration, not\n * a bad request\n * @throws HttpError(400) when a name in `options.variants` is not declared in\n * `uploads.images.variants`\n * @throws HttpError(404) when `relativePath` does not resolve to a file\n * inside the storage root\n * @throws HttpError(413) when the source is over `maxSourceBytes` or\n * `maxSourcePixels`\n * @throws HttpError(415) when the source is not jpeg, png, webp or avif\n */\nexport async function generateImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions = {},\n): Promise<GeneratedImageDescriptor> {\n const storageRoot = localDiskRoot(options.disk);\n\n if (!storageRoot) return generateRemoteImageVariants(relativePath, options);\n\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), storageRoot);\n\n if (!images) {\n throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n }\n\n const names = options.variants ?? Object.keys(images.variants);\n\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name)) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n }\n\n const candidate = await resolveVariantCandidate(relativePath, storageRoot, images);\n\n if (!candidate) {\n throw new HttpError(404, \"File Not Found\");\n }\n\n const { source, stats, sourceFormat } = candidate;\n\n const image = await loadVariantSource(source.absolutePath, {\n maxSourceBytes: images.maxSourceBytes,\n maxSourcePixels: images.maxSourcePixels,\n expectedFormat: sourceFormat,\n });\n\n const { width: sourceWidth, height: sourceHeight } = await image.metadata();\n warnIfVariantCacheIsPublic(images.cacheDirectory);\n\n const src = `${(options.urlPrefix ?? \"/uploads\").replace(/\\/$/, \"\")}/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n\n for (const name of names) {\n const variant = images.variants[name];\n if (variant === undefined) {\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const formats = outputFormatsFor(sourceFormat, images.formats);\n let dimensions: { width: number; height: number } | undefined;\n\n for (const format of formats) {\n const hash = variantCacheKey({\n relativePath: source.relativePath,\n sourceSize: stats.size,\n sourceMtimeMs: stats.mtimeMs,\n variant,\n format,\n });\n const sourceKey = variantSourceKey(source.root, source.relativePath);\n const generation = variantGenerationTag(stats.size, stats.mtimeMs);\n const target = variantCachePath(\n images.cacheDirectory,\n { sourceKey, generation },\n hash,\n format,\n );\n\n if (!(await freshImageVariant(target, images.maxCacheAge))) {\n // keyed on the target, which includes the disk root (see resolveImageVariant)\n await variantGenerations.run(target, async () => {\n if (await freshImageVariant(target, images.maxCacheAge)) return;\n\n await retryOnVanishedDirectory(() =>\n generateImageVariant({ image: image.clone(), variant, format, targetPath: target }),\n );\n scheduleImageVariantCacheTrim(images, target);\n await pruneStaleVariantGenerationsIfCurrent(\n source.absolutePath,\n variantSourceDirectory(images.cacheDirectory, sourceKey),\n generation,\n );\n });\n }\n\n if (dimensions === undefined) {\n dimensions = await readDerivativeDimensions(target);\n }\n }\n\n const urls: Partial<Record<ImageVariantOutputFormat, string>> = {};\n\n for (const format of images.formats) {\n urls[format] = variantUrl(src, name, format);\n }\n\n variants[name] = {\n width: dimensions?.width ?? variant.width,\n height:\n dimensions?.height ??\n variant.height ??\n Math.round(variant.width * ((sourceHeight ?? 1) / (sourceWidth ?? 1))),\n url: variantUrl(src, name),\n ...(Object.keys(urls).length > 0 ? { urls } : {}),\n };\n }\n\n return {\n src,\n width: sourceWidth ?? 0,\n height: sourceHeight ?? 0,\n variants,\n ...(images.formats.length > 0 ? { formats: images.formats } : {}),\n };\n}\n\nasync function generateRemoteImageVariants(\n relativePath: string,\n options: GenerateImageVariantsOptions,\n): Promise<GeneratedImageDescriptor> {\n const disk = remoteVariantDisk(options.disk);\n const images = resolveImageVariantsConfig(uploadsConfig(\"images\"), disk.cacheRoot);\n if (!images) throw new ImageVariantsConfigError(\"uploads.images is not configured.\");\n const names = options.variants ?? Object.keys(images.variants);\n for (const name of names) {\n if (!Object.prototype.hasOwnProperty.call(images.variants, name))\n throw new HttpError(400, `Unknown variant \"${name}\".`);\n }\n const source = await remoteVariantSource(relativePath, disk, images);\n if (!source) throw new HttpError(404, \"File Not Found\");\n try {\n const { image, sourceFormat } = await source.load();\n const { width, height } = await image.metadata();\n const variantSrc = `${(options.urlPrefix ?? \"/uploads\").replace(/\\/$/, \"\")}/${encodeUploadsPath(source.relativePath)}`;\n const variants: Record<string, GeneratedImageVariant> = {};\n for (const name of names) {\n let dimensions: { width: number; height: number } | undefined;\n for (const format of outputFormatsFor(sourceFormat, images.formats)) {\n const resolved = await renderRemoteImageVariant(\n {\n path: relativePath,\n variant: name,\n ...(format === sourceFormat ? {} : { format }),\n },\n disk,\n images,\n source,\n );\n if (!resolved) throw new HttpError(404, \"File Not Found\");\n dimensions ??= await readDerivativeDimensions(resolved.absolutePath);\n }\n variants[name] = {\n width: dimensions?.width ?? 0,\n height: dimensions?.height ?? 0,\n url: variantUrl(variantSrc, name),\n ...(images.formats.length\n ? {\n urls: Object.fromEntries(\n images.formats.map((format) => [format, variantUrl(variantSrc, name, format)]),\n ),\n }\n : {}),\n };\n }\n return {\n src: disk.driver.url(source.relativePath),\n width: width ?? 0,\n height: height ?? 0,\n variants,\n ...(images.formats.length ? { formats: images.formats } : {}),\n };\n } finally {\n source.release();\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
|
|
4
|
+
//#region ../../packages/core/src/http/uploads/image-variant-cache-entries.ts
|
|
5
|
+
const SHARD = /^[a-f0-9]{2}$/;
|
|
6
|
+
const SOURCE = /^[a-f0-9]{64}$/;
|
|
7
|
+
const GENERATION = /^(?:\d+--?\d+|[a-f0-9]{64})$/;
|
|
8
|
+
const DERIVATIVE = /^[a-f0-9]{64}\.(?:jpg|png|webp|avif)$/;
|
|
9
|
+
const TEMPORARY = /^(?:[a-f0-9]{64}\.(?:jpg|png|webp|avif)\.tmp-[a-f0-9]{16}|\.source\.json\.[a-f0-9]{12}\.tmp)$/;
|
|
10
|
+
async function entries(directory) {
|
|
11
|
+
try {
|
|
12
|
+
return await fs.readdir(directory, { withFileTypes: true });
|
|
13
|
+
} catch (error) {
|
|
14
|
+
if (error.code === "ENOENT") return [];
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Recognize only generation directories and files emitted by the image writers; never traverse symlinks. */
|
|
19
|
+
async function* variantSourceCacheGenerations(sourceDirectory, keepGeneration) {
|
|
20
|
+
try {
|
|
21
|
+
for (const directory of [path.dirname(sourceDirectory), sourceDirectory]) if (!(await fs.lstat(directory)).isDirectory()) return;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error.code === "ENOENT") return;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
for (const generation of await entries(sourceDirectory)) {
|
|
27
|
+
if (generation.name === keepGeneration || !generation.isDirectory() || !GENERATION.test(generation.name)) continue;
|
|
28
|
+
const directory = path.join(sourceDirectory, generation.name);
|
|
29
|
+
const found = [];
|
|
30
|
+
for (const file of await entries(directory)) {
|
|
31
|
+
if (!file.isFile()) continue;
|
|
32
|
+
const type = DERIVATIVE.test(file.name) ? "derivative" : file.name === "source.json" ? "manifest" : TEMPORARY.test(file.name) ? "temporary" : void 0;
|
|
33
|
+
if (type) found.push({
|
|
34
|
+
target: path.join(directory, file.name),
|
|
35
|
+
type
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
yield {
|
|
39
|
+
directory,
|
|
40
|
+
entries: found
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Every directory component must match the generated cache layout. */
|
|
45
|
+
async function* variantCacheGenerations(cacheDirectory) {
|
|
46
|
+
for (const shard of await entries(cacheDirectory)) {
|
|
47
|
+
if (!shard.isDirectory() || !SHARD.test(shard.name)) continue;
|
|
48
|
+
const directory = path.join(cacheDirectory, shard.name);
|
|
49
|
+
for (const source of await entries(directory)) {
|
|
50
|
+
if (!source.isDirectory() || !SOURCE.test(source.name) || !source.name.startsWith(shard.name)) continue;
|
|
51
|
+
yield* variantSourceCacheGenerations(path.join(directory, source.name));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function* flatten(generations) {
|
|
56
|
+
for await (const generation of generations) yield* generation.entries;
|
|
57
|
+
}
|
|
58
|
+
/** Recognized files of one source's generations, optionally skipping the `keepGeneration` directory. */
|
|
59
|
+
function variantSourceCacheEntries(sourceDirectory, keepGeneration) {
|
|
60
|
+
return flatten(variantSourceCacheGenerations(sourceDirectory, keepGeneration));
|
|
61
|
+
}
|
|
62
|
+
/** Recognized files of every source in the cache. */
|
|
63
|
+
function variantCacheEntries(cacheDirectory) {
|
|
64
|
+
return flatten(variantCacheGenerations(cacheDirectory));
|
|
65
|
+
}
|
|
66
|
+
/** Keep directories in place so removing cache data cannot remove user folders. */
|
|
67
|
+
async function purgeVariantCacheEntries(entries) {
|
|
68
|
+
let removed = false;
|
|
69
|
+
for await (const entry of entries) {
|
|
70
|
+
await fs.rm(entry.target, { force: true });
|
|
71
|
+
removed = true;
|
|
72
|
+
}
|
|
73
|
+
return removed;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { purgeVariantCacheEntries, variantCacheEntries, variantCacheGenerations, variantSourceCacheEntries, variantSourceCacheGenerations };
|
|
78
|
+
//# sourceMappingURL=image-variant-cache-entries.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-variant-cache-entries.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache-entries.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst SHARD = /^[a-f0-9]{2}$/;\nconst SOURCE = /^[a-f0-9]{64}$/;\nconst GENERATION = /^(?:\\d+--?\\d+|[a-f0-9]{64})$/;\nconst DERIVATIVE = /^[a-f0-9]{64}\\.(?:jpg|png|webp|avif)$/;\nconst TEMPORARY =\n /^(?:[a-f0-9]{64}\\.(?:jpg|png|webp|avif)\\.tmp-[a-f0-9]{16}|\\.source\\.json\\.[a-f0-9]{12}\\.tmp)$/;\n\nexport type VariantCacheEntry = {\n target: string;\n type: \"derivative\" | \"manifest\" | \"temporary\";\n};\n\n/** One generation-shaped directory (a real directory, never a symlink) and its recognized files. */\nexport type VariantCacheGeneration = {\n directory: string;\n entries: VariantCacheEntry[];\n};\n\nasync function entries(directory: string) {\n try {\n return await fs.readdir(directory, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw error;\n }\n}\n\n/** Recognize only generation directories and files emitted by the image writers; never traverse symlinks. */\nexport async function* variantSourceCacheGenerations(\n sourceDirectory: string,\n keepGeneration?: string,\n): AsyncGenerator<VariantCacheGeneration> {\n try {\n // Checking the final component alone still follows a symlinked shard.\n for (const directory of [path.dirname(sourceDirectory), sourceDirectory]) {\n if (!(await fs.lstat(directory)).isDirectory()) return;\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n }\n for (const generation of await entries(sourceDirectory)) {\n if (\n generation.name === keepGeneration ||\n !generation.isDirectory() ||\n !GENERATION.test(generation.name)\n )\n continue;\n const directory = path.join(sourceDirectory, generation.name);\n const found: VariantCacheEntry[] = [];\n for (const file of await entries(directory)) {\n if (!file.isFile()) continue;\n const type = DERIVATIVE.test(file.name)\n ? \"derivative\"\n : file.name === \"source.json\"\n ? \"manifest\"\n : TEMPORARY.test(file.name)\n ? \"temporary\"\n : undefined;\n if (type) found.push({ target: path.join(directory, file.name), type });\n }\n yield { directory, entries: found };\n }\n}\n\n/** Every directory component must match the generated cache layout. */\nexport async function* variantCacheGenerations(\n cacheDirectory: string,\n): AsyncGenerator<VariantCacheGeneration> {\n for (const shard of await entries(cacheDirectory)) {\n if (!shard.isDirectory() || !SHARD.test(shard.name)) continue;\n const directory = path.join(cacheDirectory, shard.name);\n for (const source of await entries(directory)) {\n if (!source.isDirectory() || !SOURCE.test(source.name) || !source.name.startsWith(shard.name))\n continue;\n yield* variantSourceCacheGenerations(path.join(directory, source.name));\n }\n }\n}\n\nasync function* flatten(\n generations: AsyncIterable<VariantCacheGeneration>,\n): AsyncGenerator<VariantCacheEntry> {\n for await (const generation of generations) yield* generation.entries;\n}\n\n/** Recognized files of one source's generations, optionally skipping the `keepGeneration` directory. */\nexport function variantSourceCacheEntries(\n sourceDirectory: string,\n keepGeneration?: string,\n): AsyncGenerator<VariantCacheEntry> {\n return flatten(variantSourceCacheGenerations(sourceDirectory, keepGeneration));\n}\n\n/** Recognized files of every source in the cache. */\nexport function variantCacheEntries(cacheDirectory: string): AsyncGenerator<VariantCacheEntry> {\n return flatten(variantCacheGenerations(cacheDirectory));\n}\n\n/** Keep directories in place so removing cache data cannot remove user folders. */\nexport async function purgeVariantCacheEntries(\n entries: AsyncIterable<VariantCacheEntry>,\n): Promise<boolean> {\n let removed = false;\n for await (const entry of entries) {\n await fs.rm(entry.target, { force: true });\n removed = true;\n }\n return removed;\n}\n"],"mappings":";;;;AAGA,MAAM,QAAQ;AACd,MAAM,SAAS;AACf,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,YACJ;AAaF,eAAe,QAAQ,WAAmB;CACxC,IAAI;EACF,OAAO,MAAM,GAAG,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC;CAC5D,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,OAAO,CAAC;EAChE,MAAM;CACR;AACF;;AAGA,gBAAuB,8BACrB,iBACA,gBACwC;CACxC,IAAI;EAEF,KAAK,MAAM,aAAa,CAAC,KAAK,QAAQ,eAAe,GAAG,eAAe,GACrE,IAAI,EAAE,MAAM,GAAG,MAAM,SAAS,EAAC,CAAE,YAAY,GAAG;CAEpD,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU;EACxD,MAAM;CACR;CACA,KAAK,MAAM,cAAc,MAAM,QAAQ,eAAe,GAAG;EACvD,IACE,WAAW,SAAS,kBACpB,CAAC,WAAW,YAAY,KACxB,CAAC,WAAW,KAAK,WAAW,IAAI,GAEhC;EACF,MAAM,YAAY,KAAK,KAAK,iBAAiB,WAAW,IAAI;EAC5D,MAAM,QAA6B,CAAC;EACpC,KAAK,MAAM,QAAQ,MAAM,QAAQ,SAAS,GAAG;GAC3C,IAAI,CAAC,KAAK,OAAO,GAAG;GACpB,MAAM,OAAO,WAAW,KAAK,KAAK,IAAI,IAClC,eACA,KAAK,SAAS,gBACZ,aACA,UAAU,KAAK,KAAK,IAAI,IACtB,cACA;GACR,IAAI,MAAM,MAAM,KAAK;IAAE,QAAQ,KAAK,KAAK,WAAW,KAAK,IAAI;IAAG;GAAK,CAAC;EACxE;EACA,MAAM;GAAE;GAAW,SAAS;EAAM;CACpC;AACF;;AAGA,gBAAuB,wBACrB,gBACwC;CACxC,KAAK,MAAM,SAAS,MAAM,QAAQ,cAAc,GAAG;EACjD,IAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG;EACrD,MAAM,YAAY,KAAK,KAAK,gBAAgB,MAAM,IAAI;EACtD,KAAK,MAAM,UAAU,MAAM,QAAQ,SAAS,GAAG;GAC7C,IAAI,CAAC,OAAO,YAAY,KAAK,CAAC,OAAO,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,WAAW,MAAM,IAAI,GAC1F;GACF,OAAO,8BAA8B,KAAK,KAAK,WAAW,OAAO,IAAI,CAAC;EACxE;CACF;AACF;AAEA,gBAAgB,QACd,aACmC;CACnC,WAAW,MAAM,cAAc,aAAa,OAAO,WAAW;AAChE;;AAGA,SAAgB,0BACd,iBACA,gBACmC;CACnC,OAAO,QAAQ,8BAA8B,iBAAiB,cAAc,CAAC;AAC/E;;AAGA,SAAgB,oBAAoB,gBAA2D;CAC7F,OAAO,QAAQ,wBAAwB,cAAc,CAAC;AACxD;;AAGA,eAAsB,yBACpB,SACkB;CAClB,IAAI,UAAU;CACd,WAAW,MAAM,SAAS,SAAS;EACjC,MAAM,GAAG,GAAG,MAAM,QAAQ,EAAE,OAAO,KAAK,CAAC;EACzC,UAAU;CACZ;CACA,OAAO;AACT"}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { rootPath } from "../../utils/paths.mjs";
|
|
2
|
+
import { configuredLocalDiskRoots } from "../../storage/local-disk-roots.mjs";
|
|
3
|
+
import { ImageVariantsConfigError } from "./image-variants-config-error.mjs";
|
|
4
|
+
import { purgeVariantCacheEntries, variantSourceCacheEntries } from "./image-variant-cache-entries.mjs";
|
|
2
5
|
import { uploadsConfig } from "../uploads-config.mjs";
|
|
3
|
-
import { isPathInside } from "./is-path-inside.mjs";
|
|
6
|
+
import { isPathInside, isPathWithin } from "./is-path-inside.mjs";
|
|
4
7
|
import { variantGenerationTag, variantSourceDirectory, variantSourceKey } from "./variant-cache-key.mjs";
|
|
5
|
-
import
|
|
8
|
+
import baseConfig from "@mongez/config";
|
|
6
9
|
import { log } from "@warlock.js/logger";
|
|
7
10
|
import path from "node:path";
|
|
11
|
+
import fsSync from "node:fs";
|
|
8
12
|
import fs from "node:fs/promises";
|
|
9
13
|
|
|
10
14
|
//#region ../../packages/core/src/http/uploads/image-variant-cache.ts
|
|
@@ -15,16 +19,70 @@ async function realpathOrSelf(target) {
|
|
|
15
19
|
return target;
|
|
16
20
|
}
|
|
17
21
|
}
|
|
22
|
+
function canonicalDirectory(target) {
|
|
23
|
+
const resolved = path.resolve(target);
|
|
24
|
+
try {
|
|
25
|
+
return fsSync.realpathSync(resolved);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
const code = error.code;
|
|
28
|
+
if (code !== "ENOENT") throw new ImageVariantsConfigError(`uploads.images.cacheDirectory (or a local disk root) could not be resolved: ${resolved} (${code ?? "unknown error"})`, { cause: error });
|
|
29
|
+
const parent = path.dirname(resolved);
|
|
30
|
+
if (parent === resolved) throw error;
|
|
31
|
+
return path.join(canonicalDirectory(parent), path.basename(resolved));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Most distinct cache/disk-root combinations whose overlap check is remembered. */
|
|
35
|
+
const OVERLAP_CHECKS_LIMIT = 64;
|
|
36
|
+
/**
|
|
37
|
+
* Overlap check outcomes, keyed by the cache directory, the disk root and
|
|
38
|
+
* every configured local root. A disk registered later changes the key, so
|
|
39
|
+
* it is checked again; the stored error is rethrown for a refused layout.
|
|
40
|
+
*/
|
|
41
|
+
const overlapChecks = /* @__PURE__ */ new Map();
|
|
42
|
+
function checkCacheOverlap(directory, diskRoot) {
|
|
43
|
+
const roots = [diskRoot, ...configuredLocalDiskRoots()];
|
|
44
|
+
const key = [directory, ...roots].join("\0");
|
|
45
|
+
if (overlapChecks.has(key)) {
|
|
46
|
+
const failure = overlapChecks.get(key);
|
|
47
|
+
if (failure) throw failure;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let failure;
|
|
51
|
+
try {
|
|
52
|
+
const realCache = canonicalDirectory(directory);
|
|
53
|
+
for (const root of roots) if (isPathWithin(canonicalDirectory(root), realCache)) {
|
|
54
|
+
failure = new ImageVariantsConfigError("uploads.images.cacheDirectory must not equal or contain the storage root of any local disk (including symlinks).");
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (!(error instanceof ImageVariantsConfigError)) throw error;
|
|
59
|
+
failure = error;
|
|
60
|
+
}
|
|
61
|
+
if (overlapChecks.size >= OVERLAP_CHECKS_LIMIT) {
|
|
62
|
+
const oldest = overlapChecks.keys().next();
|
|
63
|
+
if (!oldest.done) overlapChecks.delete(oldest.value);
|
|
64
|
+
}
|
|
65
|
+
overlapChecks.set(key, failure);
|
|
66
|
+
if (failure) throw failure;
|
|
67
|
+
}
|
|
18
68
|
/**
|
|
19
69
|
* The derivative cache directory for a local disk: `uploads.images.cacheDirectory`
|
|
20
70
|
* when the app sets one (shared by every disk; derivatives are keyed by the
|
|
21
71
|
* disk's real root, so they never collide), otherwise
|
|
22
72
|
* `<diskRoot>/.cache/image-variants`. The same rule as
|
|
23
|
-
* `resolveImageVariantsConfig`.
|
|
73
|
+
* `resolveImageVariantsConfig`. Refuses any cache that equals or contains
|
|
74
|
+
* any configured local root, resolving symlinks before comparison. The
|
|
75
|
+
* outcome is remembered per cache, disk root and configured local roots, so
|
|
76
|
+
* repeated requests do not resolve the same paths again.
|
|
77
|
+
*
|
|
78
|
+
* @throws ImageVariantsConfigError when a cache overlaps a local disk root, or
|
|
79
|
+
* when the cache or a root cannot be resolved (for example `ENOTDIR`, `EACCES`)
|
|
24
80
|
*/
|
|
25
|
-
function variantCacheDirectoryFor(diskRoot) {
|
|
26
|
-
const configured =
|
|
27
|
-
|
|
81
|
+
function variantCacheDirectoryFor(diskRoot, images = uploadsConfig("images")) {
|
|
82
|
+
const configured = images?.cacheDirectory;
|
|
83
|
+
const directory = configured ? path.resolve(configured) : path.join(path.resolve(diskRoot), ".cache", "image-variants");
|
|
84
|
+
checkCacheOverlap(directory, diskRoot);
|
|
85
|
+
return directory;
|
|
28
86
|
}
|
|
29
87
|
/**
|
|
30
88
|
* The directory holding every derivative of one file on a local disk, or
|
|
@@ -44,39 +102,23 @@ async function variantSourceDirectoryForFile(diskRoot, absolutePath) {
|
|
|
44
102
|
/**
|
|
45
103
|
* Remove every cached derivative of one file on a local disk.
|
|
46
104
|
*
|
|
47
|
-
* @returns `true` when
|
|
105
|
+
* @returns `true` when recognized cache files were removed
|
|
48
106
|
*/
|
|
49
107
|
async function purgeImageVariantsOfFile(diskRoot, absolutePath) {
|
|
50
108
|
const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);
|
|
51
109
|
if (!directory) return false;
|
|
52
|
-
|
|
53
|
-
await fs.access(directory);
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
await fs.rm(directory, {
|
|
58
|
-
recursive: true,
|
|
59
|
-
force: true
|
|
60
|
-
});
|
|
61
|
-
return true;
|
|
110
|
+
return purgeVariantCacheEntries(variantSourceCacheEntries(directory));
|
|
62
111
|
}
|
|
63
112
|
/**
|
|
64
113
|
* Remove derivatives made from older versions of a source (a different size
|
|
65
114
|
* or mtime), keeping only the `keep` generation. Called after a derivative of
|
|
66
115
|
* the current version has been written, so a source rewritten in place does
|
|
67
|
-
* not leave its old derivatives behind.
|
|
116
|
+
* not leave its old derivatives behind. Only recognized cache files in
|
|
117
|
+
* generation-shaped directories are removed; unrelated entries and all
|
|
118
|
+
* directories and symlinks stay in place.
|
|
68
119
|
*/
|
|
69
120
|
async function pruneStaleVariantGenerations(sourceDirectory, keep) {
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
entries = await fs.readdir(sourceDirectory);
|
|
73
|
-
} catch {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
await Promise.all(entries.filter((entry) => entry !== keep).map((entry) => fs.rm(path.join(sourceDirectory, entry), {
|
|
77
|
-
recursive: true,
|
|
78
|
-
force: true
|
|
79
|
-
})));
|
|
121
|
+
await purgeVariantCacheEntries(variantSourceCacheEntries(sourceDirectory, keep));
|
|
80
122
|
}
|
|
81
123
|
/**
|
|
82
124
|
* {@link pruneStaleVariantGenerations}, but only while `keep` is still the
|
|
@@ -130,7 +172,7 @@ let warnedPublicCache = false;
|
|
|
130
172
|
*/
|
|
131
173
|
function warnIfVariantCacheIsPublic(cacheDirectory) {
|
|
132
174
|
if (warnedPublicCache) return;
|
|
133
|
-
const configured =
|
|
175
|
+
const configured = baseConfig.get("storage.publicRoot", rootPath("public"));
|
|
134
176
|
const publicRoots = (Array.isArray(configured) ? configured : [configured]).filter((root) => typeof root === "string" && root.length > 0).map((root) => path.resolve(root));
|
|
135
177
|
const resolved = path.resolve(cacheDirectory);
|
|
136
178
|
if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;
|
|
@@ -139,5 +181,5 @@ function warnIfVariantCacheIsPublic(cacheDirectory) {
|
|
|
139
181
|
}
|
|
140
182
|
|
|
141
183
|
//#endregion
|
|
142
|
-
export { isMissingFileError, pruneStaleVariantGenerationsIfCurrent, purgeImageVariantsOfFile, retryOnVanishedDirectory, variantCacheDirectoryFor, warnIfVariantCacheIsPublic };
|
|
184
|
+
export { isMissingFileError, pruneStaleVariantGenerations, pruneStaleVariantGenerationsIfCurrent, purgeImageVariantsOfFile, retryOnVanishedDirectory, variantCacheDirectoryFor, variantSourceDirectoryForFile, warnIfVariantCacheIsPublic };
|
|
143
185
|
//# sourceMappingURL=image-variant-cache.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-variant-cache.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { rootPath } from \"../../utils/paths\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport { isPathInside } from \"./is-path-inside\";\nimport {\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\n\n/*\n * Cache housekeeping for image derivatives. Deliberately free of any\n * `storage` import: the local storage driver calls into this module when it\n * deletes or moves a file, and storage must not import back into the HTTP\n * layer that already imports storage.\n */\n\nasync function realpathOrSelf(target: string): Promise<string> {\n try {\n return await fs.realpath(target);\n } catch {\n return target;\n }\n}\n\n/**\n * The derivative cache directory for a local disk: `uploads.images.cacheDirectory`\n * when the app sets one (shared by every disk; derivatives are keyed by the\n * disk's real root, so they never collide), otherwise\n * `<diskRoot>/.cache/image-variants`. The same rule as\n * `resolveImageVariantsConfig`.\n */\nexport function variantCacheDirectoryFor(diskRoot: string): string {\n const configured = uploadsConfig(\"images\")?.cacheDirectory;\n\n return configured\n ? path.resolve(configured)\n : path.join(path.resolve(diskRoot), \".cache\", \"image-variants\");\n}\n\n/**\n * The directory holding every derivative of one file on a local disk, or\n * `undefined` when the file is not inside the disk root. The file does not\n * need to exist any more: only its parent directory is resolved through\n * symlinks, exactly as `resolveUploadPath` resolved it when the derivative\n * was made.\n */\nexport async function variantSourceDirectoryForFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<string | undefined> {\n const realRoot = await realpathOrSelf(path.resolve(diskRoot));\n const realParent = await realpathOrSelf(path.dirname(path.resolve(absolutePath)));\n const realPath = path.join(realParent, path.basename(absolutePath));\n\n if (!isPathInside(realPath, realRoot)) return undefined;\n\n const relativePath = path.relative(realRoot, realPath).split(path.sep).join(\"/\");\n\n return variantSourceDirectory(\n variantCacheDirectoryFor(diskRoot),\n variantSourceKey(realRoot, relativePath),\n );\n}\n\n/**\n * Remove every cached derivative of one file on a local disk.\n *\n * @returns `true` when a cache directory for the file existed and was removed\n */\nexport async function purgeImageVariantsOfFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<boolean> {\n const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);\n\n if (!directory) return false;\n\n try {\n await fs.access(directory);\n } catch {\n return false;\n }\n\n await fs.rm(directory, { recursive: true, force: true });\n\n return true;\n}\n\n/**\n * Remove derivatives made from older versions of a source (a different size\n * or mtime), keeping only the `keep` generation. Called after a derivative of\n * the current version has been written, so a source rewritten in place does\n * not leave its old derivatives behind.\n */\nexport async function pruneStaleVariantGenerations(\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let entries: string[];\n\n try {\n entries = await fs.readdir(sourceDirectory);\n } catch {\n return;\n }\n\n await Promise.all(\n entries\n .filter((entry) => entry !== keep)\n .map((entry) => fs.rm(path.join(sourceDirectory, entry), { recursive: true, force: true })),\n );\n}\n\n/**\n * {@link pruneStaleVariantGenerations}, but only while `keep` is still the\n * source's current generation.\n *\n * A request that read the source before it was rewritten renders an old\n * generation; if it pruned afterwards it would delete the derivatives of the\n * newer version another request had just written. Re-reading the source's\n * size and mtime right before pruning keeps a stale request from doing that.\n */\nexport async function pruneStaleVariantGenerationsIfCurrent(\n sourceAbsolutePath: string,\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let current: string;\n\n try {\n const stats = await fs.stat(sourceAbsolutePath);\n current = variantGenerationTag(stats.size, stats.mtimeMs);\n } catch {\n // the source is gone; its derivatives are purged by the delete itself\n return;\n }\n\n if (current !== keep) return;\n\n await pruneStaleVariantGenerations(sourceDirectory, keep);\n}\n\n/**\n * True for \"no such file or directory\"\n */\nexport function isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n\n/**\n * Run a derivative write, once more if it fails because its directory\n * vanished: a concurrent request for a newer version of the source may prune\n * the generation directory between `mkdir` and the atomic rename.\n */\nexport async function retryOnVanishedDirectory(write: () => Promise<void>): Promise<void> {\n try {\n await write();\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n\n await write();\n }\n}\n\nlet warnedPublicCache = false;\n\n/**\n * Warn once when the derivative cache sits inside the public folder.\n *\n * A configured `uploads.images.cacheDirectory` is shared by every local disk,\n * so derivatives of a private disk land beside public ones. Inside\n * `public/` (or `storage.publicRoot`) they are served to anyone, bypassing\n * whatever guards the private disk's own route. The paths are hashes, but\n * they are derived from the disk root and the file path, which are not\n * secret.\n */\nexport function warnIfVariantCacheIsPublic(cacheDirectory: string): void {\n if (warnedPublicCache) return;\n\n const configured = config.get(\"storage.publicRoot\", rootPath(\"public\")) as unknown;\n const publicRoots = (Array.isArray(configured) ? configured : [configured])\n .filter((root): root is string => typeof root === \"string\" && root.length > 0)\n .map((root) => path.resolve(root));\n const resolved = path.resolve(cacheDirectory);\n\n if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;\n\n warnedPublicCache = true;\n log.warn(\n \"uploads\",\n \"image-variants\",\n `The image variant cache (${resolved}) is inside the public folder, so every cached derivative, private disks included, is publicly served. Move uploads.images.cacheDirectory outside public/.`,\n );\n}\n\n/**\n * Forget that the public-cache warning was shown (tests).\n */\nexport function resetVariantCacheWarnings(): void {\n warnedPublicCache = false;\n}\n"],"mappings":";;;;;;;;;;AAoBA,eAAe,eAAe,QAAiC;CAC7D,IAAI;EACF,OAAO,MAAM,GAAG,SAAS,MAAM;CACjC,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;AASA,SAAgB,yBAAyB,UAA0B;CACjE,MAAM,aAAa,cAAc,QAAQ,CAAC,EAAE;CAE5C,OAAO,aACH,KAAK,QAAQ,UAAU,IACvB,KAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,UAAU,gBAAgB;AAClE;;;;;;;;AASA,eAAsB,8BACpB,UACA,cAC6B;CAC7B,MAAM,WAAW,MAAM,eAAe,KAAK,QAAQ,QAAQ,CAAC;CAC5D,MAAM,aAAa,MAAM,eAAe,KAAK,QAAQ,KAAK,QAAQ,YAAY,CAAC,CAAC;CAChF,MAAM,WAAW,KAAK,KAAK,YAAY,KAAK,SAAS,YAAY,CAAC;CAElE,IAAI,CAAC,aAAa,UAAU,QAAQ,GAAG,OAAO;CAE9C,MAAM,eAAe,KAAK,SAAS,UAAU,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;CAE/E,OAAO,uBACL,yBAAyB,QAAQ,GACjC,iBAAiB,UAAU,YAAY,CACzC;AACF;;;;;;AAOA,eAAsB,yBACpB,UACA,cACkB;CAClB,MAAM,YAAY,MAAM,8BAA8B,UAAU,YAAY;CAE5E,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI;EACF,MAAM,GAAG,OAAO,SAAS;CAC3B,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,GAAG,GAAG,WAAW;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;CAEvD,OAAO;AACT;;;;;;;AAQA,eAAsB,6BACpB,iBACA,MACe;CACf,IAAI;CAEJ,IAAI;EACF,UAAU,MAAM,GAAG,QAAQ,eAAe;CAC5C,QAAQ;EACN;CACF;CAEA,MAAM,QAAQ,IACZ,QACG,QAAQ,UAAU,UAAU,IAAI,CAAC,CACjC,KAAK,UAAU,GAAG,GAAG,KAAK,KAAK,iBAAiB,KAAK,GAAG;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC,CAAC,CAC9F;AACF;;;;;;;;;;AAWA,eAAsB,sCACpB,oBACA,iBACA,MACe;CACf,IAAI;CAEJ,IAAI;EACF,MAAM,QAAQ,MAAM,GAAG,KAAK,kBAAkB;EAC9C,UAAU,qBAAqB,MAAM,MAAM,MAAM,OAAO;CAC1D,QAAQ;EAEN;CACF;CAEA,IAAI,YAAY,MAAM;CAEtB,MAAM,6BAA6B,iBAAiB,IAAI;AAC1D;;;;AAKA,SAAgB,mBAAmB,OAAyB;CAC1D,OAAQ,OAA6C,SAAS;AAChE;;;;;;AAOA,eAAsB,yBAAyB,OAA2C;CACxF,IAAI;EACF,MAAM,MAAM;CACd,SAAS,OAAO;EACd,IAAI,CAAC,mBAAmB,KAAK,GAAG,MAAM;EAEtC,MAAM,MAAM;CACd;AACF;AAEA,IAAI,oBAAoB;;;;;;;;;;;AAYxB,SAAgB,2BAA2B,gBAA8B;CACvE,IAAI,mBAAmB;CAEvB,MAAM,aAAa,OAAO,IAAI,sBAAsB,SAAS,QAAQ,CAAC;CACtE,MAAM,eAAe,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU,EAAC,CACvE,QAAQ,SAAyB,OAAO,SAAS,YAAY,KAAK,SAAS,CAAC,CAAC,CAC7E,KAAK,SAAS,KAAK,QAAQ,IAAI,CAAC;CACnC,MAAM,WAAW,KAAK,QAAQ,cAAc;CAE5C,IAAI,CAAC,YAAY,MAAM,SAAS,aAAa,QAAQ,aAAa,UAAU,IAAI,CAAC,GAAG;CAEpF,oBAAoB;CACpB,IAAI,KACF,WACA,kBACA,4BAA4B,SAAS,2JACvC;AACF"}
|
|
1
|
+
{"version":3,"file":"image-variant-cache.mjs","names":["config"],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-cache.ts"],"sourcesContent":["import config from \"@mongez/config\";\nimport { log } from \"@warlock.js/logger\";\nimport fs from \"node:fs/promises\";\nimport fsSync from \"node:fs\";\nimport { configuredLocalDiskRoots } from \"../../storage/local-disk-roots\";\nimport type { UploadsImagesConfigurations } from \"../uploads-types\";\nimport { ImageVariantsConfigError } from \"./image-variants-config-error\";\nimport { purgeVariantCacheEntries, variantSourceCacheEntries } from \"./image-variant-cache-entries\";\nimport path from \"node:path\";\nimport { rootPath } from \"../../utils/paths\";\nimport { uploadsConfig } from \"../uploads-config\";\nimport { isPathInside, isPathWithin } from \"./is-path-inside\";\nimport {\n variantGenerationTag,\n variantSourceDirectory,\n variantSourceKey,\n} from \"./variant-cache-key\";\n\n/*\n * Cache housekeeping for image derivatives. Deliberately free of any\n * import of the storage manager or drivers: the local driver calls into this module when it\n * deletes or moves a file, and storage must not import back into the HTTP\n * layer that already imports storage.\n */\n\nasync function realpathOrSelf(target: string): Promise<string> {\n try {\n return await fs.realpath(target);\n } catch {\n return target;\n }\n}\n\nfunction canonicalDirectory(target: string): string {\n const resolved = path.resolve(target);\n try {\n return fsSync.realpathSync(resolved);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") {\n // ENOTDIR, EACCES, ELOOP, ...: a configuration problem, reported as one.\n throw new ImageVariantsConfigError(\n `uploads.images.cacheDirectory (or a local disk root) could not be resolved: ${resolved} (${code ?? \"unknown error\"})`,\n { cause: error },\n );\n }\n const parent = path.dirname(resolved);\n if (parent === resolved) throw error;\n // Resolve the nearest existing ancestor too, so a symlink followed by a\n // not-yet-created directory cannot hide an overlap with a future disk root.\n return path.join(canonicalDirectory(parent), path.basename(resolved));\n }\n}\n\n/** Most distinct cache/disk-root combinations whose overlap check is remembered. */\nconst OVERLAP_CHECKS_LIMIT = 64;\n\n/**\n * Overlap check outcomes, keyed by the cache directory, the disk root and\n * every configured local root. A disk registered later changes the key, so\n * it is checked again; the stored error is rethrown for a refused layout.\n */\nconst overlapChecks = new Map<string, ImageVariantsConfigError | undefined>();\n\nfunction checkCacheOverlap(directory: string, diskRoot: string): void {\n const roots = [diskRoot, ...configuredLocalDiskRoots()];\n const key = [directory, ...roots].join(\"\\0\");\n if (overlapChecks.has(key)) {\n const failure = overlapChecks.get(key);\n if (failure) throw failure;\n return;\n }\n let failure: ImageVariantsConfigError | undefined;\n try {\n const realCache = canonicalDirectory(directory);\n for (const root of roots) {\n if (isPathWithin(canonicalDirectory(root), realCache)) {\n failure = new ImageVariantsConfigError(\n \"uploads.images.cacheDirectory must not equal or contain the storage root of any local disk (including symlinks).\",\n );\n break;\n }\n }\n } catch (error) {\n // Only configuration errors are remembered; anything else is retried next time.\n if (!(error instanceof ImageVariantsConfigError)) throw error;\n failure = error;\n }\n if (overlapChecks.size >= OVERLAP_CHECKS_LIMIT) {\n const oldest = overlapChecks.keys().next();\n if (!oldest.done) overlapChecks.delete(oldest.value);\n }\n overlapChecks.set(key, failure);\n if (failure) throw failure;\n}\n\n/**\n * Forget remembered cache overlap checks, so the next check resolves every\n * path again (tests). Changes to the configured disks are detected without it;\n * a directory replaced by a symlink at runtime is not.\n */\nexport function resetVariantCacheOverlapChecks(): void {\n overlapChecks.clear();\n}\n\n/**\n * The derivative cache directory for a local disk: `uploads.images.cacheDirectory`\n * when the app sets one (shared by every disk; derivatives are keyed by the\n * disk's real root, so they never collide), otherwise\n * `<diskRoot>/.cache/image-variants`. The same rule as\n * `resolveImageVariantsConfig`. Refuses any cache that equals or contains\n * any configured local root, resolving symlinks before comparison. The\n * outcome is remembered per cache, disk root and configured local roots, so\n * repeated requests do not resolve the same paths again.\n *\n * @throws ImageVariantsConfigError when a cache overlaps a local disk root, or\n * when the cache or a root cannot be resolved (for example `ENOTDIR`, `EACCES`)\n */\nexport function variantCacheDirectoryFor(\n diskRoot: string,\n images: Pick<UploadsImagesConfigurations, \"cacheDirectory\"> | undefined = uploadsConfig(\"images\"),\n): string {\n const configured = images?.cacheDirectory;\n const directory = configured\n ? path.resolve(configured)\n : path.join(path.resolve(diskRoot), \".cache\", \"image-variants\");\n checkCacheOverlap(directory, diskRoot);\n return directory;\n}\n\n/**\n * The directory holding every derivative of one file on a local disk, or\n * `undefined` when the file is not inside the disk root. The file does not\n * need to exist any more: only its parent directory is resolved through\n * symlinks, exactly as `resolveUploadPath` resolved it when the derivative\n * was made.\n */\nexport async function variantSourceDirectoryForFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<string | undefined> {\n const realRoot = await realpathOrSelf(path.resolve(diskRoot));\n const realParent = await realpathOrSelf(path.dirname(path.resolve(absolutePath)));\n const realPath = path.join(realParent, path.basename(absolutePath));\n\n if (!isPathInside(realPath, realRoot)) return undefined;\n\n const relativePath = path.relative(realRoot, realPath).split(path.sep).join(\"/\");\n\n return variantSourceDirectory(\n variantCacheDirectoryFor(diskRoot),\n variantSourceKey(realRoot, relativePath),\n );\n}\n\n/**\n * Remove every cached derivative of one file on a local disk.\n *\n * @returns `true` when recognized cache files were removed\n */\nexport async function purgeImageVariantsOfFile(\n diskRoot: string,\n absolutePath: string,\n): Promise<boolean> {\n const directory = await variantSourceDirectoryForFile(diskRoot, absolutePath);\n\n if (!directory) return false;\n\n return purgeVariantCacheEntries(variantSourceCacheEntries(directory));\n}\n\n/**\n * Remove derivatives made from older versions of a source (a different size\n * or mtime), keeping only the `keep` generation. Called after a derivative of\n * the current version has been written, so a source rewritten in place does\n * not leave its old derivatives behind. Only recognized cache files in\n * generation-shaped directories are removed; unrelated entries and all\n * directories and symlinks stay in place.\n */\nexport async function pruneStaleVariantGenerations(\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n await purgeVariantCacheEntries(variantSourceCacheEntries(sourceDirectory, keep));\n}\n\n/**\n * {@link pruneStaleVariantGenerations}, but only while `keep` is still the\n * source's current generation.\n *\n * A request that read the source before it was rewritten renders an old\n * generation; if it pruned afterwards it would delete the derivatives of the\n * newer version another request had just written. Re-reading the source's\n * size and mtime right before pruning keeps a stale request from doing that.\n */\nexport async function pruneStaleVariantGenerationsIfCurrent(\n sourceAbsolutePath: string,\n sourceDirectory: string,\n keep: string,\n): Promise<void> {\n let current: string;\n\n try {\n const stats = await fs.stat(sourceAbsolutePath);\n current = variantGenerationTag(stats.size, stats.mtimeMs);\n } catch {\n // the source is gone; its derivatives are purged by the delete itself\n return;\n }\n\n if (current !== keep) return;\n\n await pruneStaleVariantGenerations(sourceDirectory, keep);\n}\n\n/**\n * True for \"no such file or directory\"\n */\nexport function isMissingFileError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === \"ENOENT\";\n}\n\n/**\n * Run a derivative write, once more if it fails because its directory\n * vanished: a concurrent request for a newer version of the source may prune\n * the generation directory between `mkdir` and the atomic rename.\n */\nexport async function retryOnVanishedDirectory(write: () => Promise<void>): Promise<void> {\n try {\n await write();\n } catch (error) {\n if (!isMissingFileError(error)) throw error;\n\n await write();\n }\n}\n\nlet warnedPublicCache = false;\n\n/**\n * Warn once when the derivative cache sits inside the public folder.\n *\n * A configured `uploads.images.cacheDirectory` is shared by every local disk,\n * so derivatives of a private disk land beside public ones. Inside\n * `public/` (or `storage.publicRoot`) they are served to anyone, bypassing\n * whatever guards the private disk's own route. The paths are hashes, but\n * they are derived from the disk root and the file path, which are not\n * secret.\n */\nexport function warnIfVariantCacheIsPublic(cacheDirectory: string): void {\n if (warnedPublicCache) return;\n\n const configured = config.get(\"storage.publicRoot\", rootPath(\"public\")) as unknown;\n const publicRoots = (Array.isArray(configured) ? configured : [configured])\n .filter((root): root is string => typeof root === \"string\" && root.length > 0)\n .map((root) => path.resolve(root));\n const resolved = path.resolve(cacheDirectory);\n\n if (!publicRoots.some((root) => resolved === root || isPathInside(resolved, root))) return;\n\n warnedPublicCache = true;\n log.warn(\n \"uploads\",\n \"image-variants\",\n `The image variant cache (${resolved}) is inside the public folder, so every cached derivative, private disks included, is publicly served. Move uploads.images.cacheDirectory outside public/.`,\n );\n}\n\n/**\n * Forget that the public-cache warning was shown (tests).\n */\nexport function resetVariantCacheWarnings(): void {\n warnedPublicCache = false;\n}\n"],"mappings":"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"}
|
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
import { ImageVariantDefinition, ImageVariantOutputFormat } from "../uploads-types.mjs";
|
|
2
|
-
|
|
3
2
|
//#region ../../packages/core/src/http/uploads/image-variant-types.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* The `uploads.images` config after validation, with every default applied
|
|
6
5
|
*/
|
|
7
|
-
type ResolvedImageVariantsConfig = {
|
|
6
|
+
export type ResolvedImageVariantsConfig = {
|
|
8
7
|
variants: Readonly<Record<string, ImageVariantDefinition>>;
|
|
9
8
|
formats: readonly ImageVariantOutputFormat[];
|
|
10
9
|
maxSourceBytes: number;
|
|
11
10
|
maxSourcePixels: number;
|
|
12
11
|
cacheDirectory: string;
|
|
12
|
+
maxCacheBytes: number;
|
|
13
|
+
maxCacheAge: number;
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
16
|
* Raster formats a variant can be generated from, detected by magic bytes
|
|
16
17
|
*/
|
|
17
|
-
type VariantSourceFormat = "jpeg" | "png" | "webp" | "avif";
|
|
18
|
+
export type VariantSourceFormat = "jpeg" | "png" | "webp" | "avif";
|
|
18
19
|
/**
|
|
19
20
|
* Every format `detectImageFormat` can recognise, including the refused ones
|
|
20
21
|
*/
|
|
21
|
-
type DetectedImageFormat = VariantSourceFormat | "gif" | "svg";
|
|
22
|
+
export type DetectedImageFormat = VariantSourceFormat | "gif" | "svg";
|
|
22
23
|
/**
|
|
23
24
|
* Format a derivative is written in
|
|
24
25
|
*/
|
|
25
|
-
type VariantOutputFormat = VariantSourceFormat;
|
|
26
|
+
export type VariantOutputFormat = VariantSourceFormat;
|
|
26
27
|
/**
|
|
27
28
|
* What the query string of an uploads request asks for
|
|
28
29
|
*/
|
|
29
|
-
type UploadedFileQuery = {
|
|
30
|
+
export type UploadedFileQuery = {
|
|
30
31
|
type: "original";
|
|
31
32
|
} | {
|
|
32
33
|
type: "variant";
|
|
@@ -44,7 +45,7 @@ type UploadedFileQuery = {
|
|
|
44
45
|
* passed through loader data as is. Core does not import that type — web
|
|
45
46
|
* depends on core, not the other way around — this is a structural match.
|
|
46
47
|
*/
|
|
47
|
-
type GeneratedImageVariant = {
|
|
48
|
+
export type GeneratedImageVariant = {
|
|
48
49
|
/**
|
|
49
50
|
* Actual rendered width, in pixels
|
|
50
51
|
*/
|
|
@@ -66,7 +67,7 @@ type GeneratedImageVariant = {
|
|
|
66
67
|
* Serializable descriptor returned by `generateImageVariants`, matching web's
|
|
67
68
|
* `ImageDescriptor` field for field.
|
|
68
69
|
*/
|
|
69
|
-
type GeneratedImageDescriptor = {
|
|
70
|
+
export type GeneratedImageDescriptor = {
|
|
70
71
|
/**
|
|
71
72
|
* The original source path: `/uploads/<path>`
|
|
72
73
|
*/
|
|
@@ -89,5 +90,4 @@ type GeneratedImageDescriptor = {
|
|
|
89
90
|
formats?: readonly ImageVariantOutputFormat[];
|
|
90
91
|
};
|
|
91
92
|
//#endregion
|
|
92
|
-
export { DetectedImageFormat, GeneratedImageDescriptor, GeneratedImageVariant, ResolvedImageVariantsConfig, UploadedFileQuery, VariantOutputFormat, VariantSourceFormat };
|
|
93
93
|
//# sourceMappingURL=image-variant-types.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-variant-types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-types.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"image-variant-types.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variant-types.ts"],"mappings":";;;;;YAKY;EACV,UAAU,SAAS,eAAe;EAClC,kBAAkB;EAClB;EACA;EACA;EACA;EACA;;;;;YAMU;;;;YAKA,sBAAsB;;;;YAKtB,sBAAsB;;;;YAKtB;EACN;;EACA;EAAiB;EAAiB;;EAClC;EAAiB;;;;;;;;;;YAUX;;;;EAIV;;;;EAKA;;;;EAKA;;;;EAKA,OAAO,QAAQ,OAAO;;;;;;YAOZ;;;;EAIV;;;;EAKA;;;;EAKA;;;;EAKA,UAAU,SAAS,eAAe;;;;EAKlC,mBAAmB"}
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* Raised the first time a variant is requested, so a bad config fails loudly
|
|
6
6
|
* on the first image instead of producing unbounded or surprising derivatives.
|
|
7
7
|
*/
|
|
8
|
-
declare class ImageVariantsConfigError extends Error {
|
|
9
|
-
|
|
8
|
+
export declare class ImageVariantsConfigError extends Error {
|
|
9
|
+
/** Stable Warlock error code; `warlock explain WL1005` prints the fix. */
|
|
10
|
+
readonly code = "WL1005";
|
|
11
|
+
constructor(message: string, options?: ErrorOptions);
|
|
10
12
|
}
|
|
11
13
|
//#endregion
|
|
12
|
-
export { ImageVariantsConfigError };
|
|
13
14
|
//# sourceMappingURL=image-variants-config-error.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-variants-config-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"image-variants-config-error.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"mappings":";;;;;;;qBAMa,iCAAiC;;WAE5B;EAEhB,YAAmB,iBAAiB,UAAU"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* on the first image instead of producing unbounded or surprising derivatives.
|
|
7
7
|
*/
|
|
8
8
|
var ImageVariantsConfigError = class extends Error {
|
|
9
|
-
constructor(message) {
|
|
10
|
-
super(`Invalid uploads.images configuration: ${message}
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(`Invalid uploads.images configuration: ${message}`, options);
|
|
11
|
+
this.code = "WL1005";
|
|
11
12
|
this.name = "ImageVariantsConfigError";
|
|
12
13
|
}
|
|
13
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-variants-config-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"sourcesContent":["/**\n * Thrown when the `uploads.images` configuration is invalid.\n *\n * Raised the first time a variant is requested, so a bad config fails loudly\n * on the first image instead of producing unbounded or surprising derivatives.\n */\nexport class ImageVariantsConfigError extends Error {\n public constructor(message: string) {\n super(`Invalid uploads.images configuration: ${message}
|
|
1
|
+
{"version":3,"file":"image-variants-config-error.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/image-variants-config-error.ts"],"sourcesContent":["/**\n * Thrown when the `uploads.images` configuration is invalid.\n *\n * Raised the first time a variant is requested, so a bad config fails loudly\n * on the first image instead of producing unbounded or surprising derivatives.\n */\nexport class ImageVariantsConfigError extends Error {\n /** Stable Warlock error code; `warlock explain WL1005` prints the fix. */\n public readonly code = \"WL1005\";\n\n public constructor(message: string, options?: ErrorOptions) {\n super(`Invalid uploads.images configuration: ${message}`, options);\n\n this.name = \"ImageVariantsConfigError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,2BAAb,cAA8C,MAAM;CAIlD,AAAO,YAAY,SAAiB,SAAwB;EAC1D,MAAM,yCAAyC,WAAW,OAAO;cAH5C;EAKrB,KAAK,OAAO;CACd;AACF"}
|
|
@@ -3,4 +3,5 @@ import { GenerateImageVariantsOptions, generateImageVariants } from "./generate-
|
|
|
3
3
|
import { ImageVariantsConfigError } from "./image-variants-config-error.mjs";
|
|
4
4
|
import { PurgeImageVariantsOptions, purgeImageVariants } from "./purge-image-variants.mjs";
|
|
5
5
|
import { ResolveImageVariantInput, ResolvedImageVariant, resolveImageVariant } from "./resolve-image-variant.mjs";
|
|
6
|
-
import { UploadedFileControllerOptions, createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
|
|
6
|
+
import { UploadedFileControllerOptions, createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
|
|
7
|
+
export { DetectedImageFormat, GenerateImageVariantsOptions, GeneratedImageDescriptor, GeneratedImageVariant, ImageVariantsConfigError, PurgeImageVariantsOptions, ResolveImageVariantInput, ResolvedImageVariant, ResolvedImageVariantsConfig, UploadedFileControllerOptions, UploadedFileQuery, VariantOutputFormat, VariantSourceFormat, createUploadedFileController, generateImageVariants, purgeImageVariants, resolveImageVariant, uploadedFileController };
|
|
@@ -4,4 +4,4 @@ import { purgeImageVariants } from "./purge-image-variants.mjs";
|
|
|
4
4
|
import { resolveImageVariant } from "./resolve-image-variant.mjs";
|
|
5
5
|
import { createUploadedFileController, uploadedFileController } from "./uploaded-file.controller.mjs";
|
|
6
6
|
|
|
7
|
-
export {
|
|
7
|
+
export { ImageVariantsConfigError, createUploadedFileController, generateImageVariants, purgeImageVariants, resolveImageVariant, uploadedFileController };
|
|
@@ -21,7 +21,7 @@ import fs from "node:fs/promises";
|
|
|
21
21
|
* I/O) propagates unchanged.
|
|
22
22
|
*/
|
|
23
23
|
async function loadVariantSource(absolutePath, { maxSourceBytes, maxSourcePixels, expectedFormat }) {
|
|
24
|
-
const buffer = await fs.readFile(absolutePath);
|
|
24
|
+
const buffer = Buffer.isBuffer(absolutePath) ? absolutePath : await fs.readFile(absolutePath);
|
|
25
25
|
if (buffer.length > maxSourceBytes) throw new HttpError(413, "The source image is too large.");
|
|
26
26
|
if (detectImageFormat(buffer) !== expectedFormat) throw new HttpError(415, "The source image changed format while it was read.");
|
|
27
27
|
const image = new Image(buffer);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-variant-source.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/load-variant-source.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { HttpError } from \"../errors\";\nimport { detectImageFormat } from \"./detect-image-format\";\nimport type { VariantSourceFormat } from \"./image-variant-types\";\n\n/**\n * Bounds and the expected format a source must match\n */\nexport type LoadVariantSourceOptions = {\n maxSourceBytes: number;\n maxSourcePixels: number;\n expectedFormat: VariantSourceFormat;\n};\n\n/**\n * Read a variant source in full and check it before it is decoded.\n *\n * The caller has already sniffed the format from the file head; this re-checks\n * the bytes actually read, the same buffer that is then resized, so the file\n * cannot be swapped between the check and the render.\n *\n * - bytes over `maxSourceBytes` → 413\n * - magic bytes that no longer match `expectedFormat` → 415\n * - a header sharp cannot read (e.g. avif without a decoder) → 415\n * - width × height over `maxSourcePixels` → 413, read from the header only\n *\n * @throws HttpError with status 413 or 415. Any other error (sharp missing,\n * I/O) propagates unchanged.\n */\nexport async function loadVariantSource(\n absolutePath: string,\n { maxSourceBytes, maxSourcePixels, expectedFormat }: LoadVariantSourceOptions,\n): Promise<Image> {\n const buffer = await fs.readFile(absolutePath);\n\n if (buffer.length > maxSourceBytes) {\n throw new HttpError(413, \"The source image is too large.\");\n }\n\n if (detectImageFormat(buffer) !== expectedFormat) {\n throw new HttpError(415, \"The source image changed format while it was read.\");\n }\n\n // Constructed outside the try below: sharp being absent is a server fault\n // (500 with the install hint), not an unsupported image.\n const image = new Image(buffer);\n\n let width: number | undefined;\n let height: number | undefined;\n\n try {\n ({ width, height } = await image.metadata());\n } catch {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (!width || !height) {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (width * height > maxSourcePixels) {\n throw new HttpError(413, \"The source image has too many pixels.\");\n }\n\n return image;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,eAAsB,kBACpB,cACA,EAAE,gBAAgB,iBAAiB,kBACnB;CAChB,MAAM,SAAS,MAAM,GAAG,SAAS,YAAY;
|
|
1
|
+
{"version":3,"file":"load-variant-source.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/load-variant-source.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { Image } from \"../../image\";\nimport { HttpError } from \"../errors\";\nimport { detectImageFormat } from \"./detect-image-format\";\nimport type { VariantSourceFormat } from \"./image-variant-types\";\n\n/**\n * Bounds and the expected format a source must match\n */\nexport type LoadVariantSourceOptions = {\n maxSourceBytes: number;\n maxSourcePixels: number;\n expectedFormat: VariantSourceFormat;\n};\n\n/**\n * Read a variant source in full and check it before it is decoded.\n *\n * The caller has already sniffed the format from the file head; this re-checks\n * the bytes actually read, the same buffer that is then resized, so the file\n * cannot be swapped between the check and the render.\n *\n * - bytes over `maxSourceBytes` → 413\n * - magic bytes that no longer match `expectedFormat` → 415\n * - a header sharp cannot read (e.g. avif without a decoder) → 415\n * - width × height over `maxSourcePixels` → 413, read from the header only\n *\n * @throws HttpError with status 413 or 415. Any other error (sharp missing,\n * I/O) propagates unchanged.\n */\nexport async function loadVariantSource(\n absolutePath: string | Buffer,\n { maxSourceBytes, maxSourcePixels, expectedFormat }: LoadVariantSourceOptions,\n): Promise<Image> {\n const buffer = Buffer.isBuffer(absolutePath) ? absolutePath : await fs.readFile(absolutePath);\n\n if (buffer.length > maxSourceBytes) {\n throw new HttpError(413, \"The source image is too large.\");\n }\n\n if (detectImageFormat(buffer) !== expectedFormat) {\n throw new HttpError(415, \"The source image changed format while it was read.\");\n }\n\n // Constructed outside the try below: sharp being absent is a server fault\n // (500 with the install hint), not an unsupported image.\n const image = new Image(buffer);\n\n let width: number | undefined;\n let height: number | undefined;\n\n try {\n ({ width, height } = await image.metadata());\n } catch {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (!width || !height) {\n throw new HttpError(415, \"The source image cannot be decoded.\");\n }\n\n if (width * height > maxSourcePixels) {\n throw new HttpError(413, \"The source image has too many pixels.\");\n }\n\n return image;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA8BA,eAAsB,kBACpB,cACA,EAAE,gBAAgB,iBAAiB,kBACnB;CAChB,MAAM,SAAS,OAAO,SAAS,YAAY,IAAI,eAAe,MAAM,GAAG,SAAS,YAAY;CAE5F,IAAI,OAAO,SAAS,gBAClB,MAAM,IAAI,UAAU,KAAK,gCAAgC;CAG3D,IAAI,kBAAkB,MAAM,MAAM,gBAChC,MAAM,IAAI,UAAU,KAAK,oDAAoD;CAK/E,MAAM,QAAQ,IAAI,MAAM,MAAM;CAE9B,IAAI;CACJ,IAAI;CAEJ,IAAI;EACF,CAAC,CAAE,OAAO,UAAW,MAAM,MAAM,SAAS;CAC5C,QAAQ;EACN,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAChE;CAEA,IAAI,CAAC,SAAS,CAAC,QACb,MAAM,IAAI,UAAU,KAAK,qCAAqC;CAGhE,IAAI,QAAQ,SAAS,iBACnB,MAAM,IAAI,UAAU,KAAK,uCAAuC;CAGlE,OAAO;AACT"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region ../../packages/core/src/http/uploads/parse-uploaded-file-query.ts
|
|
2
|
-
const ALLOWED_KEYS = new Set(["variant", "format"]);
|
|
2
|
+
const ALLOWED_KEYS = /* @__PURE__ */ new Set(["variant", "format"]);
|
|
3
3
|
/**
|
|
4
4
|
* Read the query string of an uploads request, strictly.
|
|
5
5
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-uploaded-file-query.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/parse-uploaded-file-query.ts"],"sourcesContent":["import type { UploadedFileQuery } from \"./image-variant-types\";\n\nconst ALLOWED_KEYS = new Set([\"variant\", \"format\"]);\n\n/**\n * Read the query string of an uploads request, strictly.\n *\n * It parses the raw URL rather than the framework's parsed query, because the\n * parsed form folds a repeated key into an array and a lone key into a string,\n * and a strict allowlist has to see both. Only `variant` and `format` are\n * accepted, each at most once, and `format` only next to `variant`.\n *\n * @param url - the raw request URL, path and query\n */\nexport function parseUploadedFileQuery(url: string): UploadedFileQuery {\n const queryStart = url.indexOf(\"?\");\n const rawQuery = queryStart === -1 ? \"\" : url.slice(queryStart + 1);\n\n if (rawQuery === \"\") return { type: \"original\" };\n\n const values = new Map<string, string>();\n\n for (const [key, value] of new URLSearchParams(rawQuery)) {\n if (!ALLOWED_KEYS.has(key)) {\n return { type: \"invalid\", reason: `Unknown query parameter \"${key}\".` };\n }\n\n if (values.has(key)) {\n return { type: \"invalid\", reason: `Query parameter \"${key}\" is repeated.` };\n }\n\n values.set(key, value);\n }\n\n const variant = values.get(\"variant\");\n const format = values.get(\"format\");\n\n if (variant === undefined) {\n return values.size === 0\n ? { type: \"original\" }\n : { type: \"invalid\", reason: `\"format\" requires \"variant\".` };\n }\n\n if (variant === \"\") {\n return { type: \"invalid\", reason: `\"variant\" must not be empty.` };\n }\n\n return format === undefined ? { type: \"variant\", variant } : { type: \"variant\", variant, format };\n}\n"],"mappings":";AAEA,MAAM,
|
|
1
|
+
{"version":3,"file":"parse-uploaded-file-query.mjs","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/parse-uploaded-file-query.ts"],"sourcesContent":["import type { UploadedFileQuery } from \"./image-variant-types\";\n\nconst ALLOWED_KEYS = new Set([\"variant\", \"format\"]);\n\n/**\n * Read the query string of an uploads request, strictly.\n *\n * It parses the raw URL rather than the framework's parsed query, because the\n * parsed form folds a repeated key into an array and a lone key into a string,\n * and a strict allowlist has to see both. Only `variant` and `format` are\n * accepted, each at most once, and `format` only next to `variant`.\n *\n * @param url - the raw request URL, path and query\n */\nexport function parseUploadedFileQuery(url: string): UploadedFileQuery {\n const queryStart = url.indexOf(\"?\");\n const rawQuery = queryStart === -1 ? \"\" : url.slice(queryStart + 1);\n\n if (rawQuery === \"\") return { type: \"original\" };\n\n const values = new Map<string, string>();\n\n for (const [key, value] of new URLSearchParams(rawQuery)) {\n if (!ALLOWED_KEYS.has(key)) {\n return { type: \"invalid\", reason: `Unknown query parameter \"${key}\".` };\n }\n\n if (values.has(key)) {\n return { type: \"invalid\", reason: `Query parameter \"${key}\" is repeated.` };\n }\n\n values.set(key, value);\n }\n\n const variant = values.get(\"variant\");\n const format = values.get(\"format\");\n\n if (variant === undefined) {\n return values.size === 0\n ? { type: \"original\" }\n : { type: \"invalid\", reason: `\"format\" requires \"variant\".` };\n }\n\n if (variant === \"\") {\n return { type: \"invalid\", reason: `\"variant\" must not be empty.` };\n }\n\n return format === undefined ? { type: \"variant\", variant } : { type: \"variant\", variant, format };\n}\n"],"mappings":";AAEA,MAAM,+BAAe,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;;;;;;;;;;;AAYlD,SAAgB,uBAAuB,KAAgC;CACrE,MAAM,aAAa,IAAI,QAAQ,GAAG;CAClC,MAAM,WAAW,eAAe,KAAK,KAAK,IAAI,MAAM,aAAa,CAAC;CAElE,IAAI,aAAa,IAAI,OAAO,EAAE,MAAM,WAAW;CAE/C,MAAM,yBAAS,IAAI,IAAoB;CAEvC,KAAK,MAAM,CAAC,KAAK,UAAU,IAAI,gBAAgB,QAAQ,GAAG;EACxD,IAAI,CAAC,aAAa,IAAI,GAAG,GACvB,OAAO;GAAE,MAAM;GAAW,QAAQ,4BAA4B,IAAI;EAAI;EAGxE,IAAI,OAAO,IAAI,GAAG,GAChB,OAAO;GAAE,MAAM;GAAW,QAAQ,oBAAoB,IAAI;EAAgB;EAG5E,OAAO,IAAI,KAAK,KAAK;CACvB;CAEA,MAAM,UAAU,OAAO,IAAI,SAAS;CACpC,MAAM,SAAS,OAAO,IAAI,QAAQ;CAElC,IAAI,YAAY,QACd,OAAO,OAAO,SAAS,IACnB,EAAE,MAAM,WAAW,IACnB;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGhE,IAAI,YAAY,IACd,OAAO;EAAE,MAAM;EAAW,QAAQ;CAA+B;CAGnE,OAAO,WAAW,SAAY;EAAE,MAAM;EAAW;CAAQ,IAAI;EAAE,MAAM;EAAW;EAAS;CAAO;AAClG"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { StorageDriverName } from "../../storage/types.mjs";
|
|
2
|
-
|
|
3
2
|
//#region ../../packages/core/src/http/uploads/purge-image-variants.d.ts
|
|
4
3
|
/**
|
|
5
4
|
* Options for {@link purgeImageVariants}
|
|
6
5
|
*/
|
|
7
|
-
type PurgeImageVariantsOptions = {
|
|
6
|
+
export type PurgeImageVariantsOptions = {
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
8
|
+
* Disk the source lives on; the default disk when omitted
|
|
10
9
|
*/
|
|
11
10
|
disk?: StorageDriverName;
|
|
12
11
|
};
|
|
@@ -19,14 +18,18 @@ type PurgeImageVariantsOptions = {
|
|
|
19
18
|
* `uploads.images.cacheDirectory` is set, that directory is shared by every
|
|
20
19
|
* local disk, so this clears all of them.
|
|
21
20
|
*
|
|
21
|
+
* Only recognized derivative, source-manifest and temporary files in the
|
|
22
|
+
* generated cache layout are removed. The cache root, directories, unrelated
|
|
23
|
+
* files and symlinks stay in place. Use a dedicated folder for derivatives.
|
|
24
|
+
*
|
|
22
25
|
* Deleting or moving a file through local storage (`storage.delete`,
|
|
23
26
|
* `deleteMany`, `move`) already purges its derivatives; call this for files
|
|
24
27
|
* removed some other way.
|
|
25
28
|
*
|
|
29
|
+
* @throws ImageVariantsConfigError when the cache equals or contains any
|
|
30
|
+
* configured local disk root, including through a symlink
|
|
26
31
|
* @returns `true` when something was removed
|
|
27
|
-
* @throws ImageVariantsConfigError when the disk is not a local disk
|
|
28
32
|
*/
|
|
29
|
-
declare function purgeImageVariants(relativePath?: string, options?: PurgeImageVariantsOptions): Promise<boolean>;
|
|
33
|
+
export declare function purgeImageVariants(relativePath?: string, options?: PurgeImageVariantsOptions): Promise<boolean>;
|
|
30
34
|
//#endregion
|
|
31
|
-
export { PurgeImageVariantsOptions, purgeImageVariants };
|
|
32
35
|
//# sourceMappingURL=purge-image-variants.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"purge-image-variants.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/purge-image-variants.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"purge-image-variants.d.mts","names":[],"sources":["../../../../../../../../../packages/core/src/http/uploads/purge-image-variants.ts"],"mappings":";;;;;YAeY;;;;EAIV,OAAO;;;;;;;;;;;;;;;;;;;;;;;wBAwBa,mBACpB,uBACA,UAAS,4BACR"}
|