@warlock.js/core 5.19.1 → 5.21.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 +1136 -1073
- package/esm/benchmark/benchmark.mjs +34 -25
- package/esm/benchmark/benchmark.mjs.map +1 -1
- package/esm/benchmark/profiler.d.mts.map +1 -1
- package/esm/benchmark/profiler.mjs +8 -3
- package/esm/benchmark/profiler.mjs.map +1 -1
- package/esm/bootstrap.d.mts.map +1 -1
- package/esm/bootstrap.mjs +3 -0
- package/esm/bootstrap.mjs.map +1 -1
- package/esm/cache/database-cache-driver.d.mts +2 -2
- package/esm/cache/database-cache-driver.d.mts.map +1 -1
- package/esm/cache/database-cache-driver.mjs +3 -2
- package/esm/cache/database-cache-driver.mjs.map +1 -1
- package/esm/cli/cli-commands.manager.mjs +16 -14
- package/esm/cli/cli-commands.manager.mjs.map +1 -1
- package/esm/cli/commands/add.command.mjs +1 -1
- package/esm/cli/commands/add.command.mjs.map +1 -1
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs +3 -2
- package/esm/cli/commands/doctor/checks/optional-peers.check.mjs.map +1 -1
- package/esm/cli/commands/generate/generate.command.mjs +20 -0
- package/esm/cli/commands/generate/generate.command.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/column-dsl-parser.mjs +4 -2
- package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/controller.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/controller.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/migration.generator.mjs +22 -6
- package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/model.generator.mjs +22 -7
- package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/module.generator.mjs +8 -6
- package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/repository.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/repository.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/resource.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/resource.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/generators/service.generator.mjs +1 -1
- package/esm/cli/commands/generate/generators/service.generator.mjs.map +1 -1
- package/esm/cli/commands/generate/templates/stubs.mjs +7 -7
- package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -1
- package/esm/cli/commands/generate/utils/writer.mjs +25 -1
- package/esm/cli/commands/generate/utils/writer.mjs.map +1 -1
- package/esm/cli/commands/routes/routes-command.action.mjs +5 -1
- package/esm/cli/commands/routes/routes-command.action.mjs.map +1 -1
- package/esm/cli/commands/routes/with-console-on-stderr.mjs +24 -0
- package/esm/cli/commands/routes/with-console-on-stderr.mjs.map +1 -0
- package/esm/cli/commands/routes.command.mjs +3 -4
- package/esm/cli/commands/routes.command.mjs.map +1 -1
- package/esm/cli/commands/start-production.command.mjs +5 -5
- package/esm/cli/commands/start-production.command.mjs.map +1 -1
- package/esm/cli/commands/storage-put.action.mjs +2 -1
- package/esm/cli/commands/storage-put.action.mjs.map +1 -1
- package/esm/cli/commands/update.command.mjs +1 -0
- package/esm/cli/commands/update.command.mjs.map +1 -1
- package/esm/cli/parse-cli-args.mjs +13 -1
- package/esm/cli/parse-cli-args.mjs.map +1 -1
- package/esm/commands/cli-command.d.mts.map +1 -1
- package/esm/commands/cli-command.mjs +4 -2
- package/esm/commands/cli-command.mjs.map +1 -1
- package/esm/commands/index.mjs +3 -0
- package/esm/config/config-key-from-path.mjs +20 -0
- package/esm/config/config-key-from-path.mjs.map +1 -0
- package/esm/config/config-loader.d.mts.map +1 -1
- package/esm/config/config-loader.mjs +2 -3
- package/esm/config/config-loader.mjs.map +1 -1
- package/esm/connectors/cache-connector.d.mts.map +1 -1
- package/esm/connectors/cache-connector.mjs +5 -0
- package/esm/connectors/cache-connector.mjs.map +1 -1
- package/esm/connectors/connectors-manager.d.mts +4 -0
- package/esm/connectors/connectors-manager.d.mts.map +1 -1
- package/esm/connectors/connectors-manager.mjs +30 -2
- package/esm/connectors/connectors-manager.mjs.map +1 -1
- package/esm/connectors/single-server-warnings.mjs +33 -0
- package/esm/connectors/single-server-warnings.mjs.map +1 -0
- package/esm/connectors/socket-connector.d.mts +29 -0
- package/esm/connectors/socket-connector.d.mts.map +1 -1
- package/esm/connectors/socket-connector.mjs +77 -9
- package/esm/connectors/socket-connector.mjs.map +1 -1
- package/esm/connectors/storage.connector.d.mts.map +1 -1
- package/esm/connectors/storage.connector.mjs +6 -0
- package/esm/connectors/storage.connector.mjs.map +1 -1
- package/esm/connectors/types.d.mts +4 -2
- package/esm/connectors/types.d.mts.map +1 -1
- package/esm/connectors/types.mjs.map +1 -1
- package/esm/database/models/database-log/database-log.d.mts +47 -24
- package/esm/database/models/database-log/database-log.d.mts.map +1 -1
- package/esm/database/models/database-log/database-log.mjs +36 -4
- package/esm/database/models/database-log/database-log.mjs.map +1 -1
- package/esm/database/seed-command-action.mjs +10 -2
- package/esm/database/seed-command-action.mjs.map +1 -1
- package/esm/dev-server/development-server.mjs +15 -4
- package/esm/dev-server/development-server.mjs.map +1 -1
- package/esm/dev-server/file-event-handler.mjs +26 -6
- package/esm/dev-server/file-event-handler.mjs.map +1 -1
- package/esm/dev-server/file-manager.d.mts.map +1 -1
- package/esm/dev-server/file-manager.mjs +2 -2
- package/esm/dev-server/file-manager.mjs.map +1 -1
- package/esm/dev-server/files-orchestrator.mjs +3 -1
- package/esm/dev-server/files-orchestrator.mjs.map +1 -1
- package/esm/dev-server/files-watcher.mjs +64 -5
- package/esm/dev-server/files-watcher.mjs.map +1 -1
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs +31 -9
- package/esm/dev-server/health-checker/files-healthcare.manager.mjs.map +1 -1
- package/esm/dev-server/health-checker/workers/eslint-health.worker.mjs +11 -7
- package/esm/dev-server/health-checker/workers/eslint-health.worker.mjs.map +1 -1
- package/esm/dev-server/loader/load-hook.mjs +1 -1
- package/esm/dev-server/loader/register-loader.mjs +1 -1
- package/esm/dev-server/manifest-manager.d.mts.map +1 -1
- package/esm/dev-server/manifest-manager.mjs +12 -6
- package/esm/dev-server/manifest-manager.mjs.map +1 -1
- package/esm/dev-server/parse-imports.mjs +9 -0
- package/esm/dev-server/parse-imports.mjs.map +1 -1
- package/esm/dev-server/register-dev-shortcuts.mjs +2 -1
- package/esm/dev-server/register-dev-shortcuts.mjs.map +1 -1
- package/esm/dev-server/route-types-publisher.mjs +60 -0
- package/esm/dev-server/route-types-publisher.mjs.map +1 -0
- package/esm/dev-server/shortcuts.mjs +2 -2
- package/esm/dev-server/shortcuts.mjs.map +1 -1
- package/esm/dev-server/special-file-patterns.mjs +18 -0
- package/esm/dev-server/special-file-patterns.mjs.map +1 -0
- package/esm/dev-server/special-files-collector.d.mts.map +1 -1
- package/esm/dev-server/special-files-collector.mjs +2 -5
- package/esm/dev-server/special-files-collector.mjs.map +1 -1
- package/esm/dev-server/start-development-server.mjs +1 -2
- package/esm/dev-server/start-development-server.mjs.map +1 -1
- package/esm/dev-server/supervisor.mjs +23 -3
- package/esm/dev-server/supervisor.mjs.map +1 -1
- package/esm/dev-server/tsconfig-manager.mjs +22 -12
- package/esm/dev-server/tsconfig-manager.mjs.map +1 -1
- package/esm/dev-server/type-generator.mjs +10 -9
- package/esm/dev-server/type-generator.mjs.map +1 -1
- package/esm/encryption/encrypt.d.mts.map +1 -1
- package/esm/encryption/encrypt.mjs +16 -5
- package/esm/encryption/encrypt.mjs.map +1 -1
- package/esm/encryption/hash.d.mts.map +1 -1
- package/esm/encryption/hash.mjs +2 -0
- package/esm/encryption/hash.mjs.map +1 -1
- package/esm/encryption/password.d.mts.map +1 -1
- package/esm/encryption/password.mjs +3 -1
- package/esm/encryption/password.mjs.map +1 -1
- package/esm/generations/features/index.mjs +1 -1
- package/esm/generations/features/mysql.feature.mjs +9 -2
- package/esm/generations/features/mysql.feature.mjs.map +1 -1
- package/esm/generations/features/test.feature.mjs +2 -1
- package/esm/generations/features/test.feature.mjs.map +1 -1
- package/esm/generations/features/web.feature.mjs +4 -2
- package/esm/generations/features/web.feature.mjs.map +1 -1
- package/esm/http/build-rate-limit-options.d.mts +37 -0
- package/esm/http/build-rate-limit-options.d.mts.map +1 -0
- package/esm/http/build-rate-limit-options.mjs +37 -0
- package/esm/http/build-rate-limit-options.mjs.map +1 -0
- package/esm/http/csrf-origin-policy.d.mts.map +1 -1
- package/esm/http/csrf-origin-policy.mjs +5 -2
- package/esm/http/csrf-origin-policy.mjs.map +1 -1
- package/esm/http/flush-pending-cookies.mjs +52 -0
- package/esm/http/flush-pending-cookies.mjs.map +1 -0
- package/esm/http/middleware/cache-response-middleware.d.mts.map +1 -1
- package/esm/http/middleware/cache-response-middleware.mjs +4 -2
- package/esm/http/middleware/cache-response-middleware.mjs.map +1 -1
- package/esm/http/middleware/idempotency.middleware.d.mts +5 -0
- package/esm/http/middleware/idempotency.middleware.d.mts.map +1 -1
- package/esm/http/middleware/idempotency.middleware.mjs +35 -3
- package/esm/http/middleware/idempotency.middleware.mjs.map +1 -1
- package/esm/http/middleware/inject-request-context.d.mts.map +1 -1
- package/esm/http/middleware/inject-request-context.mjs +14 -3
- package/esm/http/middleware/inject-request-context.mjs.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.d.mts +4 -3
- package/esm/http/middleware/rate-limit.middleware.d.mts.map +1 -1
- package/esm/http/middleware/rate-limit.middleware.mjs +4 -3
- package/esm/http/middleware/rate-limit.middleware.mjs.map +1 -1
- package/esm/http/middleware/utils/cidr-match.d.mts +1 -1
- package/esm/http/middleware/utils/cidr-match.d.mts.map +1 -1
- package/esm/http/middleware/utils/cidr-match.mjs +11 -2
- package/esm/http/middleware/utils/cidr-match.mjs.map +1 -1
- package/esm/http/middleware/utils/idempotency-key.mjs +1 -1
- package/esm/http/middleware/utils/idempotency-key.mjs.map +1 -1
- package/esm/http/plugins.d.mts.map +1 -1
- package/esm/http/plugins.mjs +13 -5
- package/esm/http/plugins.mjs.map +1 -1
- package/esm/http/request.d.mts +12 -1
- package/esm/http/request.d.mts.map +1 -1
- package/esm/http/request.mjs +35 -7
- package/esm/http/request.mjs.map +1 -1
- package/esm/http/response.d.mts +16 -0
- package/esm/http/response.d.mts.map +1 -1
- package/esm/http/response.mjs +75 -37
- package/esm/http/response.mjs.map +1 -1
- package/esm/http/types.d.mts +26 -14
- package/esm/http/types.d.mts.map +1 -1
- package/esm/http/uploads/uploaded-file.controller.mjs +1 -1
- package/esm/http/uploads-config.mjs +2 -1
- package/esm/http/uploads-config.mjs.map +1 -1
- package/esm/http/uploads-types.d.mts +3 -3
- package/esm/image/image.d.mts +1 -1
- package/esm/image/image.d.mts.map +1 -1
- package/esm/image/image.mjs +25 -15
- package/esm/image/image.mjs.map +1 -1
- package/esm/index.d.mts +6 -4
- package/esm/index.mjs +7 -4
- package/esm/logger/logger.mjs +6 -1
- package/esm/logger/logger.mjs.map +1 -1
- package/esm/mail/config.d.mts.map +1 -1
- package/esm/mail/config.mjs +31 -21
- package/esm/mail/config.mjs.map +1 -1
- package/esm/mail/react-mail.mjs +6 -3
- package/esm/mail/react-mail.mjs.map +1 -1
- package/esm/mail/send-mail.d.mts.map +1 -1
- package/esm/mail/send-mail.mjs +40 -19
- package/esm/mail/send-mail.mjs.map +1 -1
- package/esm/production/assert-generated-imports.mjs +1 -0
- package/esm/production/assert-generated-imports.mjs.map +1 -1
- package/esm/production/build-contributions.mjs +3 -0
- package/esm/production/build-contributions.mjs.map +1 -1
- package/esm/production/esbuild-plugins.mjs +3 -2
- package/esm/production/esbuild-plugins.mjs.map +1 -1
- package/esm/production/production-builder.mjs +49 -37
- package/esm/production/production-builder.mjs.map +1 -1
- package/esm/production/production-supervisor.mjs +12 -5
- package/esm/production/production-supervisor.mjs.map +1 -1
- package/esm/production/route-registration-child.d.mts +1 -0
- package/esm/production/route-registration-child.mjs +65 -0
- package/esm/production/route-registration-child.mjs.map +1 -0
- package/esm/production/route-registration-snapshot.mjs +166 -0
- package/esm/production/route-registration-snapshot.mjs.map +1 -0
- package/esm/repositories/adapters/cascade/cascade-adapter.d.mts +3 -1
- package/esm/repositories/adapters/cascade/cascade-adapter.d.mts.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-adapter.mjs +22 -12
- package/esm/repositories/adapters/cascade/cascade-adapter.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/cascade-query-builder.d.mts +3 -3
- package/esm/repositories/adapters/cascade/cascade-query-builder.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/filter-applicator.mjs +88 -61
- package/esm/repositories/adapters/cascade/filter-applicator.mjs.map +1 -1
- package/esm/repositories/adapters/cascade/index.d.mts +1 -1
- package/esm/repositories/adapters/cascade/index.mjs +1 -1
- package/esm/repositories/contracts/query-builder.contract.d.mts +3 -3
- package/esm/repositories/contracts/types.d.mts +5 -0
- package/esm/repositories/contracts/types.d.mts.map +1 -1
- package/esm/repositories/index.d.mts +1 -1
- package/esm/repositories/index.mjs +1 -1
- package/esm/repositories/repository.manager.d.mts +65 -3
- package/esm/repositories/repository.manager.d.mts.map +1 -1
- package/esm/repositories/repository.manager.mjs +146 -57
- package/esm/repositories/repository.manager.mjs.map +1 -1
- package/esm/resource/resource-field-builder.d.mts.map +1 -1
- package/esm/resource/resource-field-builder.mjs +1 -0
- package/esm/resource/resource-field-builder.mjs.map +1 -1
- package/esm/resource/resource.d.mts +10 -3
- package/esm/resource/resource.d.mts.map +1 -1
- package/esm/resource/resource.mjs +19 -5
- package/esm/resource/resource.mjs.map +1 -1
- package/esm/restful/restful.d.mts +12 -5
- package/esm/restful/restful.d.mts.map +1 -1
- package/esm/restful/restful.mjs +47 -16
- package/esm/restful/restful.mjs.map +1 -1
- package/esm/router/build-route-rate-limit.mjs +22 -0
- package/esm/router/build-route-rate-limit.mjs.map +1 -0
- package/esm/router/dev-dispatch.mjs +60 -0
- package/esm/router/dev-dispatch.mjs.map +1 -0
- package/esm/router/route-builder.mjs +4 -1
- package/esm/router/route-builder.mjs.map +1 -1
- package/esm/router/route-registry.d.mts.map +1 -1
- package/esm/router/route-registry.mjs +2 -2
- package/esm/router/route-registry.mjs.map +1 -1
- package/esm/router/router.d.mts +1 -1
- package/esm/router/router.d.mts.map +1 -1
- package/esm/router/router.mjs +57 -39
- package/esm/router/router.mjs.map +1 -1
- package/esm/socket/index.d.mts +1 -1
- package/esm/socket/types.d.mts +25 -3
- package/esm/socket/types.d.mts.map +1 -1
- package/esm/storage/drivers/cloud-driver.d.mts +26 -0
- package/esm/storage/drivers/cloud-driver.d.mts.map +1 -1
- package/esm/storage/drivers/cloud-driver.mjs +100 -16
- package/esm/storage/drivers/cloud-driver.mjs.map +1 -1
- package/esm/storage/drivers/do-spaces-driver.d.mts +7 -0
- package/esm/storage/drivers/do-spaces-driver.d.mts.map +1 -1
- package/esm/storage/drivers/do-spaces-driver.mjs +9 -2
- package/esm/storage/drivers/do-spaces-driver.mjs.map +1 -1
- package/esm/storage/drivers/local-driver.d.mts +16 -5
- package/esm/storage/drivers/local-driver.d.mts.map +1 -1
- package/esm/storage/drivers/local-driver.mjs +71 -28
- package/esm/storage/drivers/local-driver.mjs.map +1 -1
- package/esm/storage/index.d.mts +3 -1
- package/esm/storage/index.mjs +4 -2
- package/esm/storage/scoped-storage.d.mts +27 -1
- package/esm/storage/scoped-storage.d.mts.map +1 -1
- package/esm/storage/scoped-storage.mjs +40 -8
- package/esm/storage/scoped-storage.mjs.map +1 -1
- package/esm/storage/storage.d.mts +11 -5
- package/esm/storage/storage.d.mts.map +1 -1
- package/esm/storage/storage.mjs +39 -16
- package/esm/storage/storage.mjs.map +1 -1
- package/esm/storage/types.d.mts +43 -4
- package/esm/storage/types.d.mts.map +1 -1
- package/esm/storage/utils/classify-ip-address.d.mts +13 -0
- package/esm/storage/utils/classify-ip-address.d.mts.map +1 -0
- package/esm/storage/utils/classify-ip-address.mjs +98 -0
- package/esm/storage/utils/classify-ip-address.mjs.map +1 -0
- package/esm/storage/utils/safe-fetch.d.mts +3 -12
- package/esm/storage/utils/safe-fetch.d.mts.map +1 -1
- package/esm/storage/utils/safe-fetch.mjs +3 -48
- package/esm/storage/utils/safe-fetch.mjs.map +1 -1
- package/esm/storage/utils/storage-capability-error.d.mts +25 -0
- package/esm/storage/utils/storage-capability-error.d.mts.map +1 -0
- package/esm/storage/utils/storage-capability-error.mjs +26 -0
- package/esm/storage/utils/storage-capability-error.mjs.map +1 -0
- package/esm/updater/update-warlock-packages.mjs +11 -1
- package/esm/updater/update-warlock-packages.mjs.map +1 -1
- package/esm/use-cases/use-case-broadcast.mjs +7 -1
- package/esm/use-cases/use-case-broadcast.mjs.map +1 -1
- package/esm/use-cases/use-cases-registry.mjs +21 -2
- package/esm/use-cases/use-cases-registry.mjs.map +1 -1
- package/esm/utils/database-log.mjs +0 -3
- package/esm/utils/database-log.mjs.map +1 -1
- package/esm/utils/queue.d.mts +6 -4
- package/esm/utils/queue.d.mts.map +1 -1
- package/esm/utils/queue.mjs +20 -9
- package/esm/utils/queue.mjs.map +1 -1
- package/esm/validation/database/exists-except-current-id.mjs +6 -2
- package/esm/validation/database/exists-except-current-id.mjs.map +1 -1
- package/esm/validation/database/unique-except-current-id.mjs +6 -2
- package/esm/validation/database/unique-except-current-id.mjs.map +1 -1
- package/esm/validation/init.mjs +6 -2
- package/esm/validation/init.mjs.map +1 -1
- package/esm/validation/validateAll.mjs +3 -2
- package/esm/validation/validateAll.mjs.map +1 -1
- package/esm/warlock-config/types.d.mts +14 -1
- package/esm/warlock-config/types.d.mts.map +1 -1
- package/esm/warlock-config/warlock-config.manager.d.mts.map +1 -1
- package/esm/warlock-config/warlock-config.manager.mjs +3 -1
- package/esm/warlock-config/warlock-config.manager.mjs.map +1 -1
- package/esm/warlock-config/warn-deprecated-config.mjs +25 -0
- package/esm/warlock-config/warn-deprecated-config.mjs.map +1 -0
- package/llms-full.txt +71 -42
- package/llms.txt +41 -41
- package/package.json +21 -15
- package/skills/add-connector/SKILL.md +5 -1
- package/skills/benchmark-code/SKILL.md +1 -1
- package/skills/build-restful/SKILL.md +1 -1
- package/skills/build-url/SKILL.md +1 -1
- package/skills/configure-app/SKILL.md +7 -1
- package/skills/create-controller/SKILL.md +1 -1
- package/skills/create-module/SKILL.md +1 -1
- package/skills/define-resource/SKILL.md +1 -1
- package/skills/encrypt-data/SKILL.md +1 -1
- package/skills/hash-password/SKILL.md +1 -1
- package/skills/health-checks/SKILL.md +1 -1
- package/skills/index.md +30 -0
- package/skills/lower-stage3-decorators/SKILL.md +1 -1
- package/skills/process-image/SKILL.md +1 -1
- package/skills/register-route/SKILL.md +1 -1
- package/skills/request-memo/SKILL.md +1 -1
- package/skills/request-tracing/SKILL.md +1 -1
- package/skills/resolve-path/SKILL.md +1 -1
- package/skills/retry-operation/SKILL.md +1 -1
- package/skills/run-app/SKILL.md +1 -1
- package/skills/send-mail/SKILL.md +1 -1
- package/skills/send-response/SKILL.md +1 -1
- package/skills/store-file/SKILL.md +11 -1
- package/skills/test-http/SKILL.md +1 -1
- package/skills/test-service/SKILL.md +1 -1
- package/skills/update-packages/SKILL.md +1 -1
- package/skills/upload-file/SKILL.md +1 -1
- package/skills/use-app-context/SKILL.md +1 -1
- package/skills/use-localization/SKILL.md +1 -1
- package/skills/use-middleware/SKILL.md +7 -2
- package/skills/use-model-transformers/SKILL.md +1 -1
- package/skills/use-repository/SKILL.md +1 -1
- package/skills/use-request-locals/SKILL.md +1 -1
- package/skills/validate-input/SKILL.md +1 -1
- package/skills/warlock-conventions/SKILL.md +1 -1
- package/skills/warlock-doctor/SKILL.md +1 -1
- package/skills/warlock-routes/SKILL.md +1 -1
- package/skills/wire-socket/SKILL.md +5 -1
- package/skills/write-cli-command/SKILL.md +1 -1
- package/skills/write-middleware/SKILL.md +1 -1
- package/skills/write-seeder/SKILL.md +1 -1
- package/skills/write-use-case/SKILL.md +1 -1
- package/esm/_virtual/_rolldown/runtime.mjs +0 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-registration-child.mjs","names":[],"sources":["../../../../../../../core/src/production/route-registration-child.ts"],"sourcesContent":["import { fileExistsAsync } from \"@warlock.js/fs\";\nimport { Application } from \"../application\";\nimport { bootstrap } from \"../bootstrap\";\nimport { loadConfigFiles } from \"../config/load-config-files\";\nimport { filesOrchestrator } from \"../dev-server/files-orchestrator\";\nimport { router } from \"../router/router\";\nimport { loadEnvironmentFiles } from \"../utils/load-environment\";\nimport { appPath } from \"../utils/paths\";\nimport type { Environment, RuntimeStrategy } from \"../utils/environment\";\nimport { warlockConfigManager } from \"../warlock-config/warlock-config.manager\";\n\nconst PROTOCOL_VERSION = 1;\n\ntype RequestMessage = Readonly<{\n version: typeof PROTOCOL_VERSION;\n cwd: string;\n environment?: Environment;\n runtimeStrategy?: RuntimeStrategy;\n}>;\n\nprocess.once(\"message\", async (message: unknown) => {\n try {\n const request = validateRequest(message);\n process.chdir(request.cwd);\n\n if (request.environment) Application.setEnvironment(request.environment);\n if (request.runtimeStrategy) Application.setRuntimeStrategy(request.runtimeStrategy);\n\n await loadEnvironmentFiles();\n await warlockConfigManager.load();\n await filesOrchestrator.init();\n await bootstrap();\n\n if (await fileExistsAsync(appPath(\"bootstrap.ts\"))) {\n await filesOrchestrator.load(\"src/app/bootstrap.ts\");\n }\n\n await filesOrchestrator.initializeAll();\n filesOrchestrator.specialFilesCollector.collect(filesOrchestrator.getFiles());\n await loadConfigFiles(true);\n\n for (const file of filesOrchestrator.files.values()) {\n if (file.type === \"model\") {\n await filesOrchestrator.moduleLoader.loadModule(file, \"model\");\n }\n }\n\n await filesOrchestrator.moduleLoader.loadAll();\n\n await sendAndExit({\n type: \"route-registration:snapshot\",\n snapshot: { version: PROTOCOL_VERSION, routes: router.getNamedApiRoutes() },\n });\n } catch (error) {\n const message = error instanceof Error ? error.stack || error.message : String(error);\n await sendAndExit({ type: \"route-registration:error\", message }, 1);\n }\n});\n\nfunction validateRequest(value: unknown): RequestMessage {\n if (\n typeof value !== \"object\" ||\n value === null ||\n (value as { version?: unknown }).version !== PROTOCOL_VERSION ||\n typeof (value as { cwd?: unknown }).cwd !== \"string\" ||\n !isOptionalEnvironment((value as { environment?: unknown }).environment) ||\n !isOptionalRuntimeStrategy((value as { runtimeStrategy?: unknown }).runtimeStrategy)\n ) {\n throw new Error(\"Route registration child received an invalid protocol request.\");\n }\n\n return value as RequestMessage;\n}\n\nfunction isOptionalEnvironment(value: unknown): value is Environment | undefined {\n return (\n value === undefined || value === \"development\" || value === \"production\" || value === \"test\"\n );\n}\n\nfunction isOptionalRuntimeStrategy(value: unknown): value is RuntimeStrategy | undefined {\n return value === undefined || value === \"development\" || value === \"production\";\n}\n\nasync function sendAndExit(message: unknown, exitCode = 0): Promise<never> {\n if (typeof process.send !== \"function\") {\n throw new Error(\"Route registration child requires an IPC channel.\");\n }\n\n await new Promise<void>((resolve, reject) => {\n process.send!(message, (error) => (error ? reject(error) : resolve()));\n });\n process.disconnect?.();\n process.exit(exitCode);\n}\n"],"mappings":";;;;;;;;;;;;AAWA,MAAM,mBAAmB;AASzB,QAAQ,KAAK,WAAW,OAAO,YAAqB;CAClD,IAAI;EACF,MAAM,UAAU,gBAAgB,OAAO;EACvC,QAAQ,MAAM,QAAQ,GAAG;EAEzB,IAAI,QAAQ,aAAa,YAAY,eAAe,QAAQ,WAAW;EACvE,IAAI,QAAQ,iBAAiB,YAAY,mBAAmB,QAAQ,eAAe;EAEnF,MAAM,qBAAqB;EAC3B,MAAM,qBAAqB,KAAK;EAChC,MAAM,kBAAkB,KAAK;EAC7B,MAAM,UAAU;EAEhB,IAAI,MAAM,gBAAgB,QAAQ,cAAc,CAAC,GAC/C,MAAM,kBAAkB,KAAK,sBAAsB;EAGrD,MAAM,kBAAkB,cAAc;EACtC,kBAAkB,sBAAsB,QAAQ,kBAAkB,SAAS,CAAC;EAC5E,MAAM,gBAAgB,IAAI;EAE1B,KAAK,MAAM,QAAQ,kBAAkB,MAAM,OAAO,GAChD,IAAI,KAAK,SAAS,SAChB,MAAM,kBAAkB,aAAa,WAAW,MAAM,OAAO;EAIjE,MAAM,kBAAkB,aAAa,QAAQ;EAE7C,MAAM,YAAY;GAChB,MAAM;GACN,UAAU;IAAE,SAAS;IAAkB,QAAQ,OAAO,kBAAkB;GAAE;EAC5E,CAAC;CACH,SAAS,OAAO;EAEd,MAAM,YAAY;GAAE,MAAM;GAA4B,SADtC,iBAAiB,QAAQ,MAAM,SAAS,MAAM,UAAU,OAAO,KAAK;EACtB,GAAG,CAAC;CACpE;AACF,CAAC;AAED,SAAS,gBAAgB,OAAgC;CACvD,IACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAgC,YAAY,oBAC7C,OAAQ,MAA4B,QAAQ,YAC5C,CAAC,sBAAuB,MAAoC,WAAW,KACvE,CAAC,0BAA2B,MAAwC,eAAe,GAEnF,MAAM,IAAI,MAAM,gEAAgE;CAGlF,OAAO;AACT;AAEA,SAAS,sBAAsB,OAAkD;CAC/E,OACE,UAAU,UAAa,UAAU,iBAAiB,UAAU,gBAAgB,UAAU;AAE1F;AAEA,SAAS,0BAA0B,OAAsD;CACvF,OAAO,UAAU,UAAa,UAAU,iBAAiB,UAAU;AACrE;AAEA,eAAe,YAAY,SAAkB,WAAW,GAAmB;CACzE,IAAI,OAAO,QAAQ,SAAS,YAC1B,MAAM,IAAI,MAAM,mDAAmD;CAGrE,MAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,QAAQ,KAAM,UAAU,UAAW,QAAQ,OAAO,KAAK,IAAI,QAAQ,CAAE;CACvE,CAAC;CACD,QAAQ,aAAa;CACrB,QAAQ,KAAK,QAAQ;AACvB"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { fork } from "node:child_process";
|
|
5
|
+
|
|
6
|
+
//#region ../core/src/production/route-registration-snapshot.ts
|
|
7
|
+
const PROTOCOL_VERSION = 1;
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
9
|
+
const MAX_DIAGNOSTIC_BYTES = 16384;
|
|
10
|
+
/**
|
|
11
|
+
* Collect named application API routes in a fresh process.
|
|
12
|
+
*
|
|
13
|
+
* The child imports application registration modules but deliberately does not
|
|
14
|
+
* register, boot, or start connectors. Application module top-level code can
|
|
15
|
+
* still have arbitrary user-owned side effects; this boundary is framework-only.
|
|
16
|
+
*/
|
|
17
|
+
function collectRouteRegistrationSnapshot(options = {}) {
|
|
18
|
+
const cwd = options.cwd ?? process.cwd();
|
|
19
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
20
|
+
const forkProcess = options.forkProcess ?? defaultForkProcess;
|
|
21
|
+
const entry = options.childEntry ?? (options.forkProcess ? "<injected-route-registration-child>" : resolveCompiledChildEntry());
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
const child = forkProcess(entry, { cwd });
|
|
24
|
+
let settled = false;
|
|
25
|
+
let receivedSnapshot;
|
|
26
|
+
let stdout = "";
|
|
27
|
+
let stderr = "";
|
|
28
|
+
const append = (current, chunk) => {
|
|
29
|
+
const remaining = MAX_DIAGNOSTIC_BYTES - Buffer.byteLength(current);
|
|
30
|
+
return remaining <= 0 ? current : current + chunk.toString("utf8", 0, remaining);
|
|
31
|
+
};
|
|
32
|
+
const finish = (error, snapshot) => {
|
|
33
|
+
if (settled) return;
|
|
34
|
+
settled = true;
|
|
35
|
+
clearTimeout(timeout);
|
|
36
|
+
if (child.connected) child.disconnect?.();
|
|
37
|
+
if (error) {
|
|
38
|
+
child.kill?.();
|
|
39
|
+
reject(error);
|
|
40
|
+
} else resolve(snapshot);
|
|
41
|
+
};
|
|
42
|
+
child.stdout?.on("data", (chunk) => {
|
|
43
|
+
stdout = append(stdout, chunk);
|
|
44
|
+
});
|
|
45
|
+
child.stderr?.on("data", (chunk) => {
|
|
46
|
+
stderr = append(stderr, chunk);
|
|
47
|
+
});
|
|
48
|
+
const timeout = setTimeout(() => {
|
|
49
|
+
finish(/* @__PURE__ */ new Error(`Route registration child timed out after ${timeoutMs}ms.${formatDiagnostics(stdout, stderr)}`));
|
|
50
|
+
}, timeoutMs);
|
|
51
|
+
timeout.unref?.();
|
|
52
|
+
child.on("error", (error) => {
|
|
53
|
+
finish(/* @__PURE__ */ new Error(`Could not start route registration child: ${error.message}${formatDiagnostics(stdout, stderr)}`));
|
|
54
|
+
});
|
|
55
|
+
child.on("message", (message) => {
|
|
56
|
+
if (!isChildMessage(message)) return;
|
|
57
|
+
if (message.type === "route-registration:error") {
|
|
58
|
+
finish(/* @__PURE__ */ new Error(`Route registration child failed: ${message.message}${formatDiagnostics(stdout, stderr)}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const snapshot = validateSnapshot(message.snapshot);
|
|
63
|
+
if (receivedSnapshot) {
|
|
64
|
+
finish(/* @__PURE__ */ new Error("Route registration child sent more than one snapshot."));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
receivedSnapshot = snapshot;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
finish(error);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
child.on("close", (code) => {
|
|
73
|
+
if (settled) return;
|
|
74
|
+
if (code === 0 && receivedSnapshot) {
|
|
75
|
+
finish(void 0, receivedSnapshot);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
finish(/* @__PURE__ */ new Error(`Route registration child exited ${code ?? "by signal"} without a valid snapshot.${formatDiagnostics(stdout, stderr)}`));
|
|
79
|
+
});
|
|
80
|
+
if (!child.send) {
|
|
81
|
+
finish(/* @__PURE__ */ new Error("Route registration child did not provide an IPC send channel."));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
child.send({
|
|
85
|
+
version: PROTOCOL_VERSION,
|
|
86
|
+
cwd,
|
|
87
|
+
environment: options.environment,
|
|
88
|
+
runtimeStrategy: options.runtimeStrategy
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function defaultForkProcess(entry, options) {
|
|
93
|
+
return fork(entry, [], {
|
|
94
|
+
cwd: options.cwd,
|
|
95
|
+
stdio: [
|
|
96
|
+
"ignore",
|
|
97
|
+
"pipe",
|
|
98
|
+
"pipe",
|
|
99
|
+
"ipc"
|
|
100
|
+
],
|
|
101
|
+
windowsHide: true
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/** Resolve from Core's package root, not an assumed bundler-preserved dirname. */
|
|
105
|
+
function resolveCompiledChildEntry() {
|
|
106
|
+
let directory = path.dirname(fileURLToPath(import.meta.url));
|
|
107
|
+
while (directory !== path.dirname(directory)) {
|
|
108
|
+
const packageJson = path.join(directory, "package.json");
|
|
109
|
+
if (existsSync(packageJson)) try {
|
|
110
|
+
if (JSON.parse(readFileSync(packageJson, "utf8")).name === "@warlock.js/core") {
|
|
111
|
+
const child = path.join(directory, "esm", "production", "route-registration-child.mjs");
|
|
112
|
+
if (existsSync(child)) return child;
|
|
113
|
+
throw new Error(`@warlock.js/core is missing its compiled route-registration child at ${child}. Reinstall a complete package.`);
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (error instanceof Error && error.message.includes("route-registration child")) throw error;
|
|
117
|
+
}
|
|
118
|
+
directory = path.dirname(directory);
|
|
119
|
+
}
|
|
120
|
+
throw new Error("Could not locate @warlock.js/core package root for the route-registration child.");
|
|
121
|
+
}
|
|
122
|
+
function isChildMessage(value) {
|
|
123
|
+
return typeof value === "object" && value !== null && "type" in value && (value.type === "route-registration:snapshot" || value.type === "route-registration:error");
|
|
124
|
+
}
|
|
125
|
+
function validateSnapshot(value) {
|
|
126
|
+
if (!isRecord(value) || value.version !== PROTOCOL_VERSION || !Array.isArray(value.routes)) throw new Error("Route registration child sent an invalid snapshot protocol payload.");
|
|
127
|
+
const routes = value.routes.map((route) => {
|
|
128
|
+
if (!isRecord(route) || typeof route.name !== "string" || typeof route.path !== "string" || !isRequestMethod(route.method)) throw new Error("Route registration child sent an invalid route record.");
|
|
129
|
+
if (Object.keys(route).length !== 3) throw new Error("Route registration child sent a route record with non-browser-safe fields.");
|
|
130
|
+
return Object.freeze({
|
|
131
|
+
name: route.name,
|
|
132
|
+
path: route.path,
|
|
133
|
+
method: normalizeRequestMethod(route.method)
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
return Object.freeze({
|
|
137
|
+
version: PROTOCOL_VERSION,
|
|
138
|
+
routes: Object.freeze(routes)
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function isRecord(value) {
|
|
142
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
143
|
+
}
|
|
144
|
+
function isRequestMethod(value) {
|
|
145
|
+
return typeof value === "string" && [
|
|
146
|
+
"get",
|
|
147
|
+
"post",
|
|
148
|
+
"put",
|
|
149
|
+
"delete",
|
|
150
|
+
"patch",
|
|
151
|
+
"options",
|
|
152
|
+
"head",
|
|
153
|
+
"all"
|
|
154
|
+
].includes(value.toLowerCase());
|
|
155
|
+
}
|
|
156
|
+
function normalizeRequestMethod(value) {
|
|
157
|
+
return value.toLowerCase() === "all" ? "all" : value.toUpperCase();
|
|
158
|
+
}
|
|
159
|
+
function formatDiagnostics(stdout, stderr) {
|
|
160
|
+
if (!stdout && !stderr) return "";
|
|
161
|
+
return `\nChild stdout:\n${stdout}\nChild stderr:\n${stderr}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
//#endregion
|
|
165
|
+
export { collectRouteRegistrationSnapshot };
|
|
166
|
+
//# sourceMappingURL=route-registration-snapshot.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-registration-snapshot.mjs","names":[],"sources":["../../../../../../../core/src/production/route-registration-snapshot.ts"],"sourcesContent":["import { fork, type ChildProcess } from \"node:child_process\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NamedApiRoute, RequestMethod } from \"../router/types\";\nimport type { Environment, RuntimeStrategy } from \"../utils/environment\";\n\nconst PROTOCOL_VERSION = 1;\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_DIAGNOSTIC_BYTES = 16_384;\n\nexport type RouteRegistrationSnapshot = Readonly<{\n version: typeof PROTOCOL_VERSION;\n routes: readonly NamedApiRoute[];\n}>;\n\nexport type RouteRegistrationChildRequest = Readonly<{\n version: typeof PROTOCOL_VERSION;\n cwd: string;\n environment?: Environment;\n runtimeStrategy?: RuntimeStrategy;\n}>;\n\ntype RouteRegistrationChildMessage =\n | Readonly<{ type: \"route-registration:snapshot\"; snapshot: unknown }>\n | Readonly<{ type: \"route-registration:error\"; message: string }>;\n\nexport type RouteRegistrationChildProcess = Pick<\n ChildProcess,\n \"send\" | \"kill\" | \"disconnect\" | \"on\" | \"stdout\" | \"stderr\" | \"connected\"\n>;\n\nexport type RouteRegistrationSnapshotOptions = Readonly<{\n cwd?: string;\n environment?: Environment;\n runtimeStrategy?: RuntimeStrategy;\n timeoutMs?: number;\n childEntry?: string;\n forkProcess?: (entry: string, options: { cwd: string }) => RouteRegistrationChildProcess;\n}>;\n\n/**\n * Collect named application API routes in a fresh process.\n *\n * The child imports application registration modules but deliberately does not\n * register, boot, or start connectors. Application module top-level code can\n * still have arbitrary user-owned side effects; this boundary is framework-only.\n */\nexport function collectRouteRegistrationSnapshot(\n options: RouteRegistrationSnapshotOptions = {},\n): Promise<RouteRegistrationSnapshot> {\n const cwd = options.cwd ?? process.cwd();\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const forkProcess = options.forkProcess ?? defaultForkProcess;\n // An injected fork is a protocol seam, not an installation check. Unit\n // fixtures do not have a packaged ESM child and do not need to resolve one.\n const entry =\n options.childEntry ??\n (options.forkProcess ? \"<injected-route-registration-child>\" : resolveCompiledChildEntry());\n\n return new Promise<RouteRegistrationSnapshot>((resolve, reject) => {\n const child = forkProcess(entry, { cwd });\n let settled = false;\n let receivedSnapshot: RouteRegistrationSnapshot | undefined;\n let stdout = \"\";\n let stderr = \"\";\n\n const append = (current: string, chunk: Buffer) => {\n const remaining = MAX_DIAGNOSTIC_BYTES - Buffer.byteLength(current);\n return remaining <= 0 ? current : current + chunk.toString(\"utf8\", 0, remaining);\n };\n\n const finish = (error?: Error, snapshot?: RouteRegistrationSnapshot) => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n\n if (child.connected) child.disconnect?.();\n if (error) {\n child.kill?.();\n reject(error);\n } else {\n resolve(snapshot!);\n }\n };\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n stdout = append(stdout, chunk);\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n stderr = append(stderr, chunk);\n });\n\n const timeout = setTimeout(() => {\n finish(\n new Error(\n `Route registration child timed out after ${timeoutMs}ms.${formatDiagnostics(stdout, stderr)}`,\n ),\n );\n }, timeoutMs);\n timeout.unref?.();\n\n child.on(\"error\", (error) => {\n finish(\n new Error(\n `Could not start route registration child: ${error.message}${formatDiagnostics(stdout, stderr)}`,\n ),\n );\n });\n\n child.on(\"message\", (message: unknown) => {\n if (!isChildMessage(message)) return;\n\n if (message.type === \"route-registration:error\") {\n finish(\n new Error(\n `Route registration child failed: ${message.message}${formatDiagnostics(stdout, stderr)}`,\n ),\n );\n return;\n }\n\n try {\n const snapshot = validateSnapshot(message.snapshot);\n if (receivedSnapshot) {\n finish(new Error(\"Route registration child sent more than one snapshot.\"));\n return;\n }\n\n receivedSnapshot = snapshot;\n } catch (error) {\n finish(error as Error);\n }\n });\n\n child.on(\"close\", (code) => {\n if (settled) return;\n\n if (code === 0 && receivedSnapshot) {\n finish(undefined, receivedSnapshot);\n return;\n }\n\n finish(\n new Error(\n `Route registration child exited ${code ?? \"by signal\"} without a valid snapshot.${formatDiagnostics(stdout, stderr)}`,\n ),\n );\n });\n\n if (!child.send) {\n finish(new Error(\"Route registration child did not provide an IPC send channel.\"));\n return;\n }\n\n child.send({\n version: PROTOCOL_VERSION,\n cwd,\n environment: options.environment,\n runtimeStrategy: options.runtimeStrategy,\n } satisfies RouteRegistrationChildRequest);\n });\n}\n\nfunction defaultForkProcess(\n entry: string,\n options: { cwd: string },\n): RouteRegistrationChildProcess {\n const forkOptions: NonNullable<Parameters<typeof fork>[2]> & { windowsHide?: boolean } = {\n cwd: options.cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\", \"ipc\"],\n windowsHide: true,\n };\n return fork(entry, [], forkOptions);\n}\n\n/** Resolve from Core's package root, not an assumed bundler-preserved dirname. */\nfunction resolveCompiledChildEntry(): string {\n let directory = path.dirname(fileURLToPath(import.meta.url));\n\n while (directory !== path.dirname(directory)) {\n const packageJson = path.join(directory, \"package.json\");\n if (existsSync(packageJson)) {\n try {\n if (JSON.parse(readFileSync(packageJson, \"utf8\")).name === \"@warlock.js/core\") {\n const child = path.join(directory, \"esm\", \"production\", \"route-registration-child.mjs\");\n if (existsSync(child)) return child;\n throw new Error(\n `@warlock.js/core is missing its compiled route-registration child at ${child}. Reinstall a complete package.`,\n );\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"route-registration child\"))\n throw error;\n }\n }\n directory = path.dirname(directory);\n }\n\n throw new Error(\n \"Could not locate @warlock.js/core package root for the route-registration child.\",\n );\n}\n\nfunction isChildMessage(value: unknown): value is RouteRegistrationChildMessage {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"type\" in value &&\n ((value as { type?: unknown }).type === \"route-registration:snapshot\" ||\n (value as { type?: unknown }).type === \"route-registration:error\")\n );\n}\n\nfunction validateSnapshot(value: unknown): RouteRegistrationSnapshot {\n if (!isRecord(value) || value.version !== PROTOCOL_VERSION || !Array.isArray(value.routes)) {\n throw new Error(\"Route registration child sent an invalid snapshot protocol payload.\");\n }\n\n const routes = value.routes.map((route) => {\n if (\n !isRecord(route) ||\n typeof route.name !== \"string\" ||\n typeof route.path !== \"string\" ||\n !isRequestMethod(route.method)\n ) {\n throw new Error(\"Route registration child sent an invalid route record.\");\n }\n\n if (Object.keys(route).length !== 3) {\n throw new Error(\"Route registration child sent a route record with non-browser-safe fields.\");\n }\n\n return Object.freeze({\n name: route.name,\n path: route.path,\n method: normalizeRequestMethod(route.method),\n });\n });\n\n return Object.freeze({ version: PROTOCOL_VERSION, routes: Object.freeze(routes) });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRequestMethod(value: unknown): value is RequestMethod {\n return (\n typeof value === \"string\" &&\n [\"get\", \"post\", \"put\", \"delete\", \"patch\", \"options\", \"head\", \"all\"].includes(\n value.toLowerCase(),\n )\n );\n}\n\nfunction normalizeRequestMethod(value: RequestMethod | string): RequestMethod {\n return value.toLowerCase() === \"all\" ? \"all\" : (value.toUpperCase() as RequestMethod);\n}\n\nfunction formatDiagnostics(stdout: string, stderr: string): string {\n if (!stdout && !stderr) return \"\";\n return `\\nChild stdout:\\n${stdout}\\nChild stderr:\\n${stderr}`;\n}\n"],"mappings":"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"}
|
|
@@ -4,6 +4,8 @@ import { QueryBuilderContract as QueryBuilderContract$1 } from "../../contracts/
|
|
|
4
4
|
import { ChildModel, Model } from "@warlock.js/cascade";
|
|
5
5
|
|
|
6
6
|
//#region ../core/src/repositories/adapters/cascade/cascade-adapter.d.ts
|
|
7
|
+
/** Records loaded and written per `updateMany` batch. */
|
|
8
|
+
declare const UPDATE_MANY_BATCH_SIZE = 500;
|
|
7
9
|
/**
|
|
8
10
|
* Cascade adapter for Cascade-Next ORM
|
|
9
11
|
* Implements RepositoryAdapterContract for @warlock.js/cascade
|
|
@@ -87,5 +89,5 @@ declare class CascadeAdapter<T extends Model<any>> implements RepositoryAdapterC
|
|
|
87
89
|
createModel(data: any): T;
|
|
88
90
|
}
|
|
89
91
|
//#endregion
|
|
90
|
-
export { CascadeAdapter };
|
|
92
|
+
export { CascadeAdapter, UPDATE_MANY_BATCH_SIZE };
|
|
91
93
|
//# sourceMappingURL=cascade-adapter.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade-adapter.d.mts","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-adapter.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"cascade-adapter.d.mts","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-adapter.ts"],"mappings":";;;;;;;cAYa,sBAAA;;;;AAAb;;;cAQa,cAAA,WAAyB,KAAA,kBAAuB,yBAAA,CAA0B,CAAA;EAAA,QAK1D,KAAA;EALhB;;;;cAKgB,KAAA,EAAO,UAAA,CAAW,CAAA;EAAA;;;EAStC,KAAA,IAAS,sBAAA,CAAqB,CAAA;EAoCD;;;EA7B7B,cAAA,CAAe,cAAA;EA2CO;;;EAdhB,IAAA,CAAK,EAAA,QAAU,OAAA,CAAQ,CAAA;EA0Ca;;;EAnCpC,MAAA,CAAO,MAAA,UAAgB,KAAA,QAAa,OAAA,CAAQ,CAAA;EAoGnB;;;EA7F/B,cAAA,CAAe,KAAA,EAAO,CAAA;EAwIuB;;;EAjI7C,gBAAA,CAAiB,IAAA,QAAY,CAAA;EA0IjC;;;EAnII,qBAAA;EAyJwB;;;EAlJlB,MAAA,CAAO,IAAA,QAAY,OAAA,CAAQ,CAAA;EArFd;;;EA4Fb,MAAA,CAAO,EAAA,OAAS,IAAA,QAAY,OAAA,CAAQ,CAAA;EAvFtB;;;EAoGd,MAAA,CAAO,EAAA,QAAU,OAAA;EApGH;;;EAoHd,UAAA,CAAW,MAAA,OAAa,IAAA,QAAY,OAAA;EApG1C;;;EAwIM,UAAA,CAAW,MAAA,QAAc,OAAA;EA3GV;;;EAqIf,KAAA,CAAM,MAAA,SAAe,OAAA;EA9HE;;;EA+IvB,QAAA,CAAS,IAAA,UAAc,KAAA,WAAgB,OAAA,CAAQ,gBAAA,CAAiB,CAAA;EAxIhD;;;EA+IhB,cAAA,CACX,OAAA,EAAS,uBAAA,GACR,OAAA,CAAQ,sBAAA,CAAuB,CAAA;EA1IE;;;EAqJvB,KAAA,CAAM,IAAA,UAAc,QAAA,EAAU,aAAA,CAAc,CAAA,IAAK,OAAA;EAvI9B;;;EAkJzB,WAAA,CAAY,IAAA,QAAY,CAAA;AAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { CascadeQueryBuilder } from "./cascade-query-builder.mjs";
|
|
2
|
-
import { Model } from "@warlock.js/cascade";
|
|
2
|
+
import { Model, afterCommit } from "@warlock.js/cascade";
|
|
3
3
|
|
|
4
4
|
//#region ../core/src/repositories/adapters/cascade/cascade-adapter.ts
|
|
5
|
+
/** Records loaded and written per `updateMany` batch. */
|
|
6
|
+
const UPDATE_MANY_BATCH_SIZE = 500;
|
|
5
7
|
/**
|
|
6
8
|
* Cascade adapter for Cascade-Next ORM
|
|
7
9
|
* Implements RepositoryAdapterContract for @warlock.js/cascade
|
|
@@ -28,13 +30,11 @@ var CascadeAdapter = class {
|
|
|
28
30
|
registerEvents(eventsCallback) {
|
|
29
31
|
const events = [];
|
|
30
32
|
const modelEvents = this.model.events();
|
|
31
|
-
|
|
33
|
+
const handle = (model) => {
|
|
32
34
|
eventsCallback(model);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
eventsCallback(model);
|
|
37
|
-
}));
|
|
35
|
+
afterCommit(() => eventsCallback(model));
|
|
36
|
+
};
|
|
37
|
+
events.push(modelEvents.onCreated(handle), modelEvents.onUpdated(handle), modelEvents.onDeleted(handle));
|
|
38
38
|
return events;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
@@ -86,7 +86,9 @@ var CascadeAdapter = class {
|
|
|
86
86
|
* {@inheritDoc RepositoryAdapterContract.delete}
|
|
87
87
|
*/
|
|
88
88
|
async delete(id) {
|
|
89
|
-
await this.model.
|
|
89
|
+
const record = id instanceof Model ? id : await this.model.find(id);
|
|
90
|
+
if (!record) return;
|
|
91
|
+
await record.destroy();
|
|
90
92
|
}
|
|
91
93
|
/**
|
|
92
94
|
* {@inheritDoc RepositoryAdapterContract.updateMany}
|
|
@@ -94,9 +96,17 @@ var CascadeAdapter = class {
|
|
|
94
96
|
async updateMany(filter, data) {
|
|
95
97
|
const query = this.query();
|
|
96
98
|
if (typeof filter === "object") query.where(filter);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
let updated = 0;
|
|
100
|
+
await query.chunk(500, async (records) => {
|
|
101
|
+
const writeBatch = async () => {
|
|
102
|
+
for (const record of records) await record.save({ merge: data });
|
|
103
|
+
};
|
|
104
|
+
const runInTransaction = this.model.transaction;
|
|
105
|
+
if (typeof runInTransaction === "function") await runInTransaction.call(this.model, writeBatch);
|
|
106
|
+
else await writeBatch();
|
|
107
|
+
updated += records.length;
|
|
108
|
+
});
|
|
109
|
+
return updated;
|
|
100
110
|
}
|
|
101
111
|
/**
|
|
102
112
|
* {@inheritDoc RepositoryAdapterContract.deleteMany}
|
|
@@ -143,5 +153,5 @@ var CascadeAdapter = class {
|
|
|
143
153
|
};
|
|
144
154
|
|
|
145
155
|
//#endregion
|
|
146
|
-
export { CascadeAdapter };
|
|
156
|
+
export { CascadeAdapter, UPDATE_MANY_BATCH_SIZE };
|
|
147
157
|
//# sourceMappingURL=cascade-adapter.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade-adapter.mjs","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-adapter.ts"],"sourcesContent":["import { type ChildModel, Model } from \"@warlock.js/cascade\";\nimport type {\n ChunkCallback,\n CursorPaginationOptions,\n CursorPaginationResult,\n PaginationResult,\n QueryBuilderContract,\n RepositoryAdapterContract,\n} from \"../../contracts\";\nimport { CascadeQueryBuilder } from \"./cascade-query-builder\";\n\n/**\n * Cascade adapter for Cascade-Next ORM\n * Implements RepositoryAdapterContract for @warlock.js/cascade\n *\n * @template T - The model instance type\n */\nexport class CascadeAdapter<T extends Model<any>> implements RepositoryAdapterContract<T> {\n /**\n * Constructor\n * @param model - Cascade-Next Model class\n */\n public constructor(private model: ChildModel<T>) {}\n\n // ============================================================================\n // QUERY BUILDING\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.query}\n */\n public query(): QueryBuilderContract<T> {\n return new CascadeQueryBuilder<T>(this.model.query());\n }\n\n /**\n * Register all events\n */\n public registerEvents(eventsCallback: any): any[] {\n const events: any[] = [];\n\n const modelEvents = this.model.events();\n\n events.
|
|
1
|
+
{"version":3,"file":"cascade-adapter.mjs","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-adapter.ts"],"sourcesContent":["import { afterCommit, type ChildModel, Model } from \"@warlock.js/cascade\";\nimport type {\n ChunkCallback,\n CursorPaginationOptions,\n CursorPaginationResult,\n PaginationResult,\n QueryBuilderContract,\n RepositoryAdapterContract,\n} from \"../../contracts\";\nimport { CascadeQueryBuilder } from \"./cascade-query-builder\";\n\n/** Records loaded and written per `updateMany` batch. */\nexport const UPDATE_MANY_BATCH_SIZE = 500;\n\n/**\n * Cascade adapter for Cascade-Next ORM\n * Implements RepositoryAdapterContract for @warlock.js/cascade\n *\n * @template T - The model instance type\n */\nexport class CascadeAdapter<T extends Model<any>> implements RepositoryAdapterContract<T> {\n /**\n * Constructor\n * @param model - Cascade-Next Model class\n */\n public constructor(private model: ChildModel<T>) {}\n\n // ============================================================================\n // QUERY BUILDING\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.query}\n */\n public query(): QueryBuilderContract<T> {\n return new CascadeQueryBuilder<T>(this.model.query());\n }\n\n /**\n * Register all events\n */\n public registerEvents(eventsCallback: any): any[] {\n const events: any[] = [];\n\n const modelEvents = this.model.events();\n\n // Model events fire INSIDE the transaction, before COMMIT. Clear now (existing\n // behaviour) and again after COMMIT, so a concurrent read that re-cached the\n // old committed row in between does not leave a stale entry behind.\n const handle = (model: any) => {\n eventsCallback(model);\n afterCommit(() => eventsCallback(model));\n };\n\n events.push(\n modelEvents.onCreated(handle),\n modelEvents.onUpdated(handle),\n modelEvents.onDeleted(handle),\n );\n\n return events;\n }\n\n // ============================================================================\n // CRUD OPERATIONS\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.find}\n */\n public async find(id: any): Promise<T | null> {\n return await this.model.find(id);\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.findBy}\n */\n public async findBy(column: string, value: any): Promise<T | null> {\n return (await this.query().where(column, value).first()) as T | null;\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.serializeModel}\n */\n public serializeModel(model: T): any {\n return model.toSnapshot();\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.deserializeModel}\n */\n public deserializeModel(data: any): T {\n return this.model.fromSnapshot(data);\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.resolveRepositoryName}\n */\n public resolveRepositoryName(): string {\n return this.model.table;\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.create}\n */\n public async create(data: any): Promise<T> {\n return this.model.create(data);\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.update}\n */\n public async update(id: any, data: any): Promise<T> {\n const model = id instanceof Model ? id : await this.model.find(id);\n if (!model) {\n throw new Error(`Model not found with id ${id}`);\n }\n\n await model.save({ merge: data });\n return model as T;\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.delete}\n */\n public async delete(id: any): Promise<void> {\n // Load + destroy so events, delete strategy and repository-cache clearing apply.\n const record = id instanceof Model ? id : await this.model.find(id);\n\n if (!record) return;\n\n await record.destroy();\n }\n\n // ============================================================================\n // BULK OPERATIONS\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.updateMany}\n */\n public async updateMany(filter: any, data: any): Promise<number> {\n const query = this.query();\n\n // Apply filter\n if (typeof filter === \"object\") {\n query.where(filter);\n }\n\n let updated = 0;\n\n // Process in batches instead of loading the whole result set; each batch\n // is written inside a transaction when the model's driver offers one.\n await query.chunk(UPDATE_MANY_BATCH_SIZE, async (records) => {\n const writeBatch = async () => {\n for (const record of records) {\n await record.save({ merge: data });\n }\n };\n\n const runInTransaction = (this.model as any).transaction;\n\n if (typeof runInTransaction === \"function\") {\n await runInTransaction.call(this.model, writeBatch);\n } else {\n await writeBatch();\n }\n\n updated += records.length;\n });\n\n return updated;\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.deleteMany}\n */\n public async deleteMany(filter: any): Promise<number> {\n const query = this.query();\n\n // Apply filter\n if (typeof filter === \"object\") {\n query.where(filter);\n }\n\n // Get matching records\n const records = await query.get();\n\n // Delete each record\n for (const record of records) {\n await record.destroy();\n }\n\n return records.length;\n }\n\n // ============================================================================\n // COUNTING\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.count}\n */\n public async count(filter?: any): Promise<number> {\n const query = this.query();\n\n if (filter && typeof filter === \"object\") {\n query.where(filter);\n }\n\n return query.count();\n }\n\n // ============================================================================\n // PAGINATION\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.paginate}\n */\n public async paginate(page: number, limit: number): Promise<PaginationResult<T>> {\n return this.query().paginate(page, limit);\n }\n\n /**\n * {@inheritDoc RepositoryAdapterContract.cursorPaginate}\n */\n public async cursorPaginate(\n options: CursorPaginationOptions,\n ): Promise<CursorPaginationResult<T>> {\n return this.query().cursorPaginate(options);\n }\n\n // ============================================================================\n // CHUNKING\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.chunk}\n */\n public async chunk(size: number, callback: ChunkCallback<T>): Promise<void> {\n return this.query().chunk(size, callback);\n }\n\n // ============================================================================\n // MODEL CREATION\n // ============================================================================\n\n /**\n * {@inheritDoc RepositoryAdapterContract.createModel}\n */\n public createModel(data: any): T {\n return new (this.model as any)(data) as T;\n }\n}\n"],"mappings":"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"}
|
|
@@ -118,15 +118,15 @@ declare class CascadeQueryBuilder<T extends Model> implements QueryBuilderContra
|
|
|
118
118
|
/**
|
|
119
119
|
* {@inheritDoc QueryBuilderContract.avg}
|
|
120
120
|
*/
|
|
121
|
-
avg(field: string): Promise<number>;
|
|
121
|
+
avg(field: string): Promise<number | null>;
|
|
122
122
|
/**
|
|
123
123
|
* {@inheritDoc QueryBuilderContract.min}
|
|
124
124
|
*/
|
|
125
|
-
min(field: string): Promise<number>;
|
|
125
|
+
min(field: string): Promise<number | null>;
|
|
126
126
|
/**
|
|
127
127
|
* {@inheritDoc QueryBuilderContract.max}
|
|
128
128
|
*/
|
|
129
|
-
max(field: string): Promise<number>;
|
|
129
|
+
max(field: string): Promise<number | null>;
|
|
130
130
|
/**
|
|
131
131
|
* {@inheritDoc QueryBuilderContract.groupBy}
|
|
132
132
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cascade-query-builder.mjs","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-query-builder.ts"],"sourcesContent":["import type {\n QueryBuilderContract as CascadeQueryBuilderContract,\n Model,\n} from \"@warlock.js/cascade\";\nimport type {\n AggregateExpressions,\n ChunkCallback,\n CursorPaginationOptions,\n CursorPaginationResult,\n FilterOptions,\n FilterRules,\n GroupByFields,\n PaginationResult,\n QueryBuilderContract,\n WhereOperator,\n} from \"../../contracts\";\nimport { FilterApplicator } from \"./filter-applicator\";\n\n/**\n * Cascade query builder wrapper\n * Wraps Cascade-Next's ModelAggregate to implement QueryBuilderContract\n *\n * @template T - The model instance type\n */\nexport class CascadeQueryBuilder<T extends Model> implements QueryBuilderContract<T> {\n /**\n * Constructor\n * @param query - Cascade-Next QueryBuilder instance\n */\n public constructor(private query: CascadeQueryBuilderContract<T>) {}\n\n // ============================================================================\n // WHERE CLAUSES\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.where}\n */\n public where(field: string, value: any): this;\n public where(field: string, operator: WhereOperator, value: any): this;\n public where(conditions: Record<string, any>): this;\n public where(callback: (query: this) => void): this;\n public where(\n fieldOrConditionsOrCallback: string | Record<string, any> | ((query: this) => void),\n operatorOrValue?: WhereOperator | any,\n value?: any,\n ): this {\n if (typeof fieldOrConditionsOrCallback === \"function\") {\n // Callback\n fieldOrConditionsOrCallback(this);\n } else if (typeof fieldOrConditionsOrCallback === \"object\") {\n // Object conditions\n this.query.where(fieldOrConditionsOrCallback);\n } else if (value !== undefined) {\n // Field, operator, value\n this.query.where(fieldOrConditionsOrCallback, operatorOrValue, value);\n } else {\n // Field, value\n this.query.where(fieldOrConditionsOrCallback, operatorOrValue);\n }\n\n return this;\n }\n\n /**\n * Pretty display the query in terminal\n */\n public pretty() {\n return this.query.pretty();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.orWhere}\n */\n public orWhere(field: string, value: any): this;\n public orWhere(field: string, operator: WhereOperator, value: any): this;\n public orWhere(conditions: Record<string, any>): this;\n public orWhere(\n fieldOrConditions: string | Record<string, any>,\n operatorOrValue?: WhereOperator | any,\n value?: any,\n ): this {\n if (typeof fieldOrConditions === \"object\") {\n this.query.orWhere(fieldOrConditions);\n } else if (value !== undefined) {\n this.query.orWhere(fieldOrConditions, operatorOrValue, value);\n } else {\n this.query.orWhere(fieldOrConditions, operatorOrValue);\n }\n\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereIn}\n */\n public whereIn(field: string, values: any[]): this {\n this.query.whereIn(field, values);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNotIn}\n */\n public whereNotIn(field: string, values: any[]): this {\n this.query.whereNotIn(field, values);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNull}\n */\n public whereNull(field: string): this {\n this.query.whereNull(field);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNotNull}\n */\n public whereNotNull(field: string): this {\n this.query.whereNotNull(field);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereBetween}\n */\n public whereBetween(field: string, range: [any, any]): this {\n this.query.whereBetween(field, range);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereLike}\n */\n public whereLike(field: string, pattern: string): this {\n this.query.whereLike(field, pattern);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.similarTo}\n */\n public similarTo(column: string, embedding: number[], alias?: string): this {\n this.query.similarTo(column, embedding, alias);\n return this;\n }\n\n // ============================================================================\n // SELECT / PROJECTION\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.select}\n */\n public select(fields: string[]): this;\n public select(...fields: string[]): this;\n public select(...fields: any[]): this {\n if (Array.isArray(fields[0])) {\n this.query.select(fields[0]);\n } else {\n this.query.select(fields);\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.deselect}\n */\n public deselect(fields: string[]): this;\n public deselect(...fields: string[]): this;\n public deselect(...fields: any[]): this {\n if (Array.isArray(fields[0])) {\n this.query.deselect(fields[0]);\n } else {\n this.query.deselect(fields);\n }\n return this;\n }\n\n // ============================================================================\n // ORDERING\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.orderBy}\n */\n public orderBy(field: string, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.query.orderBy(field, direction);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.sortBy}\n */\n public sortBy(orderBy: Record<string, \"asc\" | \"desc\">): this {\n // Apply each order clause individually\n for (const [field, direction] of Object.entries(orderBy)) {\n this.query.orderBy(field, direction);\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.random}\n */\n public random(limit: number): this {\n this.query.orderByRandom(limit);\n return this;\n }\n\n // ============================================================================\n // LIMITING\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.limit}\n */\n public limit(limit: number): this {\n this.query.limit(limit);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.offset}\n */\n public offset(offset: number): this {\n this.query.offset(offset);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.skip}\n */\n public skip(count: number): this {\n return this.offset(count);\n }\n\n // ============================================================================\n // FILTERING (Repository-specific)\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.applyFilters}\n */\n public applyFilters(filters: FilterRules<this>, data: any, options: FilterOptions): this {\n const applicator = new FilterApplicator();\n applicator.apply(this.query as any, filters, data, options);\n return this;\n }\n\n // ============================================================================\n // EXECUTION\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.get}\n */\n public async get(): Promise<T[]> {\n return this.query.get();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.first}\n */\n public async first(): Promise<T | null> {\n return this.query.first();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.count}\n */\n public async count(): Promise<number> {\n return this.query.count();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.sum}\n */\n public async sum(field: string): Promise<number> {\n return this.query.sum(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.avg}\n */\n public async avg(field: string): Promise<number> {\n return this.query.avg(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.min}\n */\n public async min(field: string): Promise<number> {\n return this.query.min(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.max}\n */\n public async max(field: string): Promise<number> {\n return this.query.max(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.groupBy}\n */\n public async groupBy<R = Record<string, unknown>>(\n fields: GroupByFields,\n aggregates: AggregateExpressions,\n ): Promise<R[]> {\n return this.query.groupBy(fields, aggregates).get<R>();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.aggregate}\n *\n * Whole-set aggregation: groups with no group key so every matching record\n * falls into a single group, then returns that one summary row.\n */\n public async aggregate<R = Record<string, unknown>>(\n aggregates: AggregateExpressions,\n ): Promise<R | null> {\n const rows = await this.query.groupBy([], aggregates).get<R>();\n return rows[0] ?? null;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.paginate}\n */\n public async paginate(page: number, limit: number): Promise<PaginationResult<T>> {\n const result = await this.query.paginate({ limit, page });\n\n // Convert Cascade-Next pagination to repository format\n return {\n data: result.data,\n pagination: {\n ...result.pagination,\n result: result.data.length,\n },\n };\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.cursorPaginate}\n *\n * NOTE: This method is a pure executor.\n * The caller (e.g. RepositoryManager._listImpl) is responsible for applying\n * the cursor WHERE condition and ORDER BY BEFORE calling this method,\n * so that the cursor column is always the primary sort key.\n *\n * For a forward page (`direction: \"next\"`) the caller sorts ASC and filters\n * `> cursor`, so the rows already arrive in ascending cursor order.\n *\n * For a backward page (`direction: \"prev\"`) the caller sorts DESC and filters\n * `< cursor`, so rows arrive in DESCENDING order. We re-reverse the trimmed\n * page back to ascending so callers always receive a page in the same\n * (ascending) order regardless of direction, and we derive the next/prev\n * cursors from the page boundaries accordingly.\n */\n public async cursorPaginate(\n options: CursorPaginationOptions,\n ): Promise<CursorPaginationResult<T>> {\n const { limit, cursorColumn = \"id\", direction = \"next\" } = options;\n\n // Fetch limit + 1 to detect whether more pages exist in the scan direction.\n this.limit(limit + 1);\n\n const results = await this.get();\n const hasMore = results.length > limit;\n\n // Drop the extra record used for the hasMore check. It always sits at the\n // tail because the caller ordered the scan so the next-to-fetch row is last.\n const trimmed = hasMore ? results.slice(0, limit) : results;\n\n const cursorOf = (record: T | undefined): string | number | undefined =>\n record === undefined ? undefined : ((record as any)[cursorColumn] as string | number);\n\n if (direction === \"prev\") {\n // Scan came back DESC; present it ascending.\n const documents = [...trimmed].reverse();\n const first = documents[0];\n const last = documents[documents.length - 1];\n\n return {\n data: documents,\n pagination: {\n limit,\n result: documents.length,\n hasMore,\n // Going further back is only possible when the backward scan saw more\n // rows than this page; the boundary is this page's first (smallest) row.\n prevCursor: hasMore ? cursorOf(first) : undefined,\n // Going forward always resumes after this page's last (largest) row.\n nextCursor: cursorOf(last),\n },\n };\n }\n\n // Forward page — rows already ascending.\n const documents = trimmed;\n const first = documents[0];\n const last = documents[documents.length - 1];\n\n return {\n data: documents,\n pagination: {\n limit,\n result: documents.length,\n hasMore,\n // Going forward is only possible when the forward scan saw more rows\n // than this page; the boundary is this page's last (largest) row.\n nextCursor: hasMore ? cursorOf(last) : undefined,\n // Going back resumes before this page's first (smallest) row.\n prevCursor: cursorOf(first),\n },\n };\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.chunk}\n */\n public async chunk(size: number, callback: ChunkCallback<T>): Promise<void> {\n return this.query.chunk(size, callback);\n }\n\n // ============================================================================\n // UTILITIES\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.with}\n */\n public with(relation: string): this {\n this.query.with(relation);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.joinWith}\n */\n public joinWith(...relations: string[]): this {\n if (this.query.joinWith) {\n this.query.joinWith(...relations);\n } else {\n console.warn(\n \"[Repository] joinWith is not supported by the underlying query builder. Falling back to with.\",\n );\n for (const relation of relations) {\n this.query.with(relation);\n }\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.clone}\n */\n public clone(): this {\n return new CascadeQueryBuilder(this.query.clone()) as this;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cascade-query-builder.mjs","names":[],"sources":["../../../../../../../../../core/src/repositories/adapters/cascade/cascade-query-builder.ts"],"sourcesContent":["import type {\n QueryBuilderContract as CascadeQueryBuilderContract,\n Model,\n} from \"@warlock.js/cascade\";\nimport type {\n AggregateExpressions,\n ChunkCallback,\n CursorPaginationOptions,\n CursorPaginationResult,\n FilterOptions,\n FilterRules,\n GroupByFields,\n PaginationResult,\n QueryBuilderContract,\n WhereOperator,\n} from \"../../contracts\";\nimport { FilterApplicator } from \"./filter-applicator\";\n\n/**\n * Cascade query builder wrapper\n * Wraps Cascade-Next's ModelAggregate to implement QueryBuilderContract\n *\n * @template T - The model instance type\n */\nexport class CascadeQueryBuilder<T extends Model> implements QueryBuilderContract<T> {\n /**\n * Constructor\n * @param query - Cascade-Next QueryBuilder instance\n */\n public constructor(private query: CascadeQueryBuilderContract<T>) {}\n\n // ============================================================================\n // WHERE CLAUSES\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.where}\n */\n public where(field: string, value: any): this;\n public where(field: string, operator: WhereOperator, value: any): this;\n public where(conditions: Record<string, any>): this;\n public where(callback: (query: this) => void): this;\n public where(\n fieldOrConditionsOrCallback: string | Record<string, any> | ((query: this) => void),\n operatorOrValue?: WhereOperator | any,\n value?: any,\n ): this {\n if (typeof fieldOrConditionsOrCallback === \"function\") {\n // Callback\n fieldOrConditionsOrCallback(this);\n } else if (typeof fieldOrConditionsOrCallback === \"object\") {\n // Object conditions\n this.query.where(fieldOrConditionsOrCallback);\n } else if (value !== undefined) {\n // Field, operator, value\n this.query.where(fieldOrConditionsOrCallback, operatorOrValue, value);\n } else {\n // Field, value\n this.query.where(fieldOrConditionsOrCallback, operatorOrValue);\n }\n\n return this;\n }\n\n /**\n * Pretty display the query in terminal\n */\n public pretty() {\n return this.query.pretty();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.orWhere}\n */\n public orWhere(field: string, value: any): this;\n public orWhere(field: string, operator: WhereOperator, value: any): this;\n public orWhere(conditions: Record<string, any>): this;\n public orWhere(\n fieldOrConditions: string | Record<string, any>,\n operatorOrValue?: WhereOperator | any,\n value?: any,\n ): this {\n if (typeof fieldOrConditions === \"object\") {\n this.query.orWhere(fieldOrConditions);\n } else if (value !== undefined) {\n this.query.orWhere(fieldOrConditions, operatorOrValue, value);\n } else {\n this.query.orWhere(fieldOrConditions, operatorOrValue);\n }\n\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereIn}\n */\n public whereIn(field: string, values: any[]): this {\n this.query.whereIn(field, values);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNotIn}\n */\n public whereNotIn(field: string, values: any[]): this {\n this.query.whereNotIn(field, values);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNull}\n */\n public whereNull(field: string): this {\n this.query.whereNull(field);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereNotNull}\n */\n public whereNotNull(field: string): this {\n this.query.whereNotNull(field);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereBetween}\n */\n public whereBetween(field: string, range: [any, any]): this {\n this.query.whereBetween(field, range);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.whereLike}\n */\n public whereLike(field: string, pattern: string): this {\n this.query.whereLike(field, pattern);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.similarTo}\n */\n public similarTo(column: string, embedding: number[], alias?: string): this {\n this.query.similarTo(column, embedding, alias);\n return this;\n }\n\n // ============================================================================\n // SELECT / PROJECTION\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.select}\n */\n public select(fields: string[]): this;\n public select(...fields: string[]): this;\n public select(...fields: any[]): this {\n if (Array.isArray(fields[0])) {\n this.query.select(fields[0]);\n } else {\n this.query.select(fields);\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.deselect}\n */\n public deselect(fields: string[]): this;\n public deselect(...fields: string[]): this;\n public deselect(...fields: any[]): this {\n if (Array.isArray(fields[0])) {\n this.query.deselect(fields[0]);\n } else {\n this.query.deselect(fields);\n }\n return this;\n }\n\n // ============================================================================\n // ORDERING\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.orderBy}\n */\n public orderBy(field: string, direction: \"asc\" | \"desc\" = \"asc\"): this {\n this.query.orderBy(field, direction);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.sortBy}\n */\n public sortBy(orderBy: Record<string, \"asc\" | \"desc\">): this {\n // Apply each order clause individually\n for (const [field, direction] of Object.entries(orderBy)) {\n this.query.orderBy(field, direction);\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.random}\n */\n public random(limit: number): this {\n this.query.orderByRandom(limit);\n return this;\n }\n\n // ============================================================================\n // LIMITING\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.limit}\n */\n public limit(limit: number): this {\n this.query.limit(limit);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.offset}\n */\n public offset(offset: number): this {\n this.query.offset(offset);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.skip}\n */\n public skip(count: number): this {\n return this.offset(count);\n }\n\n // ============================================================================\n // FILTERING (Repository-specific)\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.applyFilters}\n */\n public applyFilters(filters: FilterRules<this>, data: any, options: FilterOptions): this {\n const applicator = new FilterApplicator();\n applicator.apply(this.query as any, filters, data, options);\n return this;\n }\n\n // ============================================================================\n // EXECUTION\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.get}\n */\n public async get(): Promise<T[]> {\n return this.query.get();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.first}\n */\n public async first(): Promise<T | null> {\n return this.query.first();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.count}\n */\n public async count(): Promise<number> {\n return this.query.count();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.sum}\n */\n public async sum(field: string): Promise<number> {\n return this.query.sum(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.avg}\n */\n public async avg(field: string): Promise<number | null> {\n return this.query.avg(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.min}\n */\n public async min(field: string): Promise<number | null> {\n return this.query.min(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.max}\n */\n public async max(field: string): Promise<number | null> {\n return this.query.max(field);\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.groupBy}\n */\n public async groupBy<R = Record<string, unknown>>(\n fields: GroupByFields,\n aggregates: AggregateExpressions,\n ): Promise<R[]> {\n return this.query.groupBy(fields, aggregates).get<R>();\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.aggregate}\n *\n * Whole-set aggregation: groups with no group key so every matching record\n * falls into a single group, then returns that one summary row.\n */\n public async aggregate<R = Record<string, unknown>>(\n aggregates: AggregateExpressions,\n ): Promise<R | null> {\n const rows = await this.query.groupBy([], aggregates).get<R>();\n return rows[0] ?? null;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.paginate}\n */\n public async paginate(page: number, limit: number): Promise<PaginationResult<T>> {\n const result = await this.query.paginate({ limit, page });\n\n // Convert Cascade-Next pagination to repository format\n return {\n data: result.data,\n pagination: {\n ...result.pagination,\n result: result.data.length,\n },\n };\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.cursorPaginate}\n *\n * NOTE: This method is a pure executor.\n * The caller (e.g. RepositoryManager._listImpl) is responsible for applying\n * the cursor WHERE condition and ORDER BY BEFORE calling this method,\n * so that the cursor column is always the primary sort key.\n *\n * For a forward page (`direction: \"next\"`) the caller sorts ASC and filters\n * `> cursor`, so the rows already arrive in ascending cursor order.\n *\n * For a backward page (`direction: \"prev\"`) the caller sorts DESC and filters\n * `< cursor`, so rows arrive in DESCENDING order. We re-reverse the trimmed\n * page back to ascending so callers always receive a page in the same\n * (ascending) order regardless of direction, and we derive the next/prev\n * cursors from the page boundaries accordingly.\n */\n public async cursorPaginate(\n options: CursorPaginationOptions,\n ): Promise<CursorPaginationResult<T>> {\n const { limit, cursorColumn = \"id\", direction = \"next\" } = options;\n\n // Fetch limit + 1 to detect whether more pages exist in the scan direction.\n this.limit(limit + 1);\n\n const results = await this.get();\n const hasMore = results.length > limit;\n\n // Drop the extra record used for the hasMore check. It always sits at the\n // tail because the caller ordered the scan so the next-to-fetch row is last.\n const trimmed = hasMore ? results.slice(0, limit) : results;\n\n const cursorOf = (record: T | undefined): string | number | undefined =>\n record === undefined ? undefined : ((record as any)[cursorColumn] as string | number);\n\n if (direction === \"prev\") {\n // Scan came back DESC; present it ascending.\n const documents = [...trimmed].reverse();\n const first = documents[0];\n const last = documents[documents.length - 1];\n\n return {\n data: documents,\n pagination: {\n limit,\n result: documents.length,\n hasMore,\n // Going further back is only possible when the backward scan saw more\n // rows than this page; the boundary is this page's first (smallest) row.\n prevCursor: hasMore ? cursorOf(first) : undefined,\n // Going forward always resumes after this page's last (largest) row.\n nextCursor: cursorOf(last),\n },\n };\n }\n\n // Forward page — rows already ascending.\n const documents = trimmed;\n const first = documents[0];\n const last = documents[documents.length - 1];\n\n return {\n data: documents,\n pagination: {\n limit,\n result: documents.length,\n hasMore,\n // Going forward is only possible when the forward scan saw more rows\n // than this page; the boundary is this page's last (largest) row.\n nextCursor: hasMore ? cursorOf(last) : undefined,\n // Going back resumes before this page's first (smallest) row.\n prevCursor: cursorOf(first),\n },\n };\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.chunk}\n */\n public async chunk(size: number, callback: ChunkCallback<T>): Promise<void> {\n return this.query.chunk(size, callback);\n }\n\n // ============================================================================\n // UTILITIES\n // ============================================================================\n\n /**\n * {@inheritDoc QueryBuilderContract.with}\n */\n public with(relation: string): this {\n this.query.with(relation);\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.joinWith}\n */\n public joinWith(...relations: string[]): this {\n if (this.query.joinWith) {\n this.query.joinWith(...relations);\n } else {\n console.warn(\n \"[Repository] joinWith is not supported by the underlying query builder. Falling back to with.\",\n );\n for (const relation of relations) {\n this.query.with(relation);\n }\n }\n return this;\n }\n\n /**\n * {@inheritDoc QueryBuilderContract.clone}\n */\n public clone(): this {\n return new CascadeQueryBuilder(this.query.clone()) as this;\n }\n}\n"],"mappings":"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"}
|