sonamu 0.10.12 → 0.10.13
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/dist/ai/agents/agent.d.ts +1 -1
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +5 -6
- package/dist/ai/agents/types.d.ts +1 -1
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/api.js +18 -18
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/error.js +17 -15
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.js +3 -2
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/options.js +16 -16
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/provider.js +9 -9
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.js +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +17 -17
- package/dist/api/code-converters.d.ts +4 -2
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +100 -19
- package/dist/api/config.d.ts +16 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +28 -21
- package/dist/api/context.d.ts +2 -2
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +18 -11
- package/dist/api/http-validator.d.ts +36 -0
- package/dist/api/http-validator.d.ts.map +1 -0
- package/dist/api/http-validator.js +72 -0
- package/dist/api/index.js +6 -4
- package/dist/api/sonamu.d.ts +59 -20
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +250 -106
- package/dist/api/websocket-helpers.d.ts +7 -5
- package/dist/api/websocket-helpers.d.ts.map +1 -1
- package/dist/api/websocket-helpers.js +6 -6
- package/dist/auth/audit-log/builders.d.ts.map +1 -1
- package/dist/auth/audit-log/builders.js +1 -1
- package/dist/auth/audit-log/client-ip.d.ts +1 -1
- package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
- package/dist/auth/audit-log/client-ip.js +4 -2
- package/dist/auth/audit-log/events.d.ts +5 -1
- package/dist/auth/audit-log/events.d.ts.map +1 -1
- package/dist/auth/audit-log/events.js +1 -1
- package/dist/auth/audit-log/plugin.d.ts +0 -8
- package/dist/auth/audit-log/plugin.d.ts.map +1 -1
- package/dist/auth/audit-log/plugin.js +48 -52
- package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
- package/dist/auth/audit-log-ingestor.js +16 -12
- package/dist/auth/auth-generator.d.ts.map +1 -1
- package/dist/auth/auth-generator.js +1 -1
- package/dist/auth/better-auth-request.d.ts.map +1 -1
- package/dist/auth/better-auth-request.js +6 -5
- package/dist/auth/knex-adapter.js +1 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +1 -1
- package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
- package/dist/bin/build-config.d.ts +25 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +105 -2
- package/dist/bin/cli.js +131 -27
- package/dist/bin/compiler-policy.d.ts +3 -0
- package/dist/bin/compiler-policy.d.ts.map +1 -0
- package/dist/bin/compiler-policy.js +24 -0
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +5 -3
- package/dist/bin/test-command.d.ts +22 -1
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +18 -10
- package/dist/bin/ts-loader-registration.d.ts +7 -1
- package/dist/bin/ts-loader-registration.d.ts.map +1 -1
- package/dist/bin/ts-loader-registration.js +13 -4
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +11 -4
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/compress/compress.js +1 -1
- package/dist/cone/cone-generator.d.ts +14 -1
- package/dist/cone/cone-generator.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +13 -9
- package/dist/database/_batch_update.js +1 -1
- package/dist/database/base-model.d.ts +22 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +26 -16
- package/dist/database/base-model.types.d.ts +15 -3
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/db.d.ts +12 -2
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +10 -7
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +17 -14
- package/dist/database/puri.d.ts +11 -9
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +93 -79
- package/dist/database/puri.types.d.ts +21 -21
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +1 -1
- package/dist/database/upsert-builder.d.ts +12 -10
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +20 -12
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +1 -1
- package/dist/dict/utils.d.ts.map +1 -1
- package/dist/dict/utils.js +7 -2
- package/dist/entity/entity-manager.d.ts +13 -4
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +19 -11
- package/dist/entity/entity-template-cone.d.ts +73 -5
- package/dist/entity/entity-template-cone.d.ts.map +1 -1
- package/dist/entity/entity-template-cone.js +4 -2
- package/dist/entity/entity.d.ts +6 -2
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +30 -28
- package/dist/env.d.ts +3 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +7 -2
- package/dist/exceptions/so-exceptions.d.ts +24 -20
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +4 -2
- package/dist/filter/utils.d.ts +7 -2
- package/dist/filter/utils.d.ts.map +1 -1
- package/dist/filter/utils.js +8 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +10 -10
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +50 -46
- package/dist/migration/index-where-predicate.d.ts.map +1 -1
- package/dist/migration/index-where-predicate.js +22 -8
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +1 -1
- package/dist/migration/migrator.d.ts +3 -2
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +27 -21
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/postgresql-schema-reader.js +51 -36
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/migration/slack-confirm.js +1 -1
- package/dist/naite/naite-reporter.js +2 -2
- package/dist/naite/naite.d.ts +74 -15
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +5 -19
- package/dist/runtime-type.d.ts +6 -0
- package/dist/runtime-type.d.ts.map +1 -0
- package/dist/runtime-type.js +26 -0
- package/dist/ssr/hmr-opt-out.d.ts +26 -0
- package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
- package/dist/ssr/hmr-opt-out.js +59 -0
- package/dist/ssr/renderer.d.ts.map +1 -1
- package/dist/ssr/renderer.js +4 -1
- package/dist/storage/base-file.js +14 -14
- package/dist/storage/buffered-file.d.ts +2 -2
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.js +12 -12
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/s3-driver.js +1 -1
- package/dist/storage/uploaded-file.d.ts +2 -2
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/storage/uploaded-file.js +8 -8
- package/dist/stream/sse.js +11 -11
- package/dist/stream/ws-core.d.ts +1 -1
- package/dist/stream/ws-core.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts +1 -1
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-delivery.js +6 -4
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.js +4 -2
- package/dist/stream/ws-presence-store.js +1 -1
- package/dist/stream/ws-registry.d.ts +4 -4
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-registry.js +4 -2
- package/dist/stream/ws-telemetry.d.ts +16 -12
- package/dist/stream/ws-telemetry.d.ts.map +1 -1
- package/dist/stream/ws-telemetry.js +22 -18
- package/dist/stream/ws.d.ts +18 -12
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/stream/ws.js +26 -22
- package/dist/syncer/api-parser.js +1 -1
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +7 -8
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +13 -14
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +5 -6
- package/dist/syncer/file-copy.d.ts +5 -0
- package/dist/syncer/file-copy.d.ts.map +1 -0
- package/dist/syncer/file-copy.js +36 -0
- package/dist/syncer/file-patterns.d.ts +1 -0
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +5 -2
- package/dist/syncer/file-tracking.d.ts.map +1 -1
- package/dist/syncer/file-tracking.js +5 -4
- package/dist/syncer/filesystem-dependencies.d.ts +15 -0
- package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
- package/dist/syncer/filesystem-dependencies.js +53 -0
- package/dist/syncer/module-loader.d.ts +1 -1
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +6 -4
- package/dist/syncer/syncer-actions.d.ts +4 -0
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +34 -17
- package/dist/syncer/syncer.d.ts +17 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +71 -29
- package/dist/syncer/watcher.d.ts.map +1 -1
- package/dist/syncer/watcher.js +3 -3
- package/dist/tasks/decorator.d.ts +6 -6
- package/dist/tasks/decorator.d.ts.map +1 -1
- package/dist/tasks/decorator.js +4 -4
- package/dist/tasks/step-wrapper.d.ts +6 -4
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.js +5 -5
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +13 -7
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +2 -2
- package/dist/template/helpers.d.ts +8 -6
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +1 -1
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +4 -4
- package/dist/template/implementations/generated_http.template.d.ts +7 -4
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +21 -21
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +6 -3
- package/dist/template/implementations/http_validators.template.d.ts +18 -0
- package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
- package/dist/template/implementations/http_validators.template.js +127 -0
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +1 -1
- package/dist/template/implementations/queries.template.js +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +79 -39
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +6 -4
- package/dist/template/implementations/view_form.template.d.ts +6 -1
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +23 -15
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +11 -6
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template-manager.js +9 -7
- package/dist/template/template-types.d.ts +12 -5
- package/dist/template/template-types.d.ts.map +1 -1
- package/dist/template/template-types.js +1 -1
- package/dist/template/template.d.ts +2 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +6 -4
- package/dist/template/zod-converter.d.ts +0 -19
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +100 -84
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +2 -1
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +9 -6
- package/dist/testing/data-explorer.d.ts +32 -7
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +77 -31
- package/dist/testing/dev-test-routes.d.ts +8 -1
- package/dist/testing/dev-test-routes.d.ts.map +1 -1
- package/dist/testing/dev-test-routes.js +125 -108
- package/dist/testing/dev-vitest-manager.d.ts +54 -8
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.js +24 -9
- package/dist/testing/faker-mappings.d.ts +412 -1
- package/dist/testing/faker-mappings.d.ts.map +1 -1
- package/dist/testing/faker-mappings.js +1 -1
- package/dist/testing/filesystem.d.ts +2 -0
- package/dist/testing/filesystem.d.ts.map +1 -0
- package/dist/testing/filesystem.js +7 -0
- package/dist/testing/fixture-generator.d.ts +25 -8
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +132 -73
- package/dist/testing/fixture-loader.d.ts +3 -1
- package/dist/testing/fixture-loader.d.ts.map +1 -1
- package/dist/testing/fixture-loader.js +1 -20
- package/dist/testing/fixture-manager.d.ts +8 -7
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +91 -59
- package/dist/testing/global-setup.d.ts.map +1 -1
- package/dist/testing/global-setup.js +5 -2
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +6 -3
- package/dist/types/types.d.ts +101 -99
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +234 -225
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +1 -1
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +28 -18
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +135 -128
- package/dist/ui/async-route.d.ts +3 -0
- package/dist/ui/async-route.d.ts.map +1 -0
- package/dist/ui/async-route.js +12 -0
- package/dist/ui/cdd-service.d.ts +9 -7
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +7 -5
- package/dist/ui/migrations-api.d.ts.map +1 -1
- package/dist/ui/migrations-api.js +17 -15
- package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
- package/dist/ui-web/index.html +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +7 -5
- package/dist/utils/fs-utils.d.ts +3 -3
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +6 -6
- package/dist/utils/model.d.ts +3 -5
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +1 -1
- package/dist/utils/object-utils.d.ts +1 -1
- package/dist/utils/object-utils.d.ts.map +1 -1
- package/dist/utils/object-utils.js +17 -16
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +4 -2
- package/dist/utils/runtime-value.d.ts +13 -0
- package/dist/utils/runtime-value.d.ts.map +1 -0
- package/dist/utils/runtime-value.js +40 -0
- package/dist/utils/sql-parser.d.ts +8 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +6 -3
- package/dist/utils/type-utils.d.ts.map +1 -1
- package/dist/utils/type-utils.js +10 -8
- package/dist/utils/utils.d.ts +2 -2
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +11 -8
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +7 -4
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/chunking.js +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +1 -1
- package/dist/vector/types.d.ts +3 -2
- package/dist/vector/types.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/ai/agents/agent.ts +5 -5
- package/src/ai/agents/types.ts +1 -1
- package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
- package/src/ai/providers/rtzr/error.ts +5 -3
- package/src/ai/providers/rtzr/model.ts +3 -2
- package/src/ai/providers/rtzr/options.ts +10 -5
- package/src/ai/providers/rtzr/provider.ts +10 -10
- package/src/ai/providers/rtzr/utils.ts +3 -1
- package/src/api/__tests__/config.test.ts +11 -21
- package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
- package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
- package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
- package/src/api/caster.ts +6 -8
- package/src/api/code-converters.ts +136 -36
- package/src/api/config.ts +62 -4
- package/src/api/context.ts +3 -3
- package/src/api/decorators.ts +28 -17
- package/src/api/http-validator.ts +149 -0
- package/src/api/sonamu.ts +459 -152
- package/src/api/websocket-helpers.ts +24 -17
- package/src/auth/audit-log/builders.ts +3 -2
- package/src/auth/audit-log/client-ip.ts +4 -2
- package/src/auth/audit-log/events.ts +15 -1
- package/src/auth/audit-log/plugin.ts +129 -200
- package/src/auth/audit-log-ingestor.ts +19 -15
- package/src/auth/auth-generator.ts +10 -5
- package/src/auth/better-auth-request.ts +4 -3
- package/src/auth/knex-adapter.ts +8 -2
- package/src/auth/plugins/entity-definitions/index.ts +6 -5
- package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
- package/src/bin/__tests__/test-command.test.ts +9 -15
- package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
- package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
- package/src/bin/build-config.ts +167 -0
- package/src/bin/cli.ts +153 -36
- package/src/bin/compiler-policy.ts +35 -0
- package/src/bin/fixture.ts +14 -3
- package/src/bin/test-command.ts +74 -29
- package/src/bin/ts-loader-registration.ts +22 -4
- package/src/cache/decorator.ts +10 -3
- package/src/compress/compress.ts +17 -4
- package/src/cone/cone-generator.ts +34 -6
- package/src/database/__tests__/db.test.ts +1 -0
- package/src/database/__tests__/puri.test.ts +16 -15
- package/src/database/__tests__/transaction-scope.test.ts +5 -0
- package/src/database/_batch_update.ts +1 -0
- package/src/database/base-model.ts +81 -50
- package/src/database/base-model.types.ts +6 -6
- package/src/database/db.ts +29 -19
- package/src/database/knex.ts +30 -17
- package/src/database/puri-subset.test-d.ts +17 -0
- package/src/database/puri.ts +181 -143
- package/src/database/puri.types.test-d.ts +31 -1
- package/src/database/puri.types.ts +23 -21
- package/src/database/upsert-builder.ts +75 -53
- package/src/dict/sd.ts +15 -5
- package/src/dict/sonamu-dictionary.ts +6 -6
- package/src/dict/utils.ts +9 -1
- package/src/entity/entity-manager.ts +26 -9
- package/src/entity/entity-template-cone.ts +5 -10
- package/src/entity/entity.ts +50 -34
- package/src/env.ts +7 -3
- package/src/exceptions/error-handler.ts +17 -2
- package/src/exceptions/so-exceptions.ts +26 -20
- package/src/filter/utils.ts +21 -11
- package/src/index.ts +3 -0
- package/src/logger/configure.ts +26 -18
- package/src/migration/__tests__/migrator.test.ts +50 -57
- package/src/migration/code-generation.ts +132 -104
- package/src/migration/index-where-predicate.ts +51 -24
- package/src/migration/migration-set.ts +11 -5
- package/src/migration/migrator.ts +68 -41
- package/src/migration/postgresql-schema-reader.ts +52 -47
- package/src/migration/slack-confirm.ts +17 -15
- package/src/naite/naite-reporter.ts +1 -1
- package/src/naite/naite.ts +97 -24
- package/src/runtime-type.ts +34 -0
- package/src/ssr/hmr-opt-out.ts +78 -0
- package/src/ssr/renderer.ts +6 -0
- package/src/storage/base-file.ts +13 -13
- package/src/storage/buffered-file.ts +11 -11
- package/src/storage/s3-driver.ts +4 -1
- package/src/storage/uploaded-file.ts +8 -8
- package/src/stream/__tests__/ws-contracts.test.ts +4 -2
- package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
- package/src/stream/__tests__/ws.test.ts +30 -6
- package/src/stream/sse.ts +12 -11
- package/src/stream/ws-core.ts +1 -1
- package/src/stream/ws-delivery.ts +16 -7
- package/src/stream/ws-local-connection-store.ts +2 -3
- package/src/stream/ws-presence-store.ts +6 -1
- package/src/stream/ws-registry.ts +16 -7
- package/src/stream/ws-telemetry.ts +66 -43
- package/src/stream/ws.ts +73 -39
- package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
- package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
- package/src/syncer/api-parser.ts +67 -27
- package/src/syncer/checksum.ts +17 -11
- package/src/syncer/code-generator.ts +25 -17
- package/src/syncer/entity-operations.ts +3 -5
- package/src/syncer/file-copy.ts +46 -0
- package/src/syncer/file-patterns.ts +11 -8
- package/src/syncer/file-tracking.ts +3 -4
- package/src/syncer/filesystem-dependencies.ts +73 -0
- package/src/syncer/module-loader.ts +8 -4
- package/src/syncer/syncer-actions.ts +56 -18
- package/src/syncer/syncer.ts +116 -43
- package/src/syncer/watcher.ts +8 -4
- package/src/tasks/decorator.ts +20 -12
- package/src/tasks/step-wrapper.ts +19 -9
- package/src/tasks/workflow-manager.ts +15 -9
- package/src/template/__tests__/http_validators.template.test.ts +160 -0
- package/src/template/__tests__/services.template.mutation.test.ts +24 -23
- package/src/template/__tests__/services.template.websocket.test.ts +21 -25
- package/src/template/entity-converter.ts +5 -2
- package/src/template/helpers.ts +8 -9
- package/src/template/implementations/generated.template.ts +5 -4
- package/src/template/implementations/generated_http.template.ts +61 -15
- package/src/template/implementations/generated_sso.template.ts +15 -4
- package/src/template/implementations/http_validators.template.ts +175 -0
- package/src/template/implementations/model.template.ts +3 -1
- package/src/template/implementations/sd.template.ts +81 -41
- package/src/template/implementations/services.template.ts +2 -2
- package/src/template/implementations/view_form.template.ts +56 -39
- package/src/template/implementations/view_list.template.ts +31 -23
- package/src/template/template-manager.ts +15 -13
- package/src/template/template-types.ts +13 -5
- package/src/template/template.ts +4 -3
- package/src/template/zod-converter.ts +206 -91
- package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
- package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
- package/src/testing/_relation-graph.ts +4 -1
- package/src/testing/bootstrap.ts +12 -5
- package/src/testing/data-explorer.ts +102 -53
- package/src/testing/dev-test-routes.ts +87 -50
- package/src/testing/dev-vitest-manager.ts +88 -32
- package/src/testing/faker-mappings.ts +2 -2
- package/src/testing/filesystem.ts +1 -0
- package/src/testing/fixture-generator.ts +191 -131
- package/src/testing/fixture-loader.ts +5 -1
- package/src/testing/fixture-manager.ts +129 -90
- package/src/testing/global-setup.ts +7 -3
- package/src/testing/index.ts +5 -0
- package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
- package/src/types/types.ts +184 -158
- package/src/ui/ai-api.ts +9 -7
- package/src/ui/ai-client.ts +61 -56
- package/src/ui/api.ts +727 -616
- package/src/ui/async-route.ts +4 -0
- package/src/ui/cdd-service.ts +35 -12
- package/src/ui/migrations-api.ts +63 -51
- package/src/utils/formatter.ts +7 -3
- package/src/utils/fs-utils.ts +5 -5
- package/src/utils/model.ts +4 -5
- package/src/utils/object-utils.ts +32 -22
- package/src/utils/process-utils.ts +4 -1
- package/src/utils/runtime-value.ts +43 -0
- package/src/utils/sql-parser.ts +13 -6
- package/src/utils/type-utils.ts +9 -7
- package/src/utils/utils.ts +19 -21
- package/src/utils/zod-error.ts +4 -2
- package/src/vector/chunking.ts +6 -1
- package/src/vector/embedding.ts +2 -1
- package/src/vector/types.ts +4 -2
- package/tsdown.api.config.ts +5 -2
- package/dist/ui-web/assets/index-C0m1pk6K.js +0 -177
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { type ManagedVitest } from "../dev-vitest-manager";
|
|
4
|
+
import { DevVitestManager } from "../dev-vitest-manager";
|
|
5
|
+
|
|
6
|
+
// 매니저가 사용하는 Vitest 기능만 충실히 구현한 테스트 대역입니다.
|
|
4
7
|
const mockVitest = {
|
|
5
8
|
standalone: vi.fn().mockResolvedValue(undefined),
|
|
6
9
|
onFilterWatchedSpecification: vi.fn(),
|
|
10
|
+
invalidateFile: vi.fn(),
|
|
7
11
|
setGlobalTestNamePattern: vi.fn(),
|
|
8
12
|
resetGlobalTestNamePattern: vi.fn(),
|
|
9
13
|
globTestSpecifications: vi.fn(),
|
|
10
14
|
runTestSpecifications: vi.fn(),
|
|
11
15
|
close: vi.fn(),
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
vi.mock("vitest/node", () => ({
|
|
15
|
-
createVitest: vi.fn().mockResolvedValue(mockVitest),
|
|
16
|
-
}));
|
|
16
|
+
} satisfies ManagedVitest;
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
function createModule(duration: number) {
|
|
19
|
+
return {
|
|
20
|
+
moduleId: "dup.test.ts",
|
|
21
|
+
children: [],
|
|
22
|
+
state: () => "passed" as const,
|
|
23
|
+
diagnostic: () => ({ duration }),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
19
26
|
|
|
20
27
|
describe("DevVitestManager", () => {
|
|
21
28
|
let manager: DevVitestManager;
|
|
22
29
|
|
|
23
30
|
beforeEach(() => {
|
|
24
31
|
vi.clearAllMocks();
|
|
25
|
-
manager = new DevVitestManager();
|
|
32
|
+
manager = new DevVitestManager(async () => mockVitest);
|
|
26
33
|
|
|
27
34
|
// 기본 mock: 빈 테스트 결과
|
|
28
35
|
const mockTestModule = {
|
|
@@ -114,13 +121,6 @@ describe("DevVitestManager", () => {
|
|
|
114
121
|
await manager.start();
|
|
115
122
|
mockVitest.globTestSpecifications.mockResolvedValue([{ moduleId: "dup.test.ts" }]);
|
|
116
123
|
|
|
117
|
-
const createModule = (duration: number) => ({
|
|
118
|
-
moduleId: "dup.test.ts",
|
|
119
|
-
children: [],
|
|
120
|
-
state: () => "passed" as const,
|
|
121
|
-
diagnostic: () => ({ duration }),
|
|
122
|
-
});
|
|
123
|
-
|
|
124
124
|
mockVitest.runTestSpecifications.mockResolvedValue({
|
|
125
125
|
testModules: [createModule(10), createModule(25)],
|
|
126
126
|
});
|
|
@@ -44,7 +44,10 @@ export class RelationGraph {
|
|
|
44
44
|
}
|
|
45
45
|
} else if (isManyToManyRelationProp(prop)) {
|
|
46
46
|
// ManyToMany 관계의 경우 양방향 의존성 추가
|
|
47
|
-
|
|
47
|
+
if (!Array.isArray(column.value)) {
|
|
48
|
+
throw new Error(`${fixture.fixtureId}.${prop.name} 관계 값은 배열이어야 합니다.`);
|
|
49
|
+
}
|
|
50
|
+
const relatedIds = column.value;
|
|
48
51
|
for (const relatedId of relatedIds) {
|
|
49
52
|
const relatedFixtureId = `${prop.with}#${relatedId}`;
|
|
50
53
|
if (this.graph.has(relatedFixtureId)) {
|
package/src/testing/bootstrap.ts
CHANGED
|
@@ -57,14 +57,21 @@ export function bootstrap(vi: VitestUtils, options?: BootstrapOptions) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
function getMockContext(): Context {
|
|
60
|
+
// SAFETY: 테스트 컨텍스트에서는 Fastify 요청과 응답을 사용하지 않으며 접근 시 즉시 실패해야 합니다.
|
|
61
|
+
const request: Context["request"] = null as never;
|
|
62
|
+
// SAFETY: 테스트 컨텍스트에서는 Fastify 요청과 응답을 사용하지 않으며 접근 시 즉시 실패해야 합니다.
|
|
63
|
+
const reply: Context["reply"] = null as never;
|
|
64
|
+
// SAFETY: 모의 구현은 실제 createSSE와 같은 호출 계약을 유지하되 항상 명시적으로 실패합니다.
|
|
65
|
+
const createSSE = (() => {
|
|
66
|
+
throw new Error("createSSE is not available in mock context");
|
|
67
|
+
}) as Context["createSSE"];
|
|
68
|
+
|
|
60
69
|
return {
|
|
61
70
|
transport: "http",
|
|
62
|
-
request
|
|
63
|
-
reply
|
|
71
|
+
request,
|
|
72
|
+
reply,
|
|
64
73
|
headers: {},
|
|
65
|
-
createSSE
|
|
66
|
-
throw new Error("createSSE is not available in mock context");
|
|
67
|
-
}) as Context["createSSE"],
|
|
74
|
+
createSSE,
|
|
68
75
|
session: null,
|
|
69
76
|
user: null,
|
|
70
77
|
naiteStore: Naite.createStore(),
|
|
@@ -1,22 +1,67 @@
|
|
|
1
1
|
import { type Knex } from "knex";
|
|
2
|
+
import { z } from "zod";
|
|
2
3
|
|
|
3
4
|
import { type CacheManager } from "../cache/types";
|
|
4
5
|
import { type Entity } from "../entity/entity";
|
|
5
6
|
import { type EntityManager } from "../entity/entity-manager";
|
|
6
7
|
import { isBelongsToOneRelationProp, isOneToOneRelationProp, isRelationProp } from "../types/types";
|
|
7
|
-
import {
|
|
8
|
+
import { isFunctionValue } from "../utils/runtime-value";
|
|
8
9
|
|
|
9
10
|
export type DataExplorerStrategy = "sample" | "ids" | "query" | "file" | "recent" | "random";
|
|
10
11
|
|
|
12
|
+
export type DataExplorerValue =
|
|
13
|
+
| string
|
|
14
|
+
| number
|
|
15
|
+
| boolean
|
|
16
|
+
| bigint
|
|
17
|
+
| Date
|
|
18
|
+
| Uint8Array
|
|
19
|
+
| null
|
|
20
|
+
| undefined
|
|
21
|
+
| DataExplorerValue[]
|
|
22
|
+
| DataExplorerRecord;
|
|
23
|
+
|
|
24
|
+
export type DataExplorerRecord = {
|
|
25
|
+
[columnName: string]: DataExplorerValue;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const dataExplorerValueSchema: z.ZodType<DataExplorerValue> = z.lazy(() =>
|
|
29
|
+
z.union([
|
|
30
|
+
z.string(),
|
|
31
|
+
z.number(),
|
|
32
|
+
z.boolean(),
|
|
33
|
+
z.bigint(),
|
|
34
|
+
z.date(),
|
|
35
|
+
z.instanceof(Uint8Array),
|
|
36
|
+
z.null(),
|
|
37
|
+
z.undefined(),
|
|
38
|
+
z.array(dataExplorerValueSchema),
|
|
39
|
+
z.record(z.string(), dataExplorerValueSchema),
|
|
40
|
+
]),
|
|
41
|
+
);
|
|
42
|
+
export const dataExplorerRecordSchema = z.record(z.string(), dataExplorerValueSchema);
|
|
43
|
+
export const dataExplorerRecordsSchema = z.array(dataExplorerRecordSchema);
|
|
44
|
+
const dataExplorerDirectionSchema = z.enum(["asc", "desc"]);
|
|
45
|
+
export const dataSourceConfigSchema = z.object({
|
|
46
|
+
strategy: z.enum(["sample", "ids", "query", "file", "recent", "random"]).optional(),
|
|
47
|
+
limit: z.number().optional(),
|
|
48
|
+
where: z.record(z.string(), dataExplorerValueSchema).optional(),
|
|
49
|
+
orderBy: z.string().optional(),
|
|
50
|
+
ids: z.array(z.union([z.number(), z.string()])).optional(),
|
|
51
|
+
filePath: z.string().optional(),
|
|
52
|
+
useCache: z.boolean().optional(),
|
|
53
|
+
cacheTtl: z.number().optional(),
|
|
54
|
+
});
|
|
55
|
+
|
|
11
56
|
/** WHERE 조건 타입 (객체 또는 Knex QueryBuilder 함수) */
|
|
12
|
-
export type WhereCondition =
|
|
57
|
+
export type WhereCondition = object | ((queryBuilder: Knex.QueryBuilder) => void);
|
|
13
58
|
|
|
14
59
|
export type DataExplorerOptions = {
|
|
15
60
|
strategy: DataExplorerStrategy;
|
|
16
61
|
limit?: number;
|
|
17
62
|
where?: WhereCondition;
|
|
18
63
|
orderBy?: string;
|
|
19
|
-
ids?: number[];
|
|
64
|
+
ids?: (number | string)[];
|
|
20
65
|
filePath?: string;
|
|
21
66
|
/** 캐싱 사용 여부 (기본값: false) */
|
|
22
67
|
useCache?: boolean;
|
|
@@ -35,10 +80,10 @@ export type ExploreWithRelationsResult = {
|
|
|
35
80
|
/** 메인 entity 데이터 */
|
|
36
81
|
main: {
|
|
37
82
|
entityId: string;
|
|
38
|
-
records:
|
|
83
|
+
records: DataExplorerRecord[];
|
|
39
84
|
};
|
|
40
85
|
/** 관련 entity 데이터 (entityId -> records) */
|
|
41
|
-
related: Map<string,
|
|
86
|
+
related: Map<string, DataExplorerRecord[]>;
|
|
42
87
|
};
|
|
43
88
|
|
|
44
89
|
// 기존 DB 데이터를 탐색하여 fixture 생성 시 참조할 수 있는 시스템
|
|
@@ -53,10 +98,7 @@ export class DataExplorer {
|
|
|
53
98
|
this.cache = cacheManager;
|
|
54
99
|
}
|
|
55
100
|
|
|
56
|
-
async explore(
|
|
57
|
-
entityName: string,
|
|
58
|
-
options: DataExplorerOptions,
|
|
59
|
-
): Promise<Record<string, unknown>[]> {
|
|
101
|
+
async explore(entityName: string, options: DataExplorerOptions): Promise<DataExplorerRecord[]> {
|
|
60
102
|
const entity = this.entityManager.get(entityName);
|
|
61
103
|
if (!entity) {
|
|
62
104
|
throw new Error(`Entity not found: ${entityName}`);
|
|
@@ -78,7 +120,7 @@ export class DataExplorer {
|
|
|
78
120
|
private async exploreInternal(
|
|
79
121
|
entity: Entity,
|
|
80
122
|
options: DataExplorerOptions,
|
|
81
|
-
): Promise<
|
|
123
|
+
): Promise<DataExplorerRecord[]> {
|
|
82
124
|
const query = this.db(entity.table);
|
|
83
125
|
|
|
84
126
|
switch (options.strategy) {
|
|
@@ -90,7 +132,7 @@ export class DataExplorer {
|
|
|
90
132
|
if (createdAtCol) {
|
|
91
133
|
query.orderBy(createdAtCol, "desc");
|
|
92
134
|
}
|
|
93
|
-
return await query.limit(options.limit || 10);
|
|
135
|
+
return dataExplorerRecordsSchema.parse(await query.limit(options.limit || 10));
|
|
94
136
|
}
|
|
95
137
|
|
|
96
138
|
case "random":
|
|
@@ -100,22 +142,30 @@ export class DataExplorer {
|
|
|
100
142
|
if (options.ids && options.ids.length > 0) {
|
|
101
143
|
query.whereIn("id", options.ids);
|
|
102
144
|
}
|
|
103
|
-
return await query;
|
|
145
|
+
return dataExplorerRecordsSchema.parse(await query);
|
|
104
146
|
|
|
105
147
|
case "query":
|
|
106
148
|
if (options.where) {
|
|
107
|
-
|
|
149
|
+
const whereCallback = z
|
|
150
|
+
.custom<(queryBuilder: Knex.QueryBuilder) => void>(isFunctionValue)
|
|
151
|
+
.safeParse(options.where);
|
|
152
|
+
if (whereCallback.success) {
|
|
153
|
+
query.where(whereCallback.data);
|
|
154
|
+
} else {
|
|
155
|
+
query.where(dataExplorerRecordSchema.parse(options.where));
|
|
156
|
+
}
|
|
108
157
|
}
|
|
109
158
|
if (options.orderBy) {
|
|
110
159
|
const [col, dir = "asc"] = options.orderBy.split(":");
|
|
160
|
+
const direction = dataExplorerDirectionSchema.parse(dir);
|
|
111
161
|
// id 컬럼은 숫자로 캐스팅하여 정렬합니다 (문자열 정렬 방지)
|
|
112
162
|
if (col === "id") {
|
|
113
|
-
query.orderByRaw(`CAST(?? AS INTEGER) ${
|
|
163
|
+
query.orderByRaw(`CAST(?? AS INTEGER) ${direction}`, [col]);
|
|
114
164
|
} else {
|
|
115
|
-
query.orderBy(col,
|
|
165
|
+
query.orderBy(col, direction);
|
|
116
166
|
}
|
|
117
167
|
}
|
|
118
|
-
return await query.limit(options.limit || 10);
|
|
168
|
+
return dataExplorerRecordsSchema.parse(await query.limit(options.limit || 10));
|
|
119
169
|
|
|
120
170
|
case "file":
|
|
121
171
|
if (!options.filePath) {
|
|
@@ -129,15 +179,12 @@ export class DataExplorer {
|
|
|
129
179
|
}
|
|
130
180
|
|
|
131
181
|
// 균등 샘플링 (PostgreSQL ROW_NUMBER 사용)
|
|
132
|
-
private async sampleData(
|
|
133
|
-
query: Knex.QueryBuilder,
|
|
134
|
-
limit: number,
|
|
135
|
-
): Promise<Record<string, unknown>[]> {
|
|
182
|
+
private async sampleData(query: Knex.QueryBuilder, limit: number): Promise<DataExplorerRecord[]> {
|
|
136
183
|
const [{ count }] = await query.clone().count("* as count");
|
|
137
184
|
const total = Number(count);
|
|
138
185
|
|
|
139
186
|
if (total <= limit) {
|
|
140
|
-
return await query.limit(limit);
|
|
187
|
+
return dataExplorerRecordsSchema.parse(await query.limit(limit));
|
|
141
188
|
}
|
|
142
189
|
|
|
143
190
|
// 균등 간격 계산
|
|
@@ -163,14 +210,14 @@ export class DataExplorer {
|
|
|
163
210
|
[tableName, interval, limit],
|
|
164
211
|
);
|
|
165
212
|
|
|
166
|
-
return result.rows;
|
|
213
|
+
return dataExplorerRecordsSchema.parse(result.rows);
|
|
167
214
|
}
|
|
168
215
|
|
|
169
216
|
private async randomSample(
|
|
170
217
|
query: Knex.QueryBuilder,
|
|
171
218
|
limit: number,
|
|
172
|
-
): Promise<
|
|
173
|
-
return await query.orderByRaw("RANDOM()").limit(limit);
|
|
219
|
+
): Promise<DataExplorerRecord[]> {
|
|
220
|
+
return dataExplorerRecordsSchema.parse(await query.orderByRaw("RANDOM()").limit(limit));
|
|
174
221
|
}
|
|
175
222
|
|
|
176
223
|
private findTimestampColumn(entity: Entity, columnName: string): string | null {
|
|
@@ -178,29 +225,29 @@ export class DataExplorer {
|
|
|
178
225
|
return prop?.name || null;
|
|
179
226
|
}
|
|
180
227
|
|
|
181
|
-
private async loadFromFile(filePath: string): Promise<
|
|
228
|
+
private async loadFromFile(filePath: string): Promise<DataExplorerRecord[]> {
|
|
182
229
|
const fs = await import("fs/promises");
|
|
183
230
|
const content = await fs.readFile(filePath, "utf-8");
|
|
184
231
|
|
|
185
232
|
if (filePath.endsWith(".json")) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
233
|
+
try {
|
|
234
|
+
const parsed = dataExplorerRecordsSchema.safeParse(JSON.parse(content));
|
|
235
|
+
if (!parsed.success) {
|
|
236
|
+
throw new Error("JSON file must contain an array of records");
|
|
237
|
+
}
|
|
238
|
+
return parsed.data;
|
|
239
|
+
} catch (error) {
|
|
240
|
+
throw new Error("JSON file must contain a valid array of records", { cause: error });
|
|
189
241
|
}
|
|
190
|
-
return parsed as Record<string, unknown>[];
|
|
191
242
|
} else if (filePath.endsWith(".csv")) {
|
|
192
243
|
const lines = content.split("\n").filter((line) => line.trim());
|
|
193
244
|
if (lines.length === 0) return [];
|
|
194
245
|
|
|
195
246
|
const headers = lines[0].split(",").map((h) => h.trim());
|
|
196
|
-
return lines.slice(1).map((line) => {
|
|
247
|
+
return lines.slice(1).map((line): DataExplorerRecord => {
|
|
197
248
|
const values = line.split(",");
|
|
198
|
-
return
|
|
199
|
-
(
|
|
200
|
-
obj[header] = values[i]?.trim();
|
|
201
|
-
return obj;
|
|
202
|
-
},
|
|
203
|
-
{} as Record<string, unknown>,
|
|
249
|
+
return Object.fromEntries(
|
|
250
|
+
headers.map((header, index) => [header, values[index]?.trim()] as const),
|
|
204
251
|
);
|
|
205
252
|
});
|
|
206
253
|
}
|
|
@@ -212,7 +259,7 @@ export class DataExplorer {
|
|
|
212
259
|
entityName: string,
|
|
213
260
|
relationProp: string,
|
|
214
261
|
options?: Partial<DataExplorerOptions>,
|
|
215
|
-
): Promise<
|
|
262
|
+
): Promise<DataExplorerRecord[]> {
|
|
216
263
|
const entity = this.entityManager.get(entityName);
|
|
217
264
|
const prop = entity.props.find((p) => p.name === relationProp);
|
|
218
265
|
|
|
@@ -222,17 +269,15 @@ export class DataExplorer {
|
|
|
222
269
|
|
|
223
270
|
const dataSource = prop.cone?.dataSource;
|
|
224
271
|
const strategy = dataSource?.strategy || options?.strategy || "sample";
|
|
225
|
-
const config =
|
|
226
|
-
|
|
227
|
-
? (dataSource.config as Record<string, unknown>)
|
|
228
|
-
: {};
|
|
229
|
-
|
|
230
|
-
return this.explore(prop.with, {
|
|
272
|
+
const config = dataSourceConfigSchema.parse(dataSource?.config ?? {});
|
|
273
|
+
const exploreOptions: DataExplorerOptions = {
|
|
231
274
|
strategy,
|
|
232
|
-
limit: options?.limit
|
|
233
|
-
...
|
|
275
|
+
limit: options?.limit ?? config.limit ?? 10,
|
|
276
|
+
...config,
|
|
234
277
|
...options,
|
|
235
|
-
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
return this.explore(prop.with, exploreOptions);
|
|
236
281
|
}
|
|
237
282
|
|
|
238
283
|
/**
|
|
@@ -242,7 +287,7 @@ export class DataExplorer {
|
|
|
242
287
|
entityName: string,
|
|
243
288
|
relationProps: string[],
|
|
244
289
|
options?: Partial<DataExplorerOptions>,
|
|
245
|
-
): Promise<Record<string,
|
|
290
|
+
): Promise<Record<string, DataExplorerRecord[]>> {
|
|
246
291
|
const results = await Promise.all(
|
|
247
292
|
relationProps.map(async (prop) => {
|
|
248
293
|
const data = await this.exploreRelation(entityName, prop, options);
|
|
@@ -314,8 +359,8 @@ export class DataExplorer {
|
|
|
314
359
|
*/
|
|
315
360
|
private async collectRelatedData(
|
|
316
361
|
entityName: string,
|
|
317
|
-
records:
|
|
318
|
-
relatedMap: Map<string,
|
|
362
|
+
records: DataExplorerRecord[],
|
|
363
|
+
relatedMap: Map<string, DataExplorerRecord[]>,
|
|
319
364
|
visited: Set<string>,
|
|
320
365
|
remainingDepth: number,
|
|
321
366
|
): Promise<void> {
|
|
@@ -324,7 +369,10 @@ export class DataExplorer {
|
|
|
324
369
|
}
|
|
325
370
|
|
|
326
371
|
const entity = this.entityManager.get(entityName);
|
|
327
|
-
const recordIds = records.
|
|
372
|
+
const recordIds = records.flatMap((record) => {
|
|
373
|
+
const parsedId = z.union([z.number(), z.string()]).safeParse(record.id);
|
|
374
|
+
return parsedId.success ? [parsedId.data] : [];
|
|
375
|
+
});
|
|
328
376
|
|
|
329
377
|
// 1. Forward references: 이 entity가 참조하는 다른 entity
|
|
330
378
|
const forwardRelationProps = entity.props.filter(
|
|
@@ -345,9 +393,10 @@ export class DataExplorer {
|
|
|
345
393
|
|
|
346
394
|
// 참조하는 ID들 수집
|
|
347
395
|
const foreignKeyName = `${prop.name}_id`;
|
|
348
|
-
const referencedIds = records
|
|
349
|
-
.
|
|
350
|
-
.
|
|
396
|
+
const referencedIds = records.flatMap((record) => {
|
|
397
|
+
const parsedId = z.union([z.number(), z.string()]).safeParse(record[foreignKeyName]);
|
|
398
|
+
return parsedId.success ? [parsedId.data] : [];
|
|
399
|
+
});
|
|
351
400
|
|
|
352
401
|
if (referencedIds.length === 0) {
|
|
353
402
|
continue;
|
|
@@ -8,12 +8,34 @@ import { Sonamu } from "../api/sonamu";
|
|
|
8
8
|
import { type SerializedTrace } from "../naite/naite";
|
|
9
9
|
import { createSSEFactory } from "../stream/sse";
|
|
10
10
|
import { type SSEConnection } from "../stream/sse";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
type ManagerStatus,
|
|
13
|
+
type RunResult,
|
|
14
|
+
type TestCaseResult,
|
|
15
|
+
type TestEventPayload,
|
|
16
|
+
} from "./dev-vitest-manager";
|
|
12
17
|
import { DevVitestManager } from "./dev-vitest-manager";
|
|
13
18
|
|
|
14
19
|
const SCHEMA_VERSION = 1;
|
|
15
20
|
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
16
21
|
|
|
22
|
+
export type DevTestRouteManager = Pick<
|
|
23
|
+
DevVitestManager,
|
|
24
|
+
| "start"
|
|
25
|
+
| "run"
|
|
26
|
+
| "getStatus"
|
|
27
|
+
| "emitEvent"
|
|
28
|
+
| "addEventListener"
|
|
29
|
+
| "removeEventListener"
|
|
30
|
+
| "shutdown"
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
export type DevTestRouteDependencies = {
|
|
34
|
+
manager?: DevTestRouteManager;
|
|
35
|
+
apiRootPath?: string;
|
|
36
|
+
sseAvailable?: boolean;
|
|
37
|
+
};
|
|
38
|
+
|
|
17
39
|
const SerializedTraceSchema = z.object({
|
|
18
40
|
key: z.string(),
|
|
19
41
|
value: z.unknown(),
|
|
@@ -48,6 +70,22 @@ const TestCaseResultSchema: z.ZodType<TestCaseResult> = z.lazy(() =>
|
|
|
48
70
|
}),
|
|
49
71
|
);
|
|
50
72
|
|
|
73
|
+
const RunResultSchema: z.ZodType<RunResult> = z.object({
|
|
74
|
+
ok: z.boolean(),
|
|
75
|
+
summary: z.object({
|
|
76
|
+
total: z.number(),
|
|
77
|
+
passed: z.number(),
|
|
78
|
+
failed: z.number(),
|
|
79
|
+
skipped: z.number(),
|
|
80
|
+
durationMs: z.number(),
|
|
81
|
+
}),
|
|
82
|
+
results: z.array(TestCaseResultSchema),
|
|
83
|
+
});
|
|
84
|
+
const RunRequestSchema = z.object({
|
|
85
|
+
files: z.array(z.string()).optional(),
|
|
86
|
+
pattern: z.string().optional(),
|
|
87
|
+
});
|
|
88
|
+
|
|
51
89
|
const TestEventSchema = z.object({
|
|
52
90
|
snapshot: z.object({
|
|
53
91
|
schemaVersion: z.number(),
|
|
@@ -56,6 +94,7 @@ const TestEventSchema = z.object({
|
|
|
56
94
|
ready: z.boolean(),
|
|
57
95
|
running: z.boolean(),
|
|
58
96
|
lastRunAt: z.string().nullable(),
|
|
97
|
+
sseAvailable: z.boolean(),
|
|
59
98
|
}),
|
|
60
99
|
}),
|
|
61
100
|
runQueued: z.object({
|
|
@@ -77,7 +116,7 @@ const TestEventSchema = z.object({
|
|
|
77
116
|
runId: z.string(),
|
|
78
117
|
startedAt: z.string(),
|
|
79
118
|
finishedAt: z.string(),
|
|
80
|
-
result:
|
|
119
|
+
result: RunResultSchema,
|
|
81
120
|
}),
|
|
82
121
|
runErrored: z.object({
|
|
83
122
|
schemaVersion: z.number(),
|
|
@@ -107,6 +146,15 @@ const TestEventSchema = z.object({
|
|
|
107
146
|
});
|
|
108
147
|
|
|
109
148
|
type TestEvents = z.infer<typeof TestEventSchema>;
|
|
149
|
+
const TestEventNameSchema = z.enum([
|
|
150
|
+
"snapshot",
|
|
151
|
+
"runQueued",
|
|
152
|
+
"runStarted",
|
|
153
|
+
"runCompleted",
|
|
154
|
+
"runErrored",
|
|
155
|
+
"runNodeProgress",
|
|
156
|
+
"heartbeat",
|
|
157
|
+
]);
|
|
110
158
|
|
|
111
159
|
function toPathPrefix(basePath: string): string {
|
|
112
160
|
return basePath.endsWith("/") ? basePath : `${basePath}/`;
|
|
@@ -127,24 +175,6 @@ function relativizeNode(node: TestCaseResult, basePath: string): TestCaseResult
|
|
|
127
175
|
};
|
|
128
176
|
}
|
|
129
177
|
|
|
130
|
-
function isRunNodeProgressData(data: unknown): data is TestEvents["runNodeProgress"] {
|
|
131
|
-
if (typeof data !== "object" || data === null) return false;
|
|
132
|
-
const d = data as Record<string, unknown>;
|
|
133
|
-
return (
|
|
134
|
-
d.schemaVersion === 1 &&
|
|
135
|
-
typeof d.runId === "string" &&
|
|
136
|
-
typeof d.startedAt === "string" &&
|
|
137
|
-
typeof d.at === "string" &&
|
|
138
|
-
(d.kind === "file" || d.kind === "suite" || d.kind === "test") &&
|
|
139
|
-
(d.phase === "ready" || d.phase === "result") &&
|
|
140
|
-
typeof d.fileId === "string" &&
|
|
141
|
-
typeof d.nodeId === "string" &&
|
|
142
|
-
(d.parentId === null || typeof d.parentId === "string") &&
|
|
143
|
-
typeof d.node === "object" &&
|
|
144
|
-
d.node !== null
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
178
|
function relativizeResult(result: RunResult, basePath: string): RunResult {
|
|
149
179
|
const prefix = toPathPrefix(basePath);
|
|
150
180
|
return {
|
|
@@ -156,14 +186,21 @@ function relativizeResult(result: RunResult, basePath: string): RunResult {
|
|
|
156
186
|
export async function registerDevTestRoutes(
|
|
157
187
|
server: FastifyInstance,
|
|
158
188
|
config: SonamuDevRunnerConfig,
|
|
189
|
+
dependencies?: DevTestRouteDependencies,
|
|
159
190
|
): Promise<void> {
|
|
160
191
|
const prefix = config.routePrefix ?? "/__test__";
|
|
161
192
|
|
|
162
|
-
const
|
|
193
|
+
const defaultManager = dependencies?.manager === undefined ? new DevVitestManager() : null;
|
|
194
|
+
const manager = dependencies?.manager ?? defaultManager;
|
|
195
|
+
if (manager === null) {
|
|
196
|
+
throw new Error("DevVitestManager dependency is unavailable");
|
|
197
|
+
}
|
|
163
198
|
await manager.start(config.vitestConfigPath);
|
|
164
|
-
|
|
199
|
+
if (defaultManager !== null) {
|
|
200
|
+
Sonamu.devVitestManager = defaultManager;
|
|
201
|
+
}
|
|
165
202
|
|
|
166
|
-
const sseAvailable = !!Sonamu.config.server.plugins?.sse;
|
|
203
|
+
const sseAvailable = dependencies?.sseAvailable ?? !!Sonamu.config.server.plugins?.sse;
|
|
167
204
|
|
|
168
205
|
if (sseAvailable) {
|
|
169
206
|
server.get(`${prefix}/events`, (request, reply): void => {
|
|
@@ -177,7 +214,8 @@ export async function registerDevTestRoutes(
|
|
|
177
214
|
sse.publish("snapshot", {
|
|
178
215
|
schemaVersion: SCHEMA_VERSION,
|
|
179
216
|
serverTime: new Date().toISOString(),
|
|
180
|
-
status
|
|
217
|
+
// UI는 HTTP status와 같은 형태를 기대하므로 SSE 스냅샷에도 sseAvailable을 포함합니다.
|
|
218
|
+
status: { ...status, sseAvailable },
|
|
181
219
|
});
|
|
182
220
|
|
|
183
221
|
const heartbeatTimer = setInterval(() => {
|
|
@@ -187,19 +225,29 @@ export async function registerDevTestRoutes(
|
|
|
187
225
|
});
|
|
188
226
|
}, HEARTBEAT_INTERVAL_MS);
|
|
189
227
|
|
|
190
|
-
const basePath = Sonamu.apiRootPath;
|
|
191
|
-
const listener = (event: string, data:
|
|
192
|
-
const
|
|
228
|
+
const basePath = dependencies?.apiRootPath ?? Sonamu.apiRootPath;
|
|
229
|
+
const listener = (event: string, data: TestEventPayload) => {
|
|
230
|
+
const parsedKey = TestEventNameSchema.safeParse(event);
|
|
231
|
+
if (!parsedKey.success) return;
|
|
232
|
+
const key = parsedKey.data;
|
|
193
233
|
if (key === "runNodeProgress") {
|
|
194
|
-
|
|
234
|
+
const progressEnvelope = TestEventSchema.partial().safeParse({ runNodeProgress: data });
|
|
235
|
+
if (!progressEnvelope.success || progressEnvelope.data.runNodeProgress === undefined) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const progress = progressEnvelope.data.runNodeProgress;
|
|
195
239
|
const relativized = {
|
|
196
|
-
...
|
|
197
|
-
node: relativizeNode(
|
|
240
|
+
...progress,
|
|
241
|
+
node: relativizeNode(progress.node, basePath),
|
|
198
242
|
};
|
|
199
243
|
sse.publish(key, relativized);
|
|
200
244
|
return;
|
|
201
245
|
}
|
|
202
|
-
|
|
246
|
+
const parsedEnvelope = TestEventSchema.partial().safeParse({ [key]: data });
|
|
247
|
+
if (!parsedEnvelope.success || parsedEnvelope.data[key] === undefined) return;
|
|
248
|
+
const parsedData = parsedEnvelope.data[key];
|
|
249
|
+
// SAFETY: key와 payload는 같은 TestEventSchema 항목으로 함께 검증되었습니다.
|
|
250
|
+
sse.publish(key, parsedData as TestEvents[typeof key]);
|
|
203
251
|
};
|
|
204
252
|
manager.addEventListener(listener);
|
|
205
253
|
|
|
@@ -216,17 +264,8 @@ export async function registerDevTestRoutes(
|
|
|
216
264
|
}
|
|
217
265
|
|
|
218
266
|
server.post(`${prefix}/run`, async (request, reply) => {
|
|
219
|
-
if (!Sonamu.devVitestManager) {
|
|
220
|
-
reply.status(503);
|
|
221
|
-
return { ok: false, error: "DevVitestManager is not initialized" };
|
|
222
|
-
}
|
|
223
|
-
|
|
224
267
|
const runId = randomUUID();
|
|
225
|
-
const
|
|
226
|
-
const runRequest = {
|
|
227
|
-
files: body?.files,
|
|
228
|
-
pattern: body?.pattern,
|
|
229
|
-
};
|
|
268
|
+
const runRequest = RunRequestSchema.parse(request.body ?? {});
|
|
230
269
|
|
|
231
270
|
manager.emitEvent("runQueued", {
|
|
232
271
|
schemaVersion: SCHEMA_VERSION,
|
|
@@ -243,8 +282,8 @@ export async function registerDevTestRoutes(
|
|
|
243
282
|
startedAt,
|
|
244
283
|
});
|
|
245
284
|
|
|
246
|
-
const rawResult: RunResult = await
|
|
247
|
-
const result = relativizeResult(rawResult, Sonamu.apiRootPath);
|
|
285
|
+
const rawResult: RunResult = await manager.run(runRequest, runId);
|
|
286
|
+
const result = relativizeResult(rawResult, dependencies?.apiRootPath ?? Sonamu.apiRootPath);
|
|
248
287
|
|
|
249
288
|
const finishedAt = new Date().toISOString();
|
|
250
289
|
manager.emitEvent("runCompleted", {
|
|
@@ -274,16 +313,14 @@ export async function registerDevTestRoutes(
|
|
|
274
313
|
});
|
|
275
314
|
|
|
276
315
|
server.get(`${prefix}/status`, async () => {
|
|
277
|
-
const status: ManagerStatus =
|
|
278
|
-
ready: false,
|
|
279
|
-
running: false,
|
|
280
|
-
lastRunAt: null,
|
|
281
|
-
};
|
|
316
|
+
const status: ManagerStatus = manager.getStatus();
|
|
282
317
|
return { ...status, sseAvailable };
|
|
283
318
|
});
|
|
284
319
|
|
|
285
320
|
server.addHook("onClose", async () => {
|
|
286
|
-
await
|
|
287
|
-
|
|
321
|
+
await manager.shutdown();
|
|
322
|
+
if (defaultManager !== null) {
|
|
323
|
+
Sonamu.devVitestManager = null;
|
|
324
|
+
}
|
|
288
325
|
});
|
|
289
326
|
}
|