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/ui/cdd-service.ts
CHANGED
|
@@ -4,6 +4,7 @@ import os from "os";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
|
|
6
6
|
import { Sonamu } from "../api/sonamu";
|
|
7
|
+
import { isStringValue } from "../utils/runtime-value";
|
|
7
8
|
import {
|
|
8
9
|
type CddAcEntry,
|
|
9
10
|
type CddAcFile,
|
|
@@ -17,6 +18,22 @@ import {
|
|
|
17
18
|
type CddTreeNode,
|
|
18
19
|
} from "./cdd-types";
|
|
19
20
|
|
|
21
|
+
interface CddTreeResult {
|
|
22
|
+
exists: boolean;
|
|
23
|
+
tree: CddTreeNode[];
|
|
24
|
+
}
|
|
25
|
+
interface EditorCliConfig {
|
|
26
|
+
cli: string;
|
|
27
|
+
waitFlag: string;
|
|
28
|
+
}
|
|
29
|
+
interface EditorCliResolution {
|
|
30
|
+
bin: string;
|
|
31
|
+
args: string[];
|
|
32
|
+
}
|
|
33
|
+
interface CddRulesResult {
|
|
34
|
+
rules: CddRuleSummary[];
|
|
35
|
+
}
|
|
36
|
+
|
|
20
37
|
export type {
|
|
21
38
|
CddAcEntry,
|
|
22
39
|
CddAcFile,
|
|
@@ -93,7 +110,7 @@ function scanDirectory(dirPath: string, relativeTo: string): CddTreeNode[] {
|
|
|
93
110
|
}
|
|
94
111
|
|
|
95
112
|
/** contract/ 디렉터리의 트리 구조를 반환 */
|
|
96
|
-
export function getCddTree():
|
|
113
|
+
export function getCddTree(): CddTreeResult {
|
|
97
114
|
const contractDir = getContractDir();
|
|
98
115
|
if (!fs.existsSync(contractDir)) {
|
|
99
116
|
return { exists: false, tree: [] };
|
|
@@ -142,17 +159,17 @@ export async function editContent(
|
|
|
142
159
|
}
|
|
143
160
|
|
|
144
161
|
/** 에디터별 앱 번들 내 CLI 경로 + --wait 플래그 매핑 */
|
|
145
|
-
const EDITOR_CLI_MAP
|
|
162
|
+
const EDITOR_CLI_MAP = {
|
|
146
163
|
"Visual Studio Code": { cli: "Contents/Resources/app/bin/code", waitFlag: "--wait" },
|
|
147
164
|
Zed: { cli: "Contents/MacOS/cli", waitFlag: "--wait" },
|
|
148
165
|
Cursor: { cli: "Contents/Resources/app/bin/cursor", waitFlag: "--wait" },
|
|
149
|
-
}
|
|
166
|
+
} satisfies Record<string, EditorCliConfig>;
|
|
150
167
|
|
|
151
168
|
/** 앱 번들 CLI 경로를 resolve. wait=false이면 --wait 플래그를 생략 */
|
|
152
|
-
function resolveEditorCli(options?: { wait?: boolean }):
|
|
169
|
+
function resolveEditorCli(options?: { wait?: boolean }): EditorCliResolution {
|
|
153
170
|
const wait = options?.wait ?? true;
|
|
154
171
|
const appName = Sonamu.config.externalEditor ?? "Visual Studio Code";
|
|
155
|
-
const mapping = EDITOR_CLI_MAP[appName];
|
|
172
|
+
const mapping = Object.entries(EDITOR_CLI_MAP).find(([name]) => name === appName)?.[1];
|
|
156
173
|
if (!mapping) {
|
|
157
174
|
throw new Error(
|
|
158
175
|
`지원되지 않는 에디터입니다: ${appName} (지원: ${Object.keys(EDITOR_CLI_MAP).join(", ")})`,
|
|
@@ -218,7 +235,7 @@ export function openSourceFile(filePath: string): void {
|
|
|
218
235
|
* ======================================================================== */
|
|
219
236
|
|
|
220
237
|
/** contract/rules/ 디렉터리 내 .rules.json 파일 목록 반환 */
|
|
221
|
-
export function listRules():
|
|
238
|
+
export function listRules(): CddRulesResult {
|
|
222
239
|
const contractDir = getContractDir();
|
|
223
240
|
const rulesDir = path.join(contractDir, "rules");
|
|
224
241
|
if (!fs.existsSync(rulesDir)) return { rules: [] };
|
|
@@ -235,11 +252,13 @@ export function listRules(): { rules: CddRuleSummary[] } {
|
|
|
235
252
|
|
|
236
253
|
try {
|
|
237
254
|
const raw = fs.readFileSync(absPath, "utf-8");
|
|
238
|
-
const doc =
|
|
255
|
+
const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
|
|
256
|
+
raw,
|
|
257
|
+
) as { description?: string; rules?: unknown[] };
|
|
239
258
|
rules.push({
|
|
240
259
|
key,
|
|
241
260
|
path: relPath,
|
|
242
|
-
description:
|
|
261
|
+
description: isStringValue(doc.description) ? doc.description : "",
|
|
243
262
|
ruleCount: Array.isArray(doc.rules) ? doc.rules.length : 0,
|
|
244
263
|
});
|
|
245
264
|
} catch (err) {
|
|
@@ -266,12 +285,14 @@ export function readRule(ruleKey: string): CddRuleDetail {
|
|
|
266
285
|
}
|
|
267
286
|
|
|
268
287
|
const raw = fs.readFileSync(absPath, "utf-8");
|
|
269
|
-
const doc =
|
|
288
|
+
const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
|
|
289
|
+
raw,
|
|
290
|
+
) as { description?: string; rules?: CddRuleEntry[] };
|
|
270
291
|
|
|
271
292
|
return {
|
|
272
293
|
key: ruleKey,
|
|
273
294
|
path: `rules/${ruleKey}.rules.json`,
|
|
274
|
-
description:
|
|
295
|
+
description: isStringValue(doc.description) ? doc.description : "",
|
|
275
296
|
rules: Array.isArray(doc.rules) ? doc.rules : [],
|
|
276
297
|
};
|
|
277
298
|
}
|
|
@@ -287,7 +308,9 @@ export function addRule(req: CddAddRuleRequest): CddRuleDetail {
|
|
|
287
308
|
}
|
|
288
309
|
|
|
289
310
|
const raw = fs.readFileSync(absPath, "utf-8");
|
|
290
|
-
const doc =
|
|
311
|
+
const doc = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ JSON.parse(
|
|
312
|
+
raw,
|
|
313
|
+
) as { description?: string; rules?: CddRuleEntry[] };
|
|
291
314
|
const rules: CddRuleEntry[] = Array.isArray(doc.rules) ? doc.rules : [];
|
|
292
315
|
|
|
293
316
|
const nextId = generateNextRuleId(rules);
|
|
@@ -308,7 +331,7 @@ export function addRule(req: CddAddRuleRequest): CddRuleDetail {
|
|
|
308
331
|
return {
|
|
309
332
|
key: req.ruleKey,
|
|
310
333
|
path: `rules/${req.ruleKey}.rules.json`,
|
|
311
|
-
description:
|
|
334
|
+
description: isStringValue(doc.description) ? doc.description : "",
|
|
312
335
|
rules,
|
|
313
336
|
};
|
|
314
337
|
}
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { PassThrough } from "stream";
|
|
3
|
+
|
|
4
|
+
import { type FastifyInstance, type FastifyReply } from "fastify";
|
|
5
|
+
|
|
6
|
+
import { Sonamu } from "../api/sonamu";
|
|
7
|
+
import { type SonamuDBConfig } from "../database/db";
|
|
8
|
+
import { SD } from "../dict/sd";
|
|
9
|
+
import { BadRequestException } from "../exceptions/so-exceptions";
|
|
10
|
+
import {
|
|
11
|
+
Migrator,
|
|
12
|
+
MigrationTargetExecutionError,
|
|
13
|
+
type MigrationResult,
|
|
14
|
+
} from "../migration/migrator";
|
|
15
|
+
import { SlackConfirm, type SlackConfirmPendingResult } from "../migration/slack-confirm";
|
|
16
|
+
import {
|
|
17
|
+
type MigrationAction,
|
|
18
|
+
type MigrationConnectionStatus,
|
|
19
|
+
type MigrationProgressEvent,
|
|
20
|
+
type MigrationStreamEvent,
|
|
21
|
+
type MigrationTarget,
|
|
22
|
+
} from "../migration/types";
|
|
23
|
+
import { forwardAsyncErrors } from "./async-route";
|
|
24
|
+
|
|
25
|
+
type ApprovalReady = { type: "ready" };
|
|
26
|
+
type ApprovalResult = ApprovalReady | SlackConfirmPendingResult;
|
|
27
|
+
type ApplyBody = { targets: MigrationTarget[]; requestor?: string };
|
|
28
|
+
type LegacyApplyBody = ApplyBody & { force?: boolean; forceReason?: string };
|
|
29
|
+
|
|
30
|
+
const LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1"]);
|
|
31
|
+
|
|
32
|
+
function assertTargets(migrator: Migrator, targets: MigrationTarget[]): void {
|
|
33
|
+
const allowed = new Set(migrator.getConnections().map(({ connKey }) => connKey));
|
|
34
|
+
const invalid = targets.filter((target) => !allowed.has(target));
|
|
35
|
+
if (targets.length === 0 || invalid.length > 0) {
|
|
36
|
+
throw new BadRequestException(SD("error.badRequest"), {
|
|
37
|
+
message: `Invalid migration targets: ${invalid.length === 0 ? "(empty)" : invalid.join(", ")}`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function targetRequiresApproval(slack: SlackConfirm, target: MigrationTarget): boolean {
|
|
43
|
+
const connection = /* SAFETY: UI 도구의 Zod 입력 스키마가 이 값의 타입을 보장한다. */ Sonamu
|
|
44
|
+
.dbConfig[target]?.connection as { host?: string } | undefined;
|
|
45
|
+
const remote = !LOCAL_HOSTS.has((connection?.host ?? "localhost").toLowerCase());
|
|
46
|
+
return remote && slack.isTargetRequiresApproval(target);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function getAvailableTargetStatuses(
|
|
50
|
+
migrator: Migrator,
|
|
51
|
+
targets: MigrationTarget[],
|
|
52
|
+
): Promise<MigrationConnectionStatus[]> {
|
|
53
|
+
const statuses = await Promise.all(targets.map((target) => migrator.getConnectionStatus(target)));
|
|
54
|
+
const failed = statuses.filter(({ status, error }) => status === "error" || error !== undefined);
|
|
55
|
+
if (failed.length > 0) {
|
|
56
|
+
throw new BadRequestException(SD("error.badRequest"), {
|
|
57
|
+
message: `Migration status could not be verified: ${failed.map(({ connKey }) => connKey).join(", ")}`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return statuses;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getPendingMigrations(statuses: MigrationConnectionStatus[]) {
|
|
64
|
+
return [...new Set(statuses.flatMap(({ pending }) => pending))];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function requestApproval(
|
|
68
|
+
migrator: Migrator,
|
|
69
|
+
targets: MigrationTarget[],
|
|
70
|
+
requestor?: string,
|
|
71
|
+
): Promise<ApprovalResult> {
|
|
72
|
+
assertTargets(migrator, targets);
|
|
73
|
+
const statuses = await getAvailableTargetStatuses(migrator, targets);
|
|
74
|
+
const slack = new SlackConfirm();
|
|
75
|
+
const requiresApproval = targets.some((target) => targetRequiresApproval(slack, target));
|
|
76
|
+
if (!requiresApproval || !slack.isConfigured()) {
|
|
77
|
+
return { type: "ready" };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const pending = getPendingMigrations(statuses);
|
|
81
|
+
if (pending.length === 0) {
|
|
82
|
+
return { type: "ready" };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const existing = await slack.getExistingRequest(pending);
|
|
86
|
+
if (existing !== null) {
|
|
87
|
+
const approval = await slack.checkApproval(existing.channel, existing.ts);
|
|
88
|
+
if (approval.approved) {
|
|
89
|
+
return { type: "ready" };
|
|
90
|
+
}
|
|
91
|
+
if (approval.rejected) {
|
|
92
|
+
throw new BadRequestException(SD("sonamu.error.migrationRejected"));
|
|
93
|
+
}
|
|
94
|
+
return { type: "pending", ...existing };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const created = await slack.postApprovalRequest(pending, targets, requestor);
|
|
98
|
+
await slack.saveRequest(pending, created.channel, created.ts);
|
|
99
|
+
return { type: "pending", ...created };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function requireApprovedApply(
|
|
103
|
+
body: ApplyBody,
|
|
104
|
+
statuses: MigrationConnectionStatus[],
|
|
105
|
+
): Promise<{ channel: string; ts: string } | null> {
|
|
106
|
+
const slack = new SlackConfirm();
|
|
107
|
+
const requiresApproval = body.targets.some((target) => targetRequiresApproval(slack, target));
|
|
108
|
+
if (!requiresApproval || !slack.isConfigured()) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const pending = getPendingMigrations(statuses);
|
|
113
|
+
if (pending.length === 0) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const existing = await slack.getExistingRequest(pending);
|
|
118
|
+
if (existing === null) {
|
|
119
|
+
throw new BadRequestException(SD("error.badRequest"), {
|
|
120
|
+
message: "Slack approval has not been requested",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const approval = await slack.checkApproval(existing.channel, existing.ts);
|
|
124
|
+
if (approval.rejected) {
|
|
125
|
+
throw new BadRequestException(SD("sonamu.error.migrationRejected"));
|
|
126
|
+
}
|
|
127
|
+
if (!approval.approved) {
|
|
128
|
+
throw new BadRequestException(SD("error.badRequest"), {
|
|
129
|
+
message: "Slack approval is still pending",
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return existing;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function runLegacyApply(
|
|
136
|
+
migrator: Migrator,
|
|
137
|
+
body: LegacyApplyBody,
|
|
138
|
+
): Promise<MigrationResult | SlackConfirmPendingResult> {
|
|
139
|
+
assertTargets(migrator, body.targets);
|
|
140
|
+
const statuses = await getAvailableTargetStatuses(migrator, body.targets);
|
|
141
|
+
const slack = new SlackConfirm();
|
|
142
|
+
const requiresApproval = body.targets.some((target) => targetRequiresApproval(slack, target));
|
|
143
|
+
if (!requiresApproval || !slack.isConfigured()) {
|
|
144
|
+
return migrator.apply(body.targets);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const pending = getPendingMigrations(statuses);
|
|
148
|
+
if (pending.length === 0) {
|
|
149
|
+
return migrator.apply(body.targets);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const existing = await slack.getExistingRequest(pending);
|
|
153
|
+
if (existing === null) {
|
|
154
|
+
const created = await slack.postApprovalRequest(pending, body.targets, body.requestor);
|
|
155
|
+
await slack.saveRequest(pending, created.channel, created.ts);
|
|
156
|
+
return { type: "pending", ...created };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const approval = await slack.checkApproval(existing.channel, existing.ts);
|
|
160
|
+
if (approval.rejected) {
|
|
161
|
+
throw new BadRequestException(SD("sonamu.error.migrationRejected"));
|
|
162
|
+
}
|
|
163
|
+
if (!approval.approved && !body.force) {
|
|
164
|
+
return { type: "pending", ...existing };
|
|
165
|
+
}
|
|
166
|
+
if (!approval.approved) {
|
|
167
|
+
await slack.forceApproval(
|
|
168
|
+
existing.channel,
|
|
169
|
+
existing.ts,
|
|
170
|
+
body.forceReason ?? "사유 없음",
|
|
171
|
+
body.requestor,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const result = await migrator.apply(body.targets);
|
|
176
|
+
if (result.length > 0) {
|
|
177
|
+
await slack.logExecution(existing.channel, existing.ts, result, body.requestor);
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function sendMigrationStream(
|
|
183
|
+
reply: FastifyReply,
|
|
184
|
+
action: MigrationAction,
|
|
185
|
+
targets: MigrationTarget[],
|
|
186
|
+
run: (onProgress: (event: MigrationProgressEvent) => void) => Promise<MigrationResult>,
|
|
187
|
+
afterComplete?: (result: MigrationResult) => Promise<void>,
|
|
188
|
+
) {
|
|
189
|
+
const stream = new PassThrough();
|
|
190
|
+
let canWrite = true;
|
|
191
|
+
let current: MigrationProgressEvent | undefined;
|
|
192
|
+
const completedTargets: MigrationTarget[] = [];
|
|
193
|
+
const write = (event: MigrationStreamEvent) => {
|
|
194
|
+
if (canWrite && !stream.destroyed) {
|
|
195
|
+
stream.write(`${JSON.stringify(event)}\n`);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
stream.on("close", () => {
|
|
200
|
+
canWrite = false;
|
|
201
|
+
});
|
|
202
|
+
reply
|
|
203
|
+
.header("content-type", "application/x-ndjson; charset=utf-8")
|
|
204
|
+
.header("cache-control", "no-cache, no-transform")
|
|
205
|
+
.header("content-encoding", "identity")
|
|
206
|
+
.header("x-no-compression", "1");
|
|
207
|
+
|
|
208
|
+
void (async () => {
|
|
209
|
+
try {
|
|
210
|
+
const result = await run((event) => {
|
|
211
|
+
if (event.type === "target-complete") {
|
|
212
|
+
if (event.connKey !== "shadow") completedTargets.push(event.connKey);
|
|
213
|
+
write(event);
|
|
214
|
+
// 다음 target의 lifecycle이 시작되기 전 오류를 직전 target에 잘못 귀속하지 않습니다.
|
|
215
|
+
current = undefined;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
current = event;
|
|
219
|
+
write(event);
|
|
220
|
+
});
|
|
221
|
+
await afterComplete?.(result);
|
|
222
|
+
write({ type: "complete", result });
|
|
223
|
+
} catch (caught) {
|
|
224
|
+
const message = caught instanceof Error ? caught.message : String(caught);
|
|
225
|
+
const failedTarget =
|
|
226
|
+
caught instanceof MigrationTargetExecutionError ? caught.connKey : current?.connKey;
|
|
227
|
+
write({
|
|
228
|
+
type: "error",
|
|
229
|
+
action,
|
|
230
|
+
message,
|
|
231
|
+
connKey: failedTarget,
|
|
232
|
+
file:
|
|
233
|
+
current?.type === "file-start" || current?.type === "file-executed"
|
|
234
|
+
? current.file
|
|
235
|
+
: undefined,
|
|
236
|
+
completedTargets,
|
|
237
|
+
pendingTargets: targets.filter((target) => !completedTargets.includes(target)),
|
|
238
|
+
});
|
|
239
|
+
} finally {
|
|
240
|
+
if (!stream.destroyed) {
|
|
241
|
+
stream.end();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
|
|
246
|
+
return reply.send(stream);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export async function registerMigrationsApi(server: FastifyInstance) {
|
|
250
|
+
const migrator = new Migrator();
|
|
251
|
+
|
|
252
|
+
server.get("/api/migrations/connections", async () => ({
|
|
253
|
+
connections: migrator.getConnections(),
|
|
254
|
+
}));
|
|
255
|
+
server.get("/api/migrations/codes", async () => ({ codes: await migrator.getMigrationCodes() }));
|
|
256
|
+
server.get<{ Querystring: { codeName: string } }>("/api/migrations/code", (request) =>
|
|
257
|
+
forwardAsyncErrors(async () => {
|
|
258
|
+
const migrationCode = (await migrator.getMigrationCodes()).find(
|
|
259
|
+
({ name }) => name === request.query.codeName,
|
|
260
|
+
);
|
|
261
|
+
if (migrationCode === undefined) {
|
|
262
|
+
throw new BadRequestException(SD("error.badRequest"));
|
|
263
|
+
}
|
|
264
|
+
return { code: await readFile(migrationCode.path, "utf8") };
|
|
265
|
+
}),
|
|
266
|
+
);
|
|
267
|
+
server.get<{ Querystring: { connKey?: MigrationTarget } }>("/api/migrations/status", (request) =>
|
|
268
|
+
forwardAsyncErrors(async () => {
|
|
269
|
+
if (request.query.connKey === undefined) {
|
|
270
|
+
return { status: await migrator.getStatus() };
|
|
271
|
+
}
|
|
272
|
+
return { status: await migrator.getConnectionStatus(request.query.connKey) };
|
|
273
|
+
}),
|
|
274
|
+
);
|
|
275
|
+
server.get<{ Querystring: { compareConnKey: MigrationTarget } }>(
|
|
276
|
+
"/api/migrations/prepared-codes",
|
|
277
|
+
(request) =>
|
|
278
|
+
forwardAsyncErrors(async () => ({
|
|
279
|
+
preparedCodes: await migrator.getPreparedCodes(request.query.compareConnKey),
|
|
280
|
+
})),
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
server.post<{ Body: ApplyBody }>("/api/migrations/request-approval", (request) =>
|
|
284
|
+
forwardAsyncErrors(async () => {
|
|
285
|
+
return requestApproval(migrator, request.body.targets, request.body.requestor);
|
|
286
|
+
}),
|
|
287
|
+
);
|
|
288
|
+
server.post<{ Body: { channel: string; ts: string } }>(
|
|
289
|
+
"/api/migrations/checkApproval",
|
|
290
|
+
(request) =>
|
|
291
|
+
forwardAsyncErrors(async () => {
|
|
292
|
+
const slack = new SlackConfirm();
|
|
293
|
+
return slack.isConfigured()
|
|
294
|
+
? slack.checkApproval(request.body.channel, request.body.ts)
|
|
295
|
+
: { approved: true, rejected: false };
|
|
296
|
+
}),
|
|
297
|
+
);
|
|
298
|
+
server.post<{
|
|
299
|
+
Body: { channel: string; ts: string; reason: string; requestor?: string };
|
|
300
|
+
}>("/api/migrations/forceApproval", (request) =>
|
|
301
|
+
forwardAsyncErrors(async () => {
|
|
302
|
+
const slack = new SlackConfirm();
|
|
303
|
+
if (!slack.isConfigured()) {
|
|
304
|
+
throw new BadRequestException(SD("sonamu.error.slackConfirmNotConfigured"));
|
|
305
|
+
}
|
|
306
|
+
await slack.forceApproval(
|
|
307
|
+
request.body.channel,
|
|
308
|
+
request.body.ts,
|
|
309
|
+
request.body.reason,
|
|
310
|
+
request.body.requestor,
|
|
311
|
+
);
|
|
312
|
+
return { success: true };
|
|
313
|
+
}),
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
server.post("/api/migrations/shadow", async (_request, reply) => {
|
|
317
|
+
return sendMigrationStream(reply, "shadow", [], (onProgress) => {
|
|
318
|
+
return migrator.runShadowTest({ onProgress });
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
server.post<{ Body: ApplyBody }>("/api/migrations/apply", async (request, reply) => {
|
|
322
|
+
assertTargets(migrator, request.body.targets);
|
|
323
|
+
const statuses = await getAvailableTargetStatuses(migrator, request.body.targets);
|
|
324
|
+
const approval = await requireApprovedApply(request.body, statuses);
|
|
325
|
+
return sendMigrationStream(
|
|
326
|
+
reply,
|
|
327
|
+
"apply",
|
|
328
|
+
request.body.targets,
|
|
329
|
+
(onProgress) => migrator.apply(request.body.targets, { onProgress }),
|
|
330
|
+
approval === null
|
|
331
|
+
? undefined
|
|
332
|
+
: async (result) => {
|
|
333
|
+
await new SlackConfirm().logExecution(
|
|
334
|
+
approval.channel,
|
|
335
|
+
approval.ts,
|
|
336
|
+
result,
|
|
337
|
+
request.body.requestor,
|
|
338
|
+
);
|
|
339
|
+
},
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
server.post<{ Body: { targets: MigrationTarget[] } }>(
|
|
343
|
+
"/api/migrations/rollback",
|
|
344
|
+
async (request, reply) => {
|
|
345
|
+
assertTargets(migrator, request.body.targets);
|
|
346
|
+
await getAvailableTargetStatuses(migrator, request.body.targets);
|
|
347
|
+
return sendMigrationStream(reply, "rollback", request.body.targets, (onProgress) => {
|
|
348
|
+
return migrator.rollback(request.body.targets, { onProgress });
|
|
349
|
+
});
|
|
350
|
+
},
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
server.post<{ Body: { compareConnKey?: MigrationTarget } }>(
|
|
354
|
+
"/api/migrations/generatePreparedCodes",
|
|
355
|
+
(request) =>
|
|
356
|
+
forwardAsyncErrors(async () => migrator.generatePreparedCodes(request.body.compareConnKey)),
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
// 이전 UI 번들과 외부 스크립트가 새 서버에서도 한 릴리스 동안 동작하도록 유지합니다.
|
|
360
|
+
server.post<{
|
|
361
|
+
Body: {
|
|
362
|
+
action: "apply" | "rollback" | "shadow";
|
|
363
|
+
targets: (keyof SonamuDBConfig)[];
|
|
364
|
+
force?: boolean;
|
|
365
|
+
forceReason?: string;
|
|
366
|
+
requestor?: string;
|
|
367
|
+
};
|
|
368
|
+
}>("/api/migrations/runAction", (request) =>
|
|
369
|
+
forwardAsyncErrors(async () => {
|
|
370
|
+
if (request.body.action === "shadow") {
|
|
371
|
+
return migrator.runShadowTest();
|
|
372
|
+
}
|
|
373
|
+
if (request.body.action === "apply") {
|
|
374
|
+
return runLegacyApply(migrator, request.body);
|
|
375
|
+
}
|
|
376
|
+
assertTargets(migrator, request.body.targets);
|
|
377
|
+
await getAvailableTargetStatuses(migrator, request.body.targets);
|
|
378
|
+
return migrator.rollback(request.body.targets);
|
|
379
|
+
}),
|
|
380
|
+
);
|
|
381
|
+
}
|
package/src/utils/formatter.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { format, type FormatConfig } from "oxfmt";
|
|
|
10
10
|
import { cached } from "./async-utils";
|
|
11
11
|
import { isTest } from "./controller";
|
|
12
12
|
import { execute } from "./process-utils";
|
|
13
|
+
import { isNumberValue } from "./runtime-value";
|
|
13
14
|
|
|
14
|
-
const
|
|
15
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* 코드를 프로젝트의 oxfmt + oxlint 설정에 맞춰 포매팅한 문자열을 반환합니다.
|
|
@@ -75,9 +76,11 @@ async function loadOxfmtConfig(): Promise<FormatConfig> {
|
|
|
75
76
|
while (true) {
|
|
76
77
|
const candidate = join(dir, ".oxfmtrc.json");
|
|
77
78
|
try {
|
|
79
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
78
80
|
cachedOxfmtConfig = JSON.parse(await readFile(candidate, "utf-8")) as FormatConfig;
|
|
79
81
|
return cachedOxfmtConfig;
|
|
80
82
|
} catch (e) {
|
|
83
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
81
84
|
if ((e as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
82
85
|
!isTest() && console.error(`Failed to load ${candidate}:`, e);
|
|
83
86
|
break;
|
|
@@ -121,7 +124,8 @@ async function runOxlint(code: string): Promise<string> {
|
|
|
121
124
|
});
|
|
122
125
|
} catch (e) {
|
|
123
126
|
// lint 위반 시 exit code != 0이지만 --fix는 적용됨. exec 자체 실패만 throw.
|
|
124
|
-
|
|
127
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
128
|
+
if (!isNumberValue((e as Error & { code?: number }).code)) {
|
|
125
129
|
throw e;
|
|
126
130
|
}
|
|
127
131
|
}
|
|
@@ -138,7 +142,7 @@ async function runOxlint(code: string): Promise<string> {
|
|
|
138
142
|
|
|
139
143
|
function resolveOxlintBin(): string {
|
|
140
144
|
try {
|
|
141
|
-
return
|
|
145
|
+
return requireFromHere.resolve("oxlint/bin/oxlint");
|
|
142
146
|
} catch {
|
|
143
147
|
return "oxlint";
|
|
144
148
|
}
|
package/src/utils/fs-utils.ts
CHANGED
|
@@ -8,12 +8,12 @@ import { formatCode } from "./formatter";
|
|
|
8
8
|
/**
|
|
9
9
|
* fs/promises에는 exists가 없어요. 대신 access가 있습니다.
|
|
10
10
|
* 근데 얘는 인터페이스가 쓰기 불편해요. 그래서 감싸주었습니다.
|
|
11
|
-
* @param
|
|
11
|
+
* @param targetPath
|
|
12
12
|
* @returns
|
|
13
13
|
*/
|
|
14
|
-
export async function exists(
|
|
14
|
+
export async function exists(targetPath: PathLike): Promise<boolean> {
|
|
15
15
|
try {
|
|
16
|
-
await access(
|
|
16
|
+
await access(targetPath, constants.F_OK);
|
|
17
17
|
return true;
|
|
18
18
|
} catch {
|
|
19
19
|
return false;
|
|
@@ -21,9 +21,9 @@ export async function exists(path: PathLike): Promise<boolean> {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// 디렉토리가 아니라 파일만 존재하는지 확인합니다.
|
|
24
|
-
export async function fileExists(
|
|
24
|
+
export async function fileExists(targetPath: PathLike): Promise<boolean> {
|
|
25
25
|
try {
|
|
26
|
-
const stats = await stat(
|
|
26
|
+
const stats = await stat(targetPath);
|
|
27
27
|
return stats.isFile();
|
|
28
28
|
} catch {
|
|
29
29
|
return false;
|
package/src/utils/model.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { type SonamuQueryMode } from "../types/types";
|
|
1
|
+
import { type SonamuQueryMode, type SonamuSemanticParams } from "../types/types";
|
|
2
2
|
|
|
3
3
|
// semanticQuery가 있으면 similarity를 추가하는 조건부 타입
|
|
4
|
-
type WithSimilarity<LP, T> =
|
|
5
|
-
? T & { similarity: number }
|
|
6
|
-
: T;
|
|
4
|
+
type WithSimilarity<LP, T> = "semanticQuery" extends keyof LP ? T & { similarity: number } : T;
|
|
7
5
|
|
|
8
6
|
export type ListResult<
|
|
9
7
|
LP extends { queryMode?: SonamuQueryMode },
|
|
@@ -20,6 +18,7 @@ export function asArray<T>(param: T | T[]): T[] {
|
|
|
20
18
|
if (Array.isArray(param)) {
|
|
21
19
|
return param;
|
|
22
20
|
} else {
|
|
21
|
+
// SAFETY: 선행 분기와 함수 계약이 이 타입을 보장합니다.
|
|
23
22
|
return [param] as T[];
|
|
24
23
|
}
|
|
25
24
|
}
|
|
@@ -39,5 +38,5 @@ export interface BaseListParams {
|
|
|
39
38
|
page?: number;
|
|
40
39
|
keyword?: string;
|
|
41
40
|
queryMode?: "list" | "count" | "both";
|
|
42
|
-
semanticQuery?:
|
|
41
|
+
semanticQuery?: SonamuSemanticParams["semanticQuery"];
|
|
43
42
|
}
|