sonamu 0.10.11 → 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 +133 -29
- 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 +13 -7
- 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 +61 -36
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +276 -167
- 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/migration/types.d.ts +54 -0
- package/dist/migration/types.d.ts.map +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 +146 -210
- 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 +3 -0
- package/dist/ui/migrations-api.d.ts.map +1 -0
- package/dist/ui/migrations-api.js +215 -0
- package/dist/ui-web/assets/index-D3QNH-Dv.css +1 -0
- package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
- package/dist/ui-web/index.html +2 -2
- 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 +11 -7
- 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 +155 -38
- 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 +392 -244
- package/src/migration/postgresql-schema-reader.ts +52 -47
- package/src/migration/slack-confirm.ts +17 -15
- package/src/migration/types.ts +57 -0
- 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 +726 -770
- package/src/ui/async-route.ts +4 -0
- package/src/ui/cdd-service.ts +35 -12
- package/src/ui/migrations-api.ts +381 -0
- 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-CJf8uJYf.js +0 -176
- package/dist/ui-web/assets/index-GMMIVGja.css +0 -1
package/src/entity/entity.ts
CHANGED
|
@@ -36,7 +36,10 @@ import { importMembers } from "../utils/esm-utils";
|
|
|
36
36
|
import { formatCode } from "../utils/formatter";
|
|
37
37
|
import { exists } from "../utils/fs-utils";
|
|
38
38
|
import { runtimePath } from "../utils/path-utils";
|
|
39
|
+
import { isStringValue } from "../utils/runtime-value";
|
|
39
40
|
import { assertDefined, nonNullable } from "../utils/utils";
|
|
41
|
+
|
|
42
|
+
type NestedSelect = { [key: string]: string | NestedSelect };
|
|
40
43
|
import { EntityManager } from "./entity-manager";
|
|
41
44
|
|
|
42
45
|
export class Entity {
|
|
@@ -138,6 +141,7 @@ export class Entity {
|
|
|
138
141
|
Object.entries(enums ?? {}).map(([key, enumDef]) => {
|
|
139
142
|
// cone 추출
|
|
140
143
|
if ("values" in enumDef && "cone" in enumDef && enumDef.cone) {
|
|
144
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
141
145
|
this.enumCones[key] = enumDef.cone as Cone;
|
|
142
146
|
}
|
|
143
147
|
return [key, getEnumDefValues(enumDef)];
|
|
@@ -145,7 +149,8 @@ export class Entity {
|
|
|
145
149
|
);
|
|
146
150
|
this.enums = Object.fromEntries(
|
|
147
151
|
Object.entries(this.enumLabels).map(([key, enumLabel]) => {
|
|
148
|
-
|
|
152
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
153
|
+
return [key, z.enum(Object.keys(enumLabel))];
|
|
149
154
|
}),
|
|
150
155
|
);
|
|
151
156
|
|
|
@@ -211,11 +216,8 @@ export class Entity {
|
|
|
211
216
|
* 이렇게 중첩 객체로 변환하여 select에 넘겨주면 ParseSelectObject 타입이 join된 객체의 타입을 잘 잡아줄 수 있습니다.
|
|
212
217
|
* 즉, enhancer에서 row를 받았을 때 hydrate된 객체 자체의 nullity와 그 안쪽 필드의 nullity가 fk nullable 여부에 따라 잘 추론됩니다.
|
|
213
218
|
*/
|
|
214
|
-
private buildNestedSelectObject(
|
|
215
|
-
|
|
216
|
-
// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- 반환 오브젝트의 값은 string일 수도 있고 또다른 오브젝트일 수도 있는데, 이를 재귀 타입으로 나타낼 수 없어 any로 처리합니다.
|
|
217
|
-
): Record<string, any> {
|
|
218
|
-
const result: ReturnType<typeof this.buildNestedSelectObject> = {};
|
|
219
|
+
private buildNestedSelectObject(selectItems: string[]): NestedSelect {
|
|
220
|
+
const result: NestedSelect = {};
|
|
219
221
|
|
|
220
222
|
for (const selectItem of selectItems) {
|
|
221
223
|
// "users.id" 또는 "users.id as user__id" 형태 파싱
|
|
@@ -238,7 +240,7 @@ export class Entity {
|
|
|
238
240
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
239
241
|
const part = parts[i];
|
|
240
242
|
if (part in current) {
|
|
241
|
-
if (
|
|
243
|
+
if (isStringValue(current[part])) {
|
|
242
244
|
// 입력이 ["user", "user__id"] 같은 경우!
|
|
243
245
|
// 애초에 말도 안 되지만 안전하게 예외를 던집니다.
|
|
244
246
|
throw new Error(
|
|
@@ -257,7 +259,7 @@ export class Entity {
|
|
|
257
259
|
}
|
|
258
260
|
}
|
|
259
261
|
|
|
260
|
-
return result;
|
|
262
|
+
return Object.fromEntries(Object.entries(result));
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
/**
|
|
@@ -279,8 +281,7 @@ export class Entity {
|
|
|
279
281
|
* @param withBraces true면 중괄호 포함, false면 내용만 반환
|
|
280
282
|
*/
|
|
281
283
|
private stringifyNestedSelectObject(
|
|
282
|
-
|
|
283
|
-
obj: Record<string, any>,
|
|
284
|
+
obj: NestedSelect,
|
|
284
285
|
indent: number = 0,
|
|
285
286
|
withBraces: boolean = true,
|
|
286
287
|
): string {
|
|
@@ -291,7 +292,7 @@ export class Entity {
|
|
|
291
292
|
if (entries.length === 0) return withBraces ? "{}" : "";
|
|
292
293
|
|
|
293
294
|
const lines = entries.map(([key, value]) => {
|
|
294
|
-
if (
|
|
295
|
+
if (isStringValue(value)) {
|
|
295
296
|
// 컬럼 경로 (이미 따옴표 포함)
|
|
296
297
|
return `${innerSpaces}${key}: ${value},`;
|
|
297
298
|
} else {
|
|
@@ -315,10 +316,10 @@ export class Entity {
|
|
|
315
316
|
const lines: string[] = [`[`];
|
|
316
317
|
|
|
317
318
|
// 재귀적으로 loader 생성하는 헬퍼 함수
|
|
318
|
-
const generateLoaderCode = (
|
|
319
|
+
const generateLoaderCode = (nestedLoaders: SubsetQuery["loaders"]): string[] => {
|
|
319
320
|
const loaderLines: string[] = [];
|
|
320
321
|
|
|
321
|
-
for (const loader of
|
|
322
|
+
for (const loader of nestedLoaders) {
|
|
322
323
|
const { toTable, toCol, through, fromTable } = loader.manyJoin;
|
|
323
324
|
|
|
324
325
|
// fromTable의 Entity를 가져와서 PK 타입 확인
|
|
@@ -449,15 +450,15 @@ export class Entity {
|
|
|
449
450
|
|
|
450
451
|
const result = Object.keys(subsetGroup).reduce(
|
|
451
452
|
(r, groupKey) => {
|
|
452
|
-
const
|
|
453
|
-
assert(
|
|
453
|
+
const groupedFields = subsetGroup[groupKey];
|
|
454
|
+
assert(groupedFields !== undefined, "fields is undefined");
|
|
454
455
|
|
|
455
456
|
// 현재 테이블 필드셋은 select, virtual에 추가하고 리턴
|
|
456
457
|
if (groupKey === "") {
|
|
457
|
-
const realFields =
|
|
458
|
+
const realFields = groupedFields.filter((field) => !isVirtualProp(this.propsDict[field]));
|
|
458
459
|
// virtualType: "code" (또는 undefined)인 virtual prop만 r.virtual에 추가
|
|
459
460
|
// virtualType: "query"인 경우 사용자가 appendSelect로 직접 추가하므로 제외
|
|
460
|
-
const virtualCodeFields =
|
|
461
|
+
const virtualCodeFields = groupedFields.filter((field) =>
|
|
461
462
|
isVirtualCodeProp(this.propsDict[field]),
|
|
462
463
|
);
|
|
463
464
|
|
|
@@ -483,7 +484,7 @@ export class Entity {
|
|
|
483
484
|
|
|
484
485
|
if (isOneToOneRelationProp(relation) || isBelongsToOneRelationProp(relation)) {
|
|
485
486
|
// -One Relation: JOIN 으로 처리
|
|
486
|
-
const relFields =
|
|
487
|
+
const relFields = groupedFields.map((field) => field.split(".").slice(1).join("."));
|
|
487
488
|
|
|
488
489
|
// -One Relation에서 id 필드만 참조하는 경우 릴레이션 넘기지 않고 리턴
|
|
489
490
|
if (relFields.length === 1 && relFields[0] === "id") {
|
|
@@ -585,7 +586,7 @@ export class Entity {
|
|
|
585
586
|
r.joins = r.joins.concat(relSubsetQuery.joins);
|
|
586
587
|
} else if (isHasManyRelationProp(relation) || isManyToManyRelationProp(relation)) {
|
|
587
588
|
// -Many Relation: Loader 로 처리
|
|
588
|
-
const relFields =
|
|
589
|
+
const relFields = groupedFields.map((field) => field.split(".").slice(1).join("."));
|
|
589
590
|
const relSubsetQuery = relEntity.resolveSubsetQuery("", relFields);
|
|
590
591
|
|
|
591
592
|
let manyJoin: SubsetQuery["loaders"][number]["manyJoin"];
|
|
@@ -627,6 +628,7 @@ export class Entity {
|
|
|
627
628
|
|
|
628
629
|
return r;
|
|
629
630
|
},
|
|
631
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
630
632
|
{
|
|
631
633
|
select: [],
|
|
632
634
|
virtual: [],
|
|
@@ -655,17 +657,18 @@ export class Entity {
|
|
|
655
657
|
|
|
656
658
|
return result;
|
|
657
659
|
},
|
|
660
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
658
661
|
{} as {
|
|
659
662
|
[k: string]: string[];
|
|
660
663
|
},
|
|
661
664
|
);
|
|
662
665
|
|
|
663
666
|
return Object.keys(groups).flatMap<EntityPropNode, EntityPropNode[]>((key) => {
|
|
664
|
-
const
|
|
667
|
+
const groupedFieldExprs = groups[key];
|
|
665
668
|
|
|
666
669
|
// 일반 prop 처리
|
|
667
670
|
if (key === "") {
|
|
668
|
-
return
|
|
671
|
+
return groupedFieldExprs.map((propName) => {
|
|
669
672
|
const prop = entity.props.find((p) => p.name === propName);
|
|
670
673
|
if (prop === undefined) {
|
|
671
674
|
throw new Error(
|
|
@@ -682,13 +685,16 @@ export class Entity {
|
|
|
682
685
|
// relation prop 처리
|
|
683
686
|
const prop = entity.propsDict[key];
|
|
684
687
|
if (!isRelationProp(prop)) {
|
|
685
|
-
throw new Error(`잘못된 FieldExpr ${key}.${
|
|
688
|
+
throw new Error(`잘못된 FieldExpr ${key}.${groupedFieldExprs[0]}`);
|
|
686
689
|
}
|
|
687
690
|
const relEntity = EntityManager.get(prop.with);
|
|
688
691
|
|
|
689
692
|
// relation -One 에 id 필드 하나인 경우
|
|
690
693
|
if (isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop)) {
|
|
691
|
-
if (
|
|
694
|
+
if (
|
|
695
|
+
groupedFieldExprs.length === 1 &&
|
|
696
|
+
(groupedFieldExprs[0] === "id" || groupedFieldExprs[0] === "id?")
|
|
697
|
+
) {
|
|
692
698
|
// id 하나만 있는지 체크해서, 하나만 있으면 상위 prop으로 id를 리턴
|
|
693
699
|
const idProp = relEntity.propsDict.id;
|
|
694
700
|
return {
|
|
@@ -705,7 +711,7 @@ export class Entity {
|
|
|
705
711
|
// -One 그외의 경우 object로 리턴
|
|
706
712
|
// -Many의 경우 array로 리턴
|
|
707
713
|
// Recursive 로 뎁스 처리
|
|
708
|
-
const children = this.fieldExprsToPropNodes(
|
|
714
|
+
const children = this.fieldExprsToPropNodes(groupedFieldExprs, relEntity);
|
|
709
715
|
const nodeType =
|
|
710
716
|
isBelongsToOneRelationProp(prop) || isOneToOneRelationProp(prop)
|
|
711
717
|
? ("object" as const)
|
|
@@ -806,6 +812,7 @@ export class Entity {
|
|
|
806
812
|
if (isRelationProp(prop)) {
|
|
807
813
|
// FK를 생성하는 relation만 포함
|
|
808
814
|
if (this.hasForeignKey(prop)) {
|
|
815
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
809
816
|
return {
|
|
810
817
|
name: `${prop.name}_id`,
|
|
811
818
|
type: "integer",
|
|
@@ -852,6 +859,7 @@ export class Entity {
|
|
|
852
859
|
|
|
853
860
|
if (await exists(typesFilePath)) {
|
|
854
861
|
const importedMembers = await importMembers<z.ZodTypeAny>(typesFilePath);
|
|
862
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
855
863
|
this.types = Object.fromEntries(
|
|
856
864
|
importedMembers.map(({ name, value }) => {
|
|
857
865
|
EntityManager.setModulePath(name, typesModulePath);
|
|
@@ -975,6 +983,7 @@ export class Entity {
|
|
|
975
983
|
for (const [propName, cone] of Object.entries(result.propCones)) {
|
|
976
984
|
const prop = this.props.find((p) => p.name === propName);
|
|
977
985
|
if (prop) {
|
|
986
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
978
987
|
(prop as { cone?: Cone }).cone = cone;
|
|
979
988
|
}
|
|
980
989
|
}
|
|
@@ -996,6 +1005,10 @@ export class Entity {
|
|
|
996
1005
|
preserveExisting?: boolean;
|
|
997
1006
|
onlyEmpty?: boolean;
|
|
998
1007
|
locale?: "ko" | "en" | "ja";
|
|
1008
|
+
/** 테스트나 대체 LLM 공급자를 위한 텍스트 생성 구현 */
|
|
1009
|
+
generateText?: import("../cone/cone-generator").ConeTextGenerator;
|
|
1010
|
+
/** false이면 생성 결과를 메모리에만 적용하고 entity 파일은 저장하지 않습니다. */
|
|
1011
|
+
persist?: boolean;
|
|
999
1012
|
}): Promise<import("../cone/cone-generator").ConeGenerationResult> {
|
|
1000
1013
|
const { generateCones } = await import("../cone/cone-generator");
|
|
1001
1014
|
const context: import("../cone/cone-generator").ConeGenerationContext = {
|
|
@@ -1005,9 +1018,11 @@ export class Entity {
|
|
|
1005
1018
|
onlyEmpty: options?.onlyEmpty ?? false,
|
|
1006
1019
|
};
|
|
1007
1020
|
|
|
1008
|
-
const result = await generateCones(context);
|
|
1021
|
+
const result = await generateCones(context, { generateText: options?.generateText });
|
|
1009
1022
|
this.applyCones(result);
|
|
1010
|
-
|
|
1023
|
+
if (options?.persist !== false) {
|
|
1024
|
+
await this.save();
|
|
1025
|
+
}
|
|
1011
1026
|
return result;
|
|
1012
1027
|
}
|
|
1013
1028
|
|
|
@@ -1016,28 +1031,28 @@ export class Entity {
|
|
|
1016
1031
|
*
|
|
1017
1032
|
* @returns 키가 "entity:id", "prop:name", "enum:enumId", "subset:key" 형식인 cone 맵
|
|
1018
1033
|
*/
|
|
1019
|
-
|
|
1020
|
-
const
|
|
1034
|
+
collectExistingCones(): Record<string, Cone> {
|
|
1035
|
+
const coneEntries: [string, Cone][] = [];
|
|
1021
1036
|
|
|
1022
1037
|
if (this.cone) {
|
|
1023
|
-
|
|
1038
|
+
coneEntries.push([`entity:${this.id}`, this.cone]);
|
|
1024
1039
|
}
|
|
1025
1040
|
|
|
1026
1041
|
for (const prop of this.props) {
|
|
1027
1042
|
if (prop.cone) {
|
|
1028
|
-
|
|
1043
|
+
coneEntries.push([`prop:${prop.name}`, prop.cone]);
|
|
1029
1044
|
}
|
|
1030
1045
|
}
|
|
1031
1046
|
|
|
1032
1047
|
for (const [enumId, cone] of Object.entries(this.enumCones)) {
|
|
1033
|
-
|
|
1048
|
+
coneEntries.push([`enum:${enumId}`, cone]);
|
|
1034
1049
|
}
|
|
1035
1050
|
|
|
1036
1051
|
for (const [subsetKey, cone] of Object.entries(this.subsetCones)) {
|
|
1037
|
-
|
|
1052
|
+
coneEntries.push([`subset:${subsetKey}`, cone]);
|
|
1038
1053
|
}
|
|
1039
1054
|
|
|
1040
|
-
return
|
|
1055
|
+
return Object.fromEntries(coneEntries);
|
|
1041
1056
|
}
|
|
1042
1057
|
|
|
1043
1058
|
/**
|
|
@@ -1045,7 +1060,7 @@ export class Entity {
|
|
|
1045
1060
|
*
|
|
1046
1061
|
* @param result - LLM으로 생성된 cone 결과
|
|
1047
1062
|
*/
|
|
1048
|
-
|
|
1063
|
+
applyCones(result: import("../cone/cone-generator").ConeGenerationResult): void {
|
|
1049
1064
|
if (result.entityCone) {
|
|
1050
1065
|
this.cone = result.entityCone;
|
|
1051
1066
|
}
|
|
@@ -1053,6 +1068,7 @@ export class Entity {
|
|
|
1053
1068
|
for (const [propName, cone] of Object.entries(result.propCones)) {
|
|
1054
1069
|
const prop = this.props.find((p) => p.name === propName);
|
|
1055
1070
|
if (prop) {
|
|
1071
|
+
// SAFETY: 스키마 검증과 메타데이터 계약이 이 타입을 보장합니다.
|
|
1056
1072
|
(prop as { cone?: Cone }).cone = cone;
|
|
1057
1073
|
}
|
|
1058
1074
|
}
|
package/src/env.ts
CHANGED
|
@@ -6,11 +6,15 @@ import dotenv from "dotenv";
|
|
|
6
6
|
export const SONAMU_ENVIRONMENTS = ["test", "development", "staging", "production"] as const;
|
|
7
7
|
|
|
8
8
|
export type SonamuEnvironment = (typeof SONAMU_ENVIRONMENTS)[number];
|
|
9
|
-
export
|
|
9
|
+
export interface EnvironmentSnapshot {
|
|
10
|
+
[key: string]: string;
|
|
11
|
+
}
|
|
10
12
|
export type EnvironmentSnapshots = Record<SonamuEnvironment, EnvironmentSnapshot>;
|
|
11
13
|
|
|
12
14
|
export function isSonamuEnvironment(value: string | undefined): value is SonamuEnvironment {
|
|
13
|
-
return SONAMU_ENVIRONMENTS.includes(
|
|
15
|
+
return SONAMU_ENVIRONMENTS.includes(
|
|
16
|
+
/* SAFETY: 호출 경계의 선행 검증과 소유 타입 계약이 이 값의 타입을 보장한다. */ value as SonamuEnvironment,
|
|
17
|
+
);
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export function getSonamuEnvironment(env: NodeJS.ProcessEnv = process.env): SonamuEnvironment {
|
|
@@ -87,7 +91,7 @@ export function readAllEnvironmentSnapshots(
|
|
|
87
91
|
rootPath: string,
|
|
88
92
|
baseEnv: NodeJS.ProcessEnv = {},
|
|
89
93
|
): EnvironmentSnapshots {
|
|
90
|
-
return Object.fromEntries(
|
|
94
|
+
return /* SAFETY: 호출 경계의 선행 검증과 소유 타입 계약이 이 값의 타입을 보장한다. */ Object.fromEntries(
|
|
91
95
|
SONAMU_ENVIRONMENTS.map((environment) => [
|
|
92
96
|
environment,
|
|
93
97
|
readEnvironmentSnapshot(rootPath, environment, baseEnv),
|
|
@@ -1,14 +1,29 @@
|
|
|
1
1
|
import { type FastifyInstance } from "fastify";
|
|
2
2
|
import type z from "zod";
|
|
3
3
|
|
|
4
|
+
import { isObjectValue, isStringValue } from "../utils/runtime-value";
|
|
4
5
|
import { isSoException } from "./so-exceptions";
|
|
5
6
|
|
|
7
|
+
function isZodIssuePayload<Value>(payload: Value): payload is Value & z.core.$ZodIssue[] {
|
|
8
|
+
return (
|
|
9
|
+
Array.isArray(payload) &&
|
|
10
|
+
payload.every(
|
|
11
|
+
(issue) =>
|
|
12
|
+
isObjectValue(issue) &&
|
|
13
|
+
"message" in issue &&
|
|
14
|
+
isStringValue(issue.message) &&
|
|
15
|
+
"path" in issue &&
|
|
16
|
+
Array.isArray(issue.path),
|
|
17
|
+
)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
6
21
|
export function setupErrorHandler(server: FastifyInstance) {
|
|
7
22
|
server.setErrorHandler((error, request, reply) => {
|
|
8
23
|
error.statusCode ??= 400;
|
|
9
24
|
|
|
10
|
-
if (isSoException(error) &&
|
|
11
|
-
const issues = error.payload
|
|
25
|
+
if (isSoException(error) && isZodIssuePayload(error.payload)) {
|
|
26
|
+
const issues = error.payload;
|
|
12
27
|
const [issue] = issues;
|
|
13
28
|
const message = `${issue.message} (${issue.path.join("/")})`;
|
|
14
29
|
|
|
@@ -1,24 +1,30 @@
|
|
|
1
|
+
import type z from "zod";
|
|
2
|
+
|
|
1
3
|
import { type LocalizedString } from "../dict/types";
|
|
4
|
+
import { type JsonValue } from "../types/types";
|
|
5
|
+
|
|
6
|
+
type ExceptionPayload = JsonValue | z.core.$ZodIssue[];
|
|
7
|
+
import { isObjectValue } from "../utils/runtime-value";
|
|
2
8
|
|
|
3
|
-
export abstract class SoException extends Error {
|
|
9
|
+
export abstract class SoException<Payload = ExceptionPayload> extends Error {
|
|
4
10
|
constructor(
|
|
5
11
|
public readonly statusCode: number,
|
|
6
12
|
public message: LocalizedString,
|
|
7
|
-
public payload?:
|
|
13
|
+
public payload?: Payload,
|
|
8
14
|
) {
|
|
9
15
|
super(String(message));
|
|
10
16
|
}
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
export function isSoException(err:
|
|
14
|
-
return (err
|
|
19
|
+
export function isSoException<Value>(err: Value): err is Value & SoException {
|
|
20
|
+
return isObjectValue(err) && "statusCode" in err;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
/*
|
|
18
24
|
잘못된 매개변수 등 요청사항에 문제가 있는 경우
|
|
19
25
|
*/
|
|
20
|
-
export class BadRequestException extends SoException {
|
|
21
|
-
constructor(message: LocalizedString, payload?:
|
|
26
|
+
export class BadRequestException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
27
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
22
28
|
super(400, message, payload);
|
|
23
29
|
}
|
|
24
30
|
}
|
|
@@ -26,8 +32,8 @@ export class BadRequestException extends SoException {
|
|
|
26
32
|
/*
|
|
27
33
|
로그인이 반드시 필요한 케이스에 로그아웃 상태인 경우 / 접근 권한이 없는 요청시
|
|
28
34
|
*/
|
|
29
|
-
export class UnauthorizedException extends SoException {
|
|
30
|
-
constructor(message: LocalizedString, payload?:
|
|
35
|
+
export class UnauthorizedException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
36
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
31
37
|
super(401, message, payload);
|
|
32
38
|
}
|
|
33
39
|
}
|
|
@@ -35,8 +41,8 @@ export class UnauthorizedException extends SoException {
|
|
|
35
41
|
/*
|
|
36
42
|
존재하지 않는 레코드에 접근시
|
|
37
43
|
*/
|
|
38
|
-
export class NotFoundException extends SoException {
|
|
39
|
-
constructor(message: LocalizedString, payload?:
|
|
44
|
+
export class NotFoundException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
45
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
40
46
|
super(404, message, payload);
|
|
41
47
|
}
|
|
42
48
|
}
|
|
@@ -44,8 +50,8 @@ export class NotFoundException extends SoException {
|
|
|
44
50
|
/*
|
|
45
51
|
현재 상태에서 처리가 불가능한 케이스
|
|
46
52
|
*/
|
|
47
|
-
export class ServiceUnavailableException extends SoException {
|
|
48
|
-
constructor(message: LocalizedString, payload?:
|
|
53
|
+
export class ServiceUnavailableException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
54
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
49
55
|
super(503, message, payload);
|
|
50
56
|
}
|
|
51
57
|
}
|
|
@@ -53,8 +59,8 @@ export class ServiceUnavailableException extends SoException {
|
|
|
53
59
|
/*
|
|
54
60
|
내부 처리 로직 (외부 API 콜 포함) 오류 발생시
|
|
55
61
|
*/
|
|
56
|
-
export class InternalServerErrorException extends SoException {
|
|
57
|
-
constructor(message: LocalizedString, payload?:
|
|
62
|
+
export class InternalServerErrorException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
63
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
58
64
|
super(500, message, payload);
|
|
59
65
|
}
|
|
60
66
|
}
|
|
@@ -62,8 +68,8 @@ export class InternalServerErrorException extends SoException {
|
|
|
62
68
|
/*
|
|
63
69
|
이미 처리함
|
|
64
70
|
*/
|
|
65
|
-
export class AlreadyProcessedException extends SoException {
|
|
66
|
-
constructor(message: LocalizedString, payload?:
|
|
71
|
+
export class AlreadyProcessedException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
72
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
67
73
|
super(541, message, payload);
|
|
68
74
|
}
|
|
69
75
|
}
|
|
@@ -71,8 +77,8 @@ export class AlreadyProcessedException extends SoException {
|
|
|
71
77
|
/*
|
|
72
78
|
중복 허용하지 않는 케이스에 중복 요청
|
|
73
79
|
*/
|
|
74
|
-
export class DuplicateRowException extends SoException {
|
|
75
|
-
constructor(message: LocalizedString, payload?:
|
|
80
|
+
export class DuplicateRowException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
81
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
76
82
|
super(542, message, payload);
|
|
77
83
|
}
|
|
78
84
|
}
|
|
@@ -80,8 +86,8 @@ export class DuplicateRowException extends SoException {
|
|
|
80
86
|
/*
|
|
81
87
|
뭔가를 하려고 했으나 대상이 없음
|
|
82
88
|
*/
|
|
83
|
-
export class TargetNotFoundException extends SoException {
|
|
84
|
-
constructor(message: LocalizedString, payload?:
|
|
89
|
+
export class TargetNotFoundException<Payload = ExceptionPayload> extends SoException<Payload> {
|
|
90
|
+
constructor(message: LocalizedString, payload?: Payload) {
|
|
85
91
|
super(520, message, payload);
|
|
86
92
|
}
|
|
87
93
|
}
|
package/src/filter/utils.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { type Entity } from "../entity/entity";
|
|
2
2
|
import { isEnumProp } from "../types/types";
|
|
3
|
+
import { isObjectValue, isStringValue } from "../utils/runtime-value";
|
|
3
4
|
import { operatorsByPropType } from "./types";
|
|
4
5
|
import { type FilterOperator, type FilterQuery } from "./types";
|
|
5
6
|
|
|
7
|
+
type DynamicFilterValue = string | number | boolean | Date | null | DynamicFilterValue[];
|
|
8
|
+
type DynamicFilterEntity = { [field: string]: DynamicFilterValue };
|
|
9
|
+
type ConvertedFilterValue<Value> = Value | number | boolean | null | ConvertedFilterValue<Value>[];
|
|
10
|
+
|
|
6
11
|
// ============================================================
|
|
7
12
|
// Query Normalization
|
|
8
13
|
// URL 쿼리 스트링으로 전달된 문자열을 적절한 타입으로 변환
|
|
@@ -24,10 +29,10 @@ import { type FilterOperator, type FilterQuery } from "./types";
|
|
|
24
29
|
* @param rawFilter Fastify가 파싱한 원본 sonamuFilter 객체
|
|
25
30
|
* @returns 타입이 변환된 FilterQuery 객체
|
|
26
31
|
*/
|
|
27
|
-
export function normalizeFilterQuery<TEntity =
|
|
28
|
-
rawFilter:
|
|
32
|
+
export function normalizeFilterQuery<TEntity = DynamicFilterEntity, Value = never>(
|
|
33
|
+
rawFilter: Value,
|
|
29
34
|
): FilterQuery<TEntity> {
|
|
30
|
-
if (!rawFilter ||
|
|
35
|
+
if (!rawFilter || !isObjectValue(rawFilter)) {
|
|
31
36
|
return {};
|
|
32
37
|
}
|
|
33
38
|
|
|
@@ -37,7 +42,8 @@ export function normalizeFilterQuery<TEntity = Record<string, unknown>>(
|
|
|
37
42
|
if (condition === undefined || condition === null) continue;
|
|
38
43
|
|
|
39
44
|
// 직접 값 (eq와 동일)
|
|
40
|
-
if (
|
|
45
|
+
if (!isObjectValue(condition) || Array.isArray(condition)) {
|
|
46
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
41
47
|
normalized[field as keyof TEntity] = convertType(
|
|
42
48
|
condition,
|
|
43
49
|
) as FilterQuery<TEntity>[keyof TEntity];
|
|
@@ -45,10 +51,11 @@ export function normalizeFilterQuery<TEntity = Record<string, unknown>>(
|
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
// 연산자 객체
|
|
48
|
-
const operators
|
|
54
|
+
const operators = {};
|
|
49
55
|
for (const [operator, value] of Object.entries(condition)) {
|
|
50
|
-
operators[operator]
|
|
56
|
+
Object.assign(operators, { [operator]: convertType(value) });
|
|
51
57
|
}
|
|
58
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
52
59
|
normalized[field as keyof TEntity] = operators as FilterQuery<TEntity>[keyof TEntity];
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -65,14 +72,14 @@ export function normalizeFilterQuery<TEntity = Record<string, unknown>>(
|
|
|
65
72
|
* convertType("hello") → "hello"
|
|
66
73
|
* convertType(["1", "2", "3"]) → [1, 2, 3]
|
|
67
74
|
*/
|
|
68
|
-
function convertType(value:
|
|
75
|
+
function convertType<Value>(value: Value): ConvertedFilterValue<Value> {
|
|
69
76
|
// 배열
|
|
70
77
|
if (Array.isArray(value)) {
|
|
71
78
|
return value.map(convertType);
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
// 이미 변환된 타입
|
|
75
|
-
if (
|
|
82
|
+
if (!isStringValue(value)) {
|
|
76
83
|
return value;
|
|
77
84
|
}
|
|
78
85
|
|
|
@@ -109,7 +116,7 @@ function convertType(value: unknown): unknown {
|
|
|
109
116
|
* @example
|
|
110
117
|
* validateSonamuFilters({ status: "active", id: { gte: 1 } }, ProjectEntity);
|
|
111
118
|
*/
|
|
112
|
-
export function validateSonamuFilters<TEntity =
|
|
119
|
+
export function validateSonamuFilters<TEntity = DynamicFilterEntity>(
|
|
113
120
|
filters: FilterQuery<TEntity> | undefined,
|
|
114
121
|
entity: Entity,
|
|
115
122
|
): void {
|
|
@@ -131,12 +138,14 @@ export function validateSonamuFilters<TEntity = Record<string, unknown>>(
|
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
// 해당 prop 타입에 허용되는 연산자 목록
|
|
141
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
134
142
|
const allowedOperators = (operatorsByPropType[
|
|
143
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
135
144
|
prop.type as keyof typeof operatorsByPropType
|
|
136
145
|
] ?? ["eq"]) as readonly FilterOperator[];
|
|
137
146
|
|
|
138
147
|
// 직접 값인 경우 (eq와 동일)
|
|
139
|
-
if (
|
|
148
|
+
if (!isObjectValue(condition) || Array.isArray(condition)) {
|
|
140
149
|
// enum 타입이면 값 검증
|
|
141
150
|
if (isEnumProp(prop)) {
|
|
142
151
|
const enumValues = getEnumValues(entity, prop.id);
|
|
@@ -149,6 +158,7 @@ export function validateSonamuFilters<TEntity = Record<string, unknown>>(
|
|
|
149
158
|
|
|
150
159
|
// 2. 연산자 객체인 경우
|
|
151
160
|
for (const [operator, value] of Object.entries(condition)) {
|
|
161
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
152
162
|
const op = operator as FilterOperator;
|
|
153
163
|
|
|
154
164
|
// 연산자가 해당 타입에서 지원되는지 검증
|
|
@@ -195,7 +205,7 @@ export function validateSonamuFilters<TEntity = Record<string, unknown>>(
|
|
|
195
205
|
/**
|
|
196
206
|
* Enum 값 검증 helper
|
|
197
207
|
*/
|
|
198
|
-
function validateEnumValue(field: string, value:
|
|
208
|
+
function validateEnumValue<Value>(field: string, value: Value, enumValues: string[]): void {
|
|
199
209
|
if (value === null || value === undefined) {
|
|
200
210
|
return;
|
|
201
211
|
}
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,9 @@ export * from "./api/base-frame";
|
|
|
2
2
|
export * from "./api/config";
|
|
3
3
|
export type * from "./api/context";
|
|
4
4
|
export * from "./api/decorators";
|
|
5
|
+
export { fastifyCaster } from "./api/caster";
|
|
6
|
+
export { getZodObjectFromApi } from "./api/code-converters";
|
|
7
|
+
export * from "./api/http-validator";
|
|
5
8
|
export * from "./api/sonamu";
|
|
6
9
|
export * from "./auth";
|
|
7
10
|
export { cache } from "./cache/decorator";
|